/* * Display pages of unicode character set */ #include #include #include #define SIZE 24 #define NROW 16 #define NCOL 16 #define GAP 16 typedef struct Page Page; struct Page{ Rectangle r; int first, step; }; Page whole, detail; int snarf; /* * The following table is abstracted from * The Unicode Standard * Worldwide Character Encoding * Version 1.0, Volume 1 */ char *pagename[256]={ [0x00] "Control/ASCII/Control/Latin1", [0x01] "European Latin/Extended Latin", [0x02] "Standard Phonetic/Modifier Letters", [0x03] "Generic Diacritical Marks/Greek", [0x04] "Cyrillic", [0x05] "Armenian/Hebrew", [0x06] "Arabic", [0x07] "Unassigned, Reserved for Right-To-Left Characters", [0x08] "Unassigned, Reserved for Right-To-Left Characters", [0x09] "Devanagari/Bengali", [0x0a] "Gurmukhi/Gujarati", [0x0b] "Oriya/Tamil", [0x0c] "Telugu/Kannada", [0x0d] "Malayalam", [0x0e] "Thai/Lao", [0x10] "Tibetan/Georgian", [0x20] "General Punctuation/Superscripts and Subscripts/Currency Symbols/Diacritical Marks for Symbols", [0x21] "Letterlike Symbols/Number Forms/Arrows", [0x22] "Mathematical Operators", [0x23] "Miscellaneous Technical", [0x24] "Pictures for Control Codes/Optical Character Recognition/Enclosed Alphanumerics", [0x25] "Form and Chart Components/Blocks/Geometric Shapes", [0x26] "Miscellaneous Dingbats", [0x27] "Zapf Dingbats", [0x30] "CJK Symbols and Punctuation/Hiragana/Katakana", [0x31] "Bopomofo/Hangul Elements/CJK Miscellaneous", [0x32] "Enclosed CJK Letters and Ideographs", [0x33] "CJK Squared Words/CJK Squared Abbreviations", [0x34] "Korean Hangul Syllables", [0x35] "Korean Hangul Syllables", [0x36] "Korean Hangul Syllables", [0x37] "Korean Hangul Syllables", [0x38] "Korean Hangul Syllables", [0x39] "Korean Hangul Syllables", [0x3a] "Korean Hangul Syllables", [0x3b] "Korean Hangul Syllables", [0x3c] "Korean Hangul Syllables", [0x3d] "Korean Hangul Syllables", [0x4e] "CJK Ideographs", [0x4f] "CJK Ideographs", [0x50] "CJK Ideographs", [0x51] "CJK Ideographs", [0x52] "CJK Ideographs", [0x53] "CJK Ideographs", [0x54] "CJK Ideographs", [0x55] "CJK Ideographs", [0x56] "CJK Ideographs", [0x57] "CJK Ideographs", [0x58] "CJK Ideographs", [0x59] "CJK Ideographs", [0x5a] "CJK Ideographs", [0x5b] "CJK Ideographs", [0x5c] "CJK Ideographs", [0x5d] "CJK Ideographs", [0x5e] "CJK Ideographs", [0x5f] "CJK Ideographs", [0x60] "CJK Ideographs", [0x61] "CJK Ideographs", [0x62] "CJK Ideographs", [0x63] "CJK Ideographs", [0x64] "CJK Ideographs", [0x65] "CJK Ideographs", [0x66] "CJK Ideographs", [0x67] "CJK Ideographs", [0x68] "CJK Ideographs", [0x69] "CJK Ideographs", [0x6a] "CJK Ideographs", [0x6b] "CJK Ideographs", [0x6c] "CJK Ideographs", [0x6d] "CJK Ideographs", [0x6e] "CJK Ideographs", [0x6f] "CJK Ideographs", [0x70] "CJK Ideographs", [0x71] "CJK Ideographs", [0x72] "CJK Ideographs", [0x73] "CJK Ideographs", [0x74] "CJK Ideographs", [0x75] "CJK Ideographs", [0x76] "CJK Ideographs", [0x77] "CJK Ideographs", [0x78] "CJK Ideographs", [0x79] "CJK Ideographs", [0x7a] "CJK Ideographs", [0x7b] "CJK Ideographs", [0x7c] "CJK Ideographs", [0x7d] "CJK Ideographs", [0x7e] "CJK Ideographs", [0x7f] "CJK Ideographs", [0x80] "CJK Ideographs", [0x81] "CJK Ideographs", [0x82] "CJK Ideographs", [0x83] "CJK Ideographs", [0x84] "CJK Ideographs", [0x85] "CJK Ideographs", [0x86] "CJK Ideographs", [0x87] "CJK Ideographs", [0x88] "CJK Ideographs", [0x89] "CJK Ideographs", [0x8a] "CJK Ideographs", [0x8b] "CJK Ideographs", [0x8c] "CJK Ideographs", [0x8d] "CJK Ideographs", [0x8e] "CJK Ideographs", [0x8f] "CJK Ideographs", [0x90] "CJK Ideographs", [0x91] "CJK Ideographs", [0x92] "CJK Ideographs", [0x93] "CJK Ideographs", [0x94] "CJK Ideographs", [0x95] "CJK Ideographs", [0x96] "CJK Ideographs", [0x97] "CJK Ideographs", [0x98] "CJK Ideographs", [0x99] "CJK Ideographs", [0x9a] "CJK Ideographs", [0x9b] "CJK Ideographs", [0x9c] "CJK Ideographs", [0x9d] "CJK Ideographs", [0x9e] "CJK Ideographs", [0x9f] "CJK Ideographs", [0xe8] "Private Use Area", [0xe9] "Private Use Area", [0xea] "Private Use Area", [0xeb] "Private Use Area", [0xec] "Private Use Area", [0xed] "Private Use Area", [0xee] "Private Use Area", [0xef] "Private Use Area", [0xf0] "Private Use Area", [0xf1] "Private Use Area", [0xf2] "Private Use Area", [0xf3] "Private Use Area", [0xf4] "Private Use Area", [0xf5] "Private Use Area", [0xf6] "Private Use Area", [0xf7] "Private Use Area", [0xf8] "Private Use Area", [0xf9] "Private Use Area", [0xfa] "Private Use Area", [0xfb] "Private Use Area", [0xfc] "Private Use Area", [0xfd] "Private Use Area", [0xfe] "CNS 11643 Compatibility/Small Variants/Basic Glyphs for Arabic Language", [0xff] "Halfwidth and Fullwidth Variants/Special", }; void showsnarf(void); void seepage(Page *pg){ Point p; int c; char buf[10]; bitblt(&screen, sub(pg->r.min, Pt(2, 2)), &screen, inset(pg->r, -2), Zero); for(p.x=0,c=pg->first;p.x!=NCOL;p.x++){ for(p.y=0;p.y!=NROW;p.y++,c+=pg->step){ sprint(buf, "%C", c); string(&screen, add(pg->r.min, mul(p, SIZE)), font, buf, S); } buf[0]="0123456789abcdef"[p.x]; buf[1]='\0'; string(&screen, add(pg->r.min, mul(Pt(p.x, NCOL), SIZE)), font, buf, S); string(&screen, add(pg->r.min, mul(Pt(NCOL, p.x), SIZE)), font, buf, S); } bflush(); } void ereshaped(Rectangle r){ screen.r=r; screen.clipr=inset(screen.r, 2); bitblt(&screen, screen.clipr.min, &screen, screen.clipr, Zero); whole.r.min=sub(div(add(r.min, r.max), 2), Pt((NCOL+1)*SIZE+GAP, (NROW+1)*SIZE/2)); whole.r.max=add(whole.r.min, Pt((NCOL+1)*SIZE, (NROW+1)*SIZE)); whole.first=0; whole.step=NROW*NCOL; detail.r.min=Pt(whole.r.max.x+2*GAP, whole.r.min.y); detail.r.max=add(detail.r.min, Pt((NCOL+1)*SIZE, (NROW+1)*SIZE)); /* don't set detail.first, so we see the same page as before */ detail.step=1; seepage(&whole); seepage(&detail); showsnarf(); } int hit(Point p, Page *pg){ if(!ptinrect(p, pg->r)) return -1; p=div(sub(p, pg->r.min), SIZE); if(p.y>=NROW || p.x>=NCOL) return -1; return p.x*NROW+p.y; } enum{ TRUNC, EXIT }; char *item3[]={ [TRUNC] "empty snarf", [EXIT] "exit", 0 }; Menu menu3={item3}; Cursor confirmcurs={ 0, 0, 0x0F, 0xBF, 0x0F, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, 0x00, 0x0E, 0x07, 0x1F, 0x03, 0x17, 0x73, 0x6F, 0xFB, 0xCE, 0xDB, 0x8C, 0xDB, 0xC0, 0xFB, 0x6C, 0x77, 0xFC, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x94, 0xA6, 0x63, 0x3C, 0x63, 0x18, 0x94, 0x90 }; /* * Wait for mouse down */ void mdown(Mouse *mp){ while(mp->buttons==0) *mp=emouse(); } /* * Wait for mouse up */ void mup(Mouse *mp){ while(mp->buttons!=0) *mp=emouse(); } /* * wait for confirming click on button b */ int confirm(int b, Mouse *mp){ int down; cursorswitch(&confirmcurs); mup(mp); mdown(mp); down=mp->buttons==(1<<(b-1)); mup(mp); cursorswitch(0); return down; } /* * Return the offset of the first byte of the line containing byte offs in file fd. * Fill buf with the line. */ int line(int offs, int fd, char *buf, int nbuf){ char *nl; int n, nread; nread=nbuf-1; /* save space to add a nul */ while(offs){ if(offs=0){ strcpy(line, "snarf: "); seek(snarf, 0, 0); n=read(snarf, line+7, NLINE-8); if(n<0) n=0; line[n+7]='\0'; } else strcpy(line, "no /dev/snarf"); p=string(&screen, add(screen.clipr.min, Pt(4, 6+font->height)), font, line, S); bitblt(&screen, p, &screen, Rect(p.x, p.y, screen.clipr.max.x, p.y+font->height), Zero); } void main(int argc, char *argv[]){ Mouse m; Point p; int h, n; char buf[100+NLINE]; char line[NLINE]; int unames; unames=open("/lib/unicode", OREAD); snarf=open("/dev/snarf", ORDWR); binit(0, argc>1?argv[1]:0, argv[0]); einit(Emouse|Ekeyboard); ereshaped(screen.r); for(;;){ m=emouse(); switch(m.buttons){ case 1: case 2: h=hit(m.xy, &whole); if(h>=0){ sprint(buf, "%x%xxx %s", h/NROW, h%NROW, pagename[h]?pagename[h]:""); p=string(&screen, add(screen.clipr.min, Pt(4, 4)), font, buf, S); bitblt(&screen, p, &screen, Rect(p.x,p.y, screen.clipr.max.x,p.y+font->height), Zero); detail.first=h*NROW*NCOL; seepage(&detail); break; } h=hit(m.xy, &detail); if(h<0) break; sprint(buf, "%x%x%x%x", detail.first/(NROW*NROW)/NROW, detail.first/(NROW*NROW)%NROW, h/NROW, h%NROW); if(unames>=0 && look(unames, buf, line, NLINE) && strlen(line)>5){ strcat(buf, " "); strcat(buf, line+5); } p=string(&screen, add(screen.clipr.min, Pt(4, 4)), font, buf, S); if(p.xheight), Zero); if(m.buttons!=2) break; if(snarf>=0){ /* there appears to be a bug in /dev/snarf */ seek(snarf, 0, 0); n=read(snarf, buf, NLINE); seek(snarf, 0, 0); write(snarf, buf, n); fprint(snarf, "%C", detail.first+h); } break; case 4: switch(menuhit(3, &m, &menu3)){ case TRUNC: close(snarf); snarf=create("/dev/snarf", ORDWR, 0666); break; case EXIT: if(confirm(3, &m)) exits(""); break; } } showsnarf(); mup(&m); } }