void curses_drawwindow(WINDOW *win) { int i,j,w,drawx,drawy; unsigned tmp; for (j=0; j<win->height; j++){ if (win->line[j].touched) { needupdate = true; win->line[j].touched=false; for (i=0,w=0; w<win->width; i++,w++){ drawx=((win->x+w)*fontwidth); drawy=((win->y+j)*fontheight);//-j; if (((drawx+fontwidth)<=WindowWidth) && ((drawy+fontheight)<=WindowHeight)){ const char* utf8str = win->line[j].chars+i; int len = ANY_LENGTH; tmp = UTF8_getch(&utf8str, &len); int FG = win->line[j].FG[w]; int BG = win->line[j].BG[w]; FillRectDIB(drawx,drawy,fontwidth,fontheight,BG); if ( tmp != UNKNOWN_UNICODE){ int cw = mk_wcwidth((wchar_t)tmp); len = ANY_LENGTH-len; if(cw>1) { FillRectDIB(drawx+fontwidth*(cw-1),drawy,fontwidth,fontheight,BG); w+=cw-1; } if(len>1) { i+=len-1; } if(tmp) OutputChar(tmp, drawx,drawy,FG); } else { switch ((unsigned char)win->line[j].chars[i]) { case LINE_OXOX_C://box bottom/top side (horizontal line) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); break; case LINE_XOXO_C://box left/right side (vertical line) VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); break; case LINE_OXXO_C://box top left HorzLineDIB(drawx+halfwidth,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy+halfheight,drawy+fontheight,2,FG); break; case LINE_OOXX_C://box top right HorzLineDIB(drawx,drawy+halfheight,drawx+halfwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy+halfheight,drawy+fontheight,2,FG); break; case LINE_XOOX_C://box bottom right HorzLineDIB(drawx,drawy+halfheight,drawx+halfwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+halfheight+1,2,FG); break; case LINE_XXOO_C://box bottom left HorzLineDIB(drawx+halfwidth,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+halfheight+1,2,FG); break; case LINE_XXOX_C://box bottom north T (left, right, up) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+halfheight,2,FG); break; case LINE_XXXO_C://box bottom east T (up, right, down) VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); HorzLineDIB(drawx+halfwidth,drawy+halfheight,drawx+fontwidth,1,FG); break; case LINE_OXXX_C://box bottom south T (left, right, down) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy+halfheight,drawy+fontheight,2,FG); break; case LINE_XXXX_C://box X (left down up right) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); break; case LINE_XOXX_C://box bottom east T (left, down, up) VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); HorzLineDIB(drawx,drawy+halfheight,drawx+halfwidth,1,FG); break; default: break; } };//switch (tmp) }//(tmp < 0) };//for (i=0;i<_windows[w].width;i++) } };// for (j=0;j<_windows[w].height;j++) win->draw=false; //We drew the window, mark it as so if (needupdate) try_update(); }
void curses_drawwindow(WINDOW *win) { int i,j,w,drawx,drawy; unsigned tmp; RECT update = {win->x * fontwidth, -1, (win->x + win->width) * fontwidth, -1}; for (j=0; j<win->height; j++){ if (win->line[j].touched) { update.bottom = (win->y+j+1)*fontheight; if (update.top == -1) { update.top = update.bottom - fontheight; } win->line[j].touched=false; for (i=0,w=0; w<win->width; i++,w++){ drawx=((win->x+w)*fontwidth); drawy=((win->y+j)*fontheight);//-j; if (((drawx+fontwidth)<=WindowWidth) && ((drawy+fontheight)<=WindowHeight)){ const char* utf8str = win->line[j].chars+i; int len = ANY_LENGTH; tmp = UTF8_getch(&utf8str, &len); int FG = win->line[j].FG[w]; int BG = win->line[j].BG[w]; FillRectDIB(drawx,drawy,fontwidth,fontheight,BG); if (tmp != UNKNOWN_UNICODE) { int color = RGB(windowsPalette[FG].rgbRed,windowsPalette[FG].rgbGreen,windowsPalette[FG].rgbBlue); SetTextColor(backbuffer,color); int cw = mk_wcwidth(tmp); len = ANY_LENGTH-len; if (cw > 1) { FillRectDIB(drawx+fontwidth*(cw-1), drawy, fontwidth, fontheight, BG); w += cw - 1; } if (len > 1) { i += len - 1; } if (tmp) ExtTextOutW (backbuffer, drawx, drawy, 0, NULL, (WCHAR*)&tmp, 1, NULL); } else { switch ((unsigned char)win->line[j].chars[i]) { case LINE_OXOX_C://box bottom/top side (horizontal line) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); break; case LINE_XOXO_C://box left/right side (vertical line) VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); break; case LINE_OXXO_C://box top left HorzLineDIB(drawx+halfwidth,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy+halfheight,drawy+fontheight,2,FG); break; case LINE_OOXX_C://box top right HorzLineDIB(drawx,drawy+halfheight,drawx+halfwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy+halfheight,drawy+fontheight,2,FG); break; case LINE_XOOX_C://box bottom right HorzLineDIB(drawx,drawy+halfheight,drawx+halfwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+halfheight+1,2,FG); break; case LINE_XXOO_C://box bottom left HorzLineDIB(drawx+halfwidth,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+halfheight+1,2,FG); break; case LINE_XXOX_C://box bottom north T (left, right, up) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+halfheight,2,FG); break; case LINE_XXXO_C://box bottom east T (up, right, down) VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); HorzLineDIB(drawx+halfwidth,drawy+halfheight,drawx+fontwidth,1,FG); break; case LINE_OXXX_C://box bottom south T (left, right, down) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy+halfheight,drawy+fontheight,2,FG); break; case LINE_XXXX_C://box X (left down up right) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); break; case LINE_XOXX_C://box bottom east T (left, down, up) VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); HorzLineDIB(drawx,drawy+halfheight,drawx+halfwidth,1,FG); break; default: break; } };//switch (tmp) }//(tmp < 0) };//for (i=0;i<_windows[w].width;i++) } };// for (j=0;j<_windows[w].height;j++) win->draw=false; //We drew the window, mark it as so if (update.top != -1) { RedrawWindow(WindowHandle, &update, NULL, RDW_INVALIDATE | RDW_UPDATENOW); } }
// utf-8 version std::string word_rewrap (const std::string &ins, int width) { std::ostringstream o; std::string in = ins; // find non-printing tags std::vector<size_t> tag_positions = get_tag_positions(in); int lastwb = 0; //last word break int lastout = 0; const char *instr = in.c_str(); bool skipping_tag = false; for (int j = 0, x = 0; j < in.size(); ) { const char *ins = instr + j; int len = ANY_LENGTH; unsigned uc = UTF8_getch(&ins, &len); if (uc == '<') { // maybe skip non-printing tag std::vector<size_t>::iterator it; for (it = tag_positions.begin(); it != tag_positions.end(); ++it) { if (*it == j) { skipping_tag = true; break; } } } j += ANY_LENGTH - len; if (skipping_tag) { if (uc == '>') { skipping_tag = false; } continue; } x += mk_wcwidth(uc); if (x > width) { if (lastwb == lastout) { lastwb = j; } for(int k = lastout; k < lastwb; k++) { o << in[k]; } o << '\n'; x = 0; lastout = j = lastwb; } if (uc == ' ' || uc >= 0x2E80) { lastwb = j; } } for (int k = lastout; k < in.size(); k++) { o << in[k]; } return o.str(); }
static int i_isalnum(unichar c) { if (term_type == TERM_TYPE_UTF8) return (g_unichar_isalnum(c) || mk_wcwidth(c) == 0); return (c >= 0 && c <= 255) ? isalnum(c) : 0; }
/* Truncate the message so that each line begins at column 'acol' and * ends at 'bcol' or sooner. The first column is number 0. The new * message is placed in 'out'. The message is expected to end in a * new line for now. * * NOTE: This needs to be modified to deal with backing up if we find * a SPACING COMBINING MARK at the end of a line. If that happens, we * should back up to the last non-mark character and stop there. * * NOTE: If a line ends at bcol, we omit the newline. This is so printing * to ncurses works. */ void owl_fmtext_truncate_cols(const owl_fmtext *in, int acol, int bcol, owl_fmtext *out) { const char *ptr_s, *ptr_e, *ptr_c, *last; int col, st, padding, chwidth; /* copy the default attributes */ out->default_attrs = in->default_attrs; out->default_fgcolor = in->default_fgcolor; out->default_bgcolor = in->default_bgcolor; last=in->textbuff+in->textlen-1; ptr_s=in->textbuff; while (ptr_s <= last) { ptr_e=strchr(ptr_s, '\n'); if (!ptr_e) { /* but this shouldn't happen if we end in a \n */ break; } if (ptr_e == ptr_s) { owl_fmtext_append_normal(out, "\n"); ++ptr_s; continue; } col = 0; st = 0; padding = 0; chwidth = 0; ptr_c = ptr_s; while(ptr_c < ptr_e) { gunichar c = g_utf8_get_char(ptr_c); if (!owl_fmtext_is_format_char(c)) { chwidth = mk_wcwidth(c); if (col + chwidth > bcol) break; if (col >= acol) { if (st == 0) { ptr_s = ptr_c; padding = col - acol; ++st; } } col += chwidth; chwidth = 0; } ptr_c = g_utf8_next_char(ptr_c); } if (st) { /* lead padding */ owl_fmtext_append_spaces(out, padding); if (ptr_c == ptr_e) { /* We made it to the newline. */ _owl_fmtext_append_fmtext(out, in, ptr_s - in->textbuff, ptr_c - in->textbuff); } else if (chwidth > 1) { /* Last char is wide, truncate. */ _owl_fmtext_append_fmtext(out, in, ptr_s - in->textbuff, ptr_c - in->textbuff - 1); owl_fmtext_append_normal(out, "\n"); } else { /* Last char fits perfectly, We skip to the next char and back * up a byte to make sure we get it all. */ ptr_c = g_utf8_next_char(ptr_c); _owl_fmtext_append_fmtext(out, in, ptr_s - in->textbuff, ptr_c - in->textbuff - 1); } } else { owl_fmtext_append_normal(out, "\n"); } ptr_s = g_utf8_next_char(ptr_e); } }
int main (int argc, char** argv) { UnitTest t (16); // Ensure environment has no influence. unsetenv ("TASKDATA"); unsetenv ("TASKRC"); t.is (mk_wcwidth ('a'), 1, "U+0061 --> 1"); t.is (mk_wcwidth (0x5149), 2, "U+5149 --> 2"); t.is (mk_wcwidth (0x9a8c), 2, "U+9a8c --> 2"); t.is (mk_wcwidth (0x4e70), 2, "U+4e70 --> 2"); t.is (mk_wcwidth (0x94b1), 2, "U+94b1 --> 2"); t.is (mk_wcwidth (0x5305), 2, "U+5305 --> 2"); t.is (mk_wcwidth (0x91cd), 2, "U+91cd --> 2"); t.is (mk_wcwidth (0x65b0), 2, "U+65b0 --> 2"); t.is (mk_wcwidth (0x8bbe), 2, "U+8bbe --> 2"); t.is (mk_wcwidth (0x8ba1), 2, "U+8ba1 --> 2"); t.is (mk_wcwidth (0x5411), 2, "U+5411 --> 2"); t.is (mk_wcwidth (0x4e0a), 2, "U+4e0a --> 2"); t.is (mk_wcwidth (0x4e0b), 2, "U+4e0b --> 2"); t.is (mk_wcwidth (0x7bad), 2, "U+7bad --> 2"); t.is (mk_wcwidth (0x5934), 2, "U+5934 --> 2"); t.is (mk_wcwidth (0xff0c), 2, "U+ff0c --> 2"); // comma return 0; }
int get_str_width(uint32_t ucs) { return mk_wcwidth(ucs); }
int waddch(WINDOW *win, const chtype ch) { char charcode; charcode=ch; switch (ch){ //LINE_NESW - X for on, O for off case LINE_XOXO: //#define LINE_XOXO 4194424 charcode=LINE_XOXO_C; break; case LINE_OXOX: //#define LINE_OXOX 4194417 charcode=LINE_OXOX_C; break; case LINE_XXOO: //#define LINE_XXOO 4194413 charcode=LINE_XXOO_C; break; case LINE_OXXO: //#define LINE_OXXO 4194412 charcode=LINE_OXXO_C; break; case LINE_OOXX: //#define LINE_OOXX 4194411 charcode=LINE_OOXX_C; break; case LINE_XOOX: //#define LINE_XOOX 4194410 charcode=LINE_XOOX_C; break; case LINE_XXOX: //#define LINE_XXOX 4194422 charcode=LINE_XXOX_C; break; case LINE_XXXO: //#define LINE_XXXO 4194420 charcode=LINE_XXXO_C; break; case LINE_XOXX: //#define LINE_XOXX 4194421 charcode=LINE_XOXX_C; break; case LINE_OXXX: //#define LINE_OXXX 4194423 charcode=LINE_OXXX_C; break; case LINE_XXXX: //#define LINE_XXXX 4194414 charcode=LINE_XXXX_C; break; default: charcode = (char)ch; break; } int cury=win->cursory; int p = win->cursorx; int curx=(win->line[cury].width_in_bytes==win->width)?win->cursorx:cursorx_to_position(win->line[cury].chars, win->cursorx, &p); if(curx!=p) { const char* ts = win->line[cury].chars+p; int len = ANY_LENGTH; unsigned tc = UTF8_getch(&ts, &len); int tw = mk_wcwidth((wchar_t)tc); win->line[cury].width_in_bytes += erease_utf8_by_cw(win->line[cury].chars+p, tw, tw, win->width*4-p-1); curx = p+tw-1; } else if(win->line[cury].width_in_bytes!=win->width) { win->line[cury].width_in_bytes += erease_utf8_by_cw(win->line[cury].chars+p, 1, 1, win->width*4-p-1); } //if (win2 > -1){ win->line[cury].chars[curx]=charcode; win->line[cury].FG[win->cursorx]=win->FG; win->line[cury].BG[win->cursorx]=win->BG; win->draw=true; addedchar(win); return 1; // else{ // win2=win2+1; }
/* * The following functions are the same as mk_wcwidth() and * mk_wcwidth_cjk(), except that spacing characters in the East Asian * Ambiguous (A) category as defined in Unicode Technical Report #11 * have a column width of 2. This variant might be useful for users of * CJK legacy encodings who want to migrate to UCS without changing * the traditional terminal character-width behaviour. It is not * otherwise recommended for general use. */ int mk_wcwidth_cjk(wchar_t ucs) { /* sorted list of non-overlapping intervals of East Asian Ambiguous * characters, generated by * * uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf \ * +E000..F8FF \ * +F0000..FFFFD \ * +100000..10FFFD c * * "WIDTH-A" is a file extracted from EastAsianWidth.txt by selecting * only those with width "A", and omitting: * * 0xAD * all lines with "COMBINING" * * (uniset does not recognize the range expressions in WIDTH-A). */ static const struct interval ambiguous[] = { { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 }, { 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B2 }, { 0x00B4, 0x00B4 }, { 0x00B6, 0x00B6 }, { 0x00B8, 0x00BA }, { 0x00BC, 0x00BC }, { 0x00BF, 0x00BF }, { 0x00C6, 0x00C6 }, { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00DE }, { 0x00E6, 0x00E6 }, { 0x00E8, 0x00E8 }, { 0x00EC, 0x00EC }, { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F2 }, { 0x00F7, 0x00F8 }, { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 }, { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B }, { 0x0126, 0x0126 }, { 0x012B, 0x012B }, { 0x0131, 0x0131 }, { 0x0138, 0x0138 }, { 0x013F, 0x013F }, { 0x0144, 0x0144 }, { 0x0148, 0x0148 }, { 0x014D, 0x014D }, { 0x0152, 0x0152 }, { 0x0166, 0x0166 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE }, { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 }, { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA }, { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 }, { 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02C9 }, { 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02D8 }, { 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x0391 }, { 0x03A3, 0x03A3 }, { 0x03B1, 0x03B1 }, { 0x03C3, 0x03C3 }, { 0x0401, 0x0401 }, { 0x0410, 0x0410 }, { 0x0451, 0x0451 }, { 0x2010, 0x2010 }, { 0x2013, 0x2013 }, { 0x2016, 0x2016 }, { 0x2018, 0x2019 }, { 0x201C, 0x201D }, { 0x2020, 0x2020 }, { 0x2024, 0x2024 }, { 0x2030, 0x2030 }, { 0x2032, 0x2032 }, { 0x2035, 0x2035 }, { 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 }, { 0x207F, 0x207F }, { 0x2081, 0x2081 }, { 0x20AC, 0x20AC }, { 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 }, { 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2121 }, { 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2153 }, { 0x215B, 0x215B }, { 0x2160, 0x2160 }, { 0x2170, 0x2170 }, { 0x2189, 0x2189 }, { 0x2190, 0x2190 }, { 0x2195, 0x2195 }, { 0x21B8, 0x21B8 }, { 0x21D2, 0x21D2 }, { 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 }, { 0x2202, 0x2202 }, { 0x2207, 0x2207 }, { 0x220B, 0x220B }, { 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 }, { 0x221A, 0x221A }, { 0x221D, 0x221D }, { 0x2223, 0x2223 }, { 0x2225, 0x2225 }, { 0x2227, 0x2227 }, { 0x222E, 0x222E }, { 0x2234, 0x2234 }, { 0x223C, 0x223C }, { 0x2248, 0x2248 }, { 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2260 }, { 0x2264, 0x2264 }, { 0x226A, 0x226A }, { 0x226E, 0x226E }, { 0x2282, 0x2282 }, { 0x2286, 0x2286 }, { 0x2295, 0x2295 }, { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF }, { 0x2312, 0x2312 }, { 0x2460, 0x2460 }, { 0x249C, 0x249C }, { 0x24EB, 0x24EB }, { 0x2500, 0x2500 }, { 0x2550, 0x2550 }, { 0x2580, 0x2580 }, { 0x2592, 0x2592 }, { 0x25A0, 0x25A0 }, { 0x25A3, 0x25A3 }, { 0x25B2, 0x25B2 }, { 0x25B6, 0x25B7 }, { 0x25BC, 0x25BC }, { 0x25C0, 0x25C1 }, { 0x25C6, 0x25C6 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25CE }, { 0x25E2, 0x25E2 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2605 }, { 0x2609, 0x2609 }, { 0x260E, 0x260E }, { 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 }, { 0x2642, 0x2642 }, { 0x2660, 0x2660 }, { 0x2663, 0x2663 }, { 0x2667, 0x2667 }, { 0x266C, 0x266C }, { 0x266F, 0x266F }, { 0x269E, 0x269E }, { 0x26BF, 0x26BF }, { 0x26C6, 0x26C6 }, { 0x26CF, 0x26CF }, { 0x26D5, 0x26D5 }, { 0x26E3, 0x26E3 }, { 0x26E8, 0x26E8 }, { 0x26EB, 0x26EB }, { 0x26F4, 0x26F4 }, { 0x26F6, 0x26F6 }, { 0x26FB, 0x26FB }, { 0x26FE, 0x26FE }, { 0x273D, 0x273D }, { 0x2776, 0x2776 }, { 0x2B56, 0x2B56 }, { 0x3248, 0x3248 }, { 0xE000, 0xF8FF }, { 0xFFFD, 0xFFFD }, { 0x1F100, 0x1F100 }, { 0x1F110, 0x1F110 }, { 0x1F130, 0x1F130 }, { 0x1F170, 0x1F170 }, { 0x1F18F, 0x1F18F }, { 0x1F19B, 0x1F19B }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD } }; /* binary search in table of non-spacing characters */ if (Lookup((unsigned long) ucs, ambiguous)) return 2; return mk_wcwidth(ucs); }
INTERNAL int vterm_unicode_width(int codepoint) { return mk_wcwidth(codepoint); }
// text "one two three\n four" // bytes 0123456789012 3456789 // characters 1234567890a23 4567890 // // leading_ws // ws ^ ^ ^^ // punct // break ^ bool extractLine ( std::string& line, const std::string& text, int width, bool hyphenate, unsigned int& offset) { // Terminate processing. // Note: bytes vs bytes. if (offset >= text.length ()) return false; std::string::size_type last_last_bytes = offset; std::string::size_type last_bytes = offset; std::string::size_type bytes = offset; unsigned int last_ws = 0; int character; int char_width = 0; int line_width = 0; while (1) { last_last_bytes = last_bytes; last_bytes = bytes; character = utf8_next_char (text, bytes); if (character == 0 || character == '\n') { line = text.substr (offset, last_bytes - offset); offset = bytes; break; } else if (character == ' ') last_ws = last_bytes; char_width = mk_wcwidth (character); if (line_width + char_width > width) { int last_last_character = text[last_last_bytes]; int last_character = text[last_bytes]; // [case 1] one| two --> last_last != 32, last == 32, ws == 0 if (last_last_character != ' ' && last_character == ' ') { line = text.substr (offset, last_bytes - offset); offset = last_bytes + 1; break; } // [case 2] one |two --> last_last == 32, last != 32, ws != 0 else if (last_last_character == ' ' && last_character != ' ' && last_ws != 0) { line = text.substr (offset, last_bytes - offset - 1); offset = last_bytes; break; } else if (last_last_character != ' ' && last_character != ' ') { // [case 3] one t|wo --> last_last != 32, last != 32, ws != 0 if (last_ws != 0) { line = text.substr (offset, last_ws - offset); offset = last_ws + 1; break; } // [case 4] on|e two --> last_last != 32, last != 32, ws == 0 else { if (hyphenate) { line = text.substr (offset, last_bytes - offset - 1) + "-"; offset = last_last_bytes; } else { line = text.substr (offset, last_bytes - offset); offset = last_bytes; } } break; } } line_width += char_width; } return true; }
void curses_drawwindow(WINDOW *win) { int i,j,w,drawx,drawy; unsigned tmp; int miny = 99999; int maxy = -99999; for (j=0; j<win->height; j++) { if (win->line[j].touched) { if(j<miny) { miny=j; } if(j>maxy) { maxy=j; } win->line[j].touched=false; for (i=0,w=0; w<win->width; i++,w++) { drawx=((win->x+w)*fontwidth); drawy=((win->y+j)*fontheight);//-j; if (((drawx+fontwidth)<=WindowWidth) && ((drawy+fontheight)<=WindowHeight)) { const char* utf8str = win->line[j].chars+i; int len = ANY_LENGTH; tmp = UTF8_getch(&utf8str, &len); int FG = win->line[j].FG[w]; int BG = win->line[j].BG[w]; FillRectDIB(drawx,drawy,fontwidth,fontheight,BG); if ( tmp != UNKNOWN_UNICODE){ int cw = mk_wcwidth((wchar_t)tmp); len = ANY_LENGTH-len; if(cw>1) { FillRectDIB(drawx+fontwidth*(cw-1),drawy,fontwidth,fontheight,BG); w+=cw-1; } if(len>1) { i+=len-1; } if(0!=tmp) { OutputChar(tmp, drawx,drawy,FG); } } else { switch ((unsigned char)win->line[j].chars[i]) { case LINE_OXOX_C://box bottom/top side (horizontal line) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); break; case LINE_XOXO_C://box left/right side (vertical line) VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); break; case LINE_OXXO_C://box top left HorzLineDIB(drawx+halfwidth,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy+halfheight,drawy+fontheight,2,FG); break; case LINE_OOXX_C://box top right HorzLineDIB(drawx,drawy+halfheight,drawx+halfwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy+halfheight,drawy+fontheight,2,FG); break; case LINE_XOOX_C://box bottom right HorzLineDIB(drawx,drawy+halfheight,drawx+halfwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+halfheight+1,2,FG); break; case LINE_XXOO_C://box bottom left HorzLineDIB(drawx+halfwidth,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+halfheight+1,2,FG); break; case LINE_XXOX_C://box bottom north T (left, right, up) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+halfheight,2,FG); break; case LINE_XXXO_C://box bottom east T (up, right, down) VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); HorzLineDIB(drawx+halfwidth,drawy+halfheight,drawx+fontwidth,1,FG); break; case LINE_OXXX_C://box bottom south T (left, right, down) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy+halfheight,drawy+fontheight,2,FG); break; case LINE_XXXX_C://box X (left down up right) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); break; case LINE_XOXX_C://box bottom east T (left, down, up) VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); HorzLineDIB(drawx,drawy+halfheight,drawx+halfwidth,1,FG); break; default: break; }//switch (tmp) } }//(tmp < 0) }//for (i=0;i<_windows[w].width;i++) } }// for (j=0;j<_windows[w].height;j++) win->draw=false; //We drew the window, mark it as so if(maxy>=0) { int tx=win->x, ty=win->y+miny, tw=win->width, th=maxy-miny+1; int maxw=WindowWidth/fontwidth, maxh=WindowHeight/fontheight; if(tw+tx>maxw) { tw= maxw-tx; } if(th+ty>maxh) { th= maxh-ty; } SDL_UpdateRect(screen, tx*fontwidth, ty*fontheight, tw*fontwidth, th*fontheight); } }
void curses_drawwindow(WINDOW *win) { int i,j,w,drawx,drawy; unsigned tmp; SDL_Rect update_rect; update_rect.x = win->x * fontwidth; update_rect.w = win->width * fontwidth; update_rect.y = 9999; // default value update_rect.h = 9999; // default value int jr = 0; for (j=0; j<win->height; j++){ if (win->line[j].touched) { if (update_rect.y == 9999) { update_rect.y = (win->y+j)*fontheight; jr=j; } update_rect.h = (j-jr+1)*fontheight; needupdate = true; win->line[j].touched=false; for (i=0,w=0; w<win->width; i++,w++){ drawx=((win->x+w)*fontwidth); drawy=((win->y+j)*fontheight);//-j; if (((drawx+fontwidth)<=WindowWidth) && ((drawy+fontheight)<=WindowHeight)){ const char* utf8str = win->line[j].chars+i; int len = ANY_LENGTH; tmp = UTF8_getch(&utf8str, &len); int FG = win->line[j].FG[w]; int BG = win->line[j].BG[w]; FillRectDIB(drawx,drawy,fontwidth,fontheight,BG); if ( tmp != UNKNOWN_UNICODE){ int cw = mk_wcwidth(tmp); len = ANY_LENGTH-len; if(cw>1) { FillRectDIB(drawx+fontwidth*(cw-1),drawy,fontwidth,fontheight,BG); w+=cw-1; } if(len>1) { i+=len-1; } if(tmp) OutputChar(tmp, drawx,drawy,FG); } else { switch ((unsigned char)win->line[j].chars[i]) { case LINE_OXOX_C://box bottom/top side (horizontal line) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); break; case LINE_XOXO_C://box left/right side (vertical line) VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); break; case LINE_OXXO_C://box top left HorzLineDIB(drawx+halfwidth,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy+halfheight,drawy+fontheight,2,FG); break; case LINE_OOXX_C://box top right HorzLineDIB(drawx,drawy+halfheight,drawx+halfwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy+halfheight,drawy+fontheight,2,FG); break; case LINE_XOOX_C://box bottom right HorzLineDIB(drawx,drawy+halfheight,drawx+halfwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+halfheight+1,2,FG); break; case LINE_XXOO_C://box bottom left HorzLineDIB(drawx+halfwidth,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+halfheight+1,2,FG); break; case LINE_XXOX_C://box bottom north T (left, right, up) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+halfheight,2,FG); break; case LINE_XXXO_C://box bottom east T (up, right, down) VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); HorzLineDIB(drawx+halfwidth,drawy+halfheight,drawx+fontwidth,1,FG); break; case LINE_OXXX_C://box bottom south T (left, right, down) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy+halfheight,drawy+fontheight,2,FG); break; case LINE_XXXX_C://box X (left down up right) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); break; case LINE_XOXX_C://box bottom east T (left, down, up) VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); HorzLineDIB(drawx,drawy+halfheight,drawx+halfwidth,1,FG); break; default: break; } };//switch (tmp) }//(tmp < 0) };//for (i=0;i<_windows[w].width;i++) } };// for (j=0;j<_windows[w].height;j++) win->draw=false; //We drew the window, mark it as so if (g && win == g->w_terrain && use_tiles) { update_rect.y = win->y*tilecontext->tile_height; update_rect.h = win->height*tilecontext->tile_height; update_rect.x = win->y*tilecontext->tile_width; update_rect.w = win->width*tilecontext->tile_width; //GfxDraw(thegame, win->x*fontwidth, win->y*fontheight, thegame->terrain_view_x, thegame->terrain_view_y, win->width*fontwidth, win->height*fontheight); tilecontext->draw(win->x * fontwidth, win->y * fontheight, g->ter_view_x, g->ter_view_y, tilecontext->terrain_term_x * fontwidth, tilecontext->terrain_term_y * fontheight); } //*/ if (update_rect.y != 9999) { SDL_UpdateRect(screen, update_rect.x, update_rect.y, update_rect.w, update_rect.h); } if (needupdate) try_update(); }
//////////////////////////////////////////////////////////////////////////////// // Walk the input text looking for a break point. A break point is one of: // - EOS // - \n // - last space before 'length' characters // - first 'length' characters void extractLine ( std::string& text, std::string& line, int length, bool hyphenate) { std::string::size_type bytes = 0; std::string::size_type previous = std::string::npos; std::string::size_type last_space = std::string::npos; int character; int width = 0; while (width < length) { previous = bytes; character = utf8_next_char (text, bytes); // Record last seen space. if (character == ' ') last_space = previous; // Newline is an early break point. if (character == '\n') { line = text.substr (0, bytes - 1); text = text.substr (bytes); return; } // EOS is an early break point. if (character == 0) { line = text; text = ""; return; } width += mk_wcwidth (character); } // Case where EOS was not quite reached. // 012345 // |eleven|\0 if (text[bytes] == '\0') { line = text; text = ""; return; } // Case where a word ends at the right margin. // 012345 // |eleven|_ if (text[bytes] == ' ') { line = text.substr (0, bytes); text = text.substr (bytes + 1); return; } // Case where a word straddles the margin, but there is an earlier space // to break on. // 012345 // |one_tw|o if (last_space != std::string::npos) { line = text.substr (0, last_space); text = text.substr (last_space + 1); return; } // Case where a word needs to be split, and there is no last_space. // Hyphenation becomes the issue. // 012345 // |fiftee|n // |fifte-|en else { if (hyphenate) { line = text.substr (0, previous) + "-"; text = text.substr (previous); } else { line = text.substr (0, bytes); text = text.substr (bytes); } return; } }
void curses_drawwindow(WINDOW *win) { int i,j,drawx,drawy; unsigned tmp; RECT update = {win->x * fontwidth, -1, (win->x + win->width) * fontwidth, -1}; for (j=0; j<win->height; j++){ if (win->line[j].touched) { update.bottom = (win->y+j+1)*fontheight; if (update.top == -1) { update.top = update.bottom - fontheight; } win->line[j].touched=false; for (i=0; i<win->width; i++){ const cursecell &cell = win->line[j].chars[i]; if( cell.ch.empty() ) { continue; // second cell of a multi-cell character } drawx=((win->x+i)*fontwidth); drawy=((win->y+j)*fontheight);//-j; if( drawx + fontwidth > WindowWidth || drawy + fontheight > WindowHeight ) { // Outside of the display area, would not render anyway continue; } const char* utf8str = cell.ch.c_str(); int len = cell.ch.length(); tmp = UTF8_getch(&utf8str, &len); int FG = cell.FG; int BG = cell.BG; FillRectDIB(drawx,drawy,fontwidth,fontheight,BG); if (tmp != UNKNOWN_UNICODE) { int color = RGB(windowsPalette[FG].rgbRed,windowsPalette[FG].rgbGreen,windowsPalette[FG].rgbBlue); SetTextColor(backbuffer,color); int cw = mk_wcwidth(tmp); if (cw > 1) { FillRectDIB(drawx+fontwidth*(cw-1), drawy, fontwidth, fontheight, BG); i += cw - 1; } if (tmp) { const std::wstring utf16 = widen(cell.ch); ExtTextOutW( backbuffer, drawx, drawy, 0, NULL, utf16.c_str(), utf16.length(), NULL ); } } else { switch ((unsigned char)win->line[j].chars[i].ch[0]) { case LINE_OXOX_C://box bottom/top side (horizontal line) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); break; case LINE_XOXO_C://box left/right side (vertical line) VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); break; case LINE_OXXO_C://box top left HorzLineDIB(drawx+halfwidth,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy+halfheight,drawy+fontheight,2,FG); break; case LINE_OOXX_C://box top right HorzLineDIB(drawx,drawy+halfheight,drawx+halfwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy+halfheight,drawy+fontheight,2,FG); break; case LINE_XOOX_C://box bottom right HorzLineDIB(drawx,drawy+halfheight,drawx+halfwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+halfheight+1,2,FG); break; case LINE_XXOO_C://box bottom left HorzLineDIB(drawx+halfwidth,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+halfheight+1,2,FG); break; case LINE_XXOX_C://box bottom north T (left, right, up) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+halfheight,2,FG); break; case LINE_XXXO_C://box bottom east T (up, right, down) VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); HorzLineDIB(drawx+halfwidth,drawy+halfheight,drawx+fontwidth,1,FG); break; case LINE_OXXX_C://box bottom south T (left, right, down) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy+halfheight,drawy+fontheight,2,FG); break; case LINE_XXXX_C://box X (left down up right) HorzLineDIB(drawx,drawy+halfheight,drawx+fontwidth,1,FG); VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); break; case LINE_XOXX_C://box bottom east T (left, down, up) VertLineDIB(drawx+halfwidth,drawy,drawy+fontheight,2,FG); HorzLineDIB(drawx,drawy+halfheight,drawx+halfwidth,1,FG); break; default: break; };//switch (tmp) }//(tmp < 0) };//for (i=0;i<_windows[w].width;i++) } };// for (j=0;j<_windows[w].height;j++) win->draw=false; //We drew the window, mark it as so if (update.top != -1) { RedrawWindow(WindowHandle, &update, NULL, RDW_INVALIDATE | RDW_UPDATENOW); } }
/* * The following functions are the same as mk_wcwidth() and * mk_wcwidth_cjk(), except that spacing characters in the East Asian * Ambiguous (A) category as defined in Unicode Technical Report #11 * have a column width of 2. This variant might be useful for users of * CJK legacy encodings who want to migrate to UCS without changing * the traditional terminal character-width behaviour. It is not * otherwise recommended for general use. */ int mk_wcwidth_cjk(wchar_t ucs) { /* sorted list of non-overlapping intervals of East Asian Ambiguous * characters, generated by * * uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf \ * +E000..F8FF \ * +F0000..FFFFD \ * +100000..10FFFD c * * "WIDTH-A" is a file extracted from EastAsianWidth.txt by selecting * only those with width "A", and omitting: * * 0xAD * all lines with "COMBINING" * * (uniset does not recognize the range expressions in WIDTH-A). */ /* *INDENT-OFF* */ static const struct interval ambiguous[] = { { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 }, { 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 }, { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 }, { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 }, { 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED }, { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA }, { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 }, { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B }, { 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 }, { 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 }, { 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 }, { 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE }, { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 }, { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA }, { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 }, { 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB }, { 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB }, { 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 }, { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 }, { 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 }, { 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 }, { 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 }, { 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 }, { 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 }, { 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC }, { 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 }, { 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 }, { 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 }, { 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 }, { 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 }, { 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 }, { 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B }, { 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 }, { 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 }, { 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E }, { 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 }, { 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 }, { 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F }, { 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 }, { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF }, { 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B }, { 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 }, { 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 }, { 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 }, { 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 }, { 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 }, { 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 }, { 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 }, { 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 }, { 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F }, { 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF }, { 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD } }; /* *INDENT-ON* */ /* binary search in table of non-spacing characters */ if (bisearch((unsigned long) ucs, ambiguous, (int) (sizeof(ambiguous) / sizeof(struct interval) - 1))) return 2; return mk_wcwidth(ucs); }
/* * The following functions are the same as mk_wcwidth() and * mk_wcswidth(), except that spacing characters in the East Asian * Ambiguous (A) category as defined in Unicode Technical Report #11 * have a column width of 2. This variant might be useful for users of * CJK legacy encodings who want to migrate to UCS without changing * the traditional terminal character-width behaviour. It is not * otherwise recommended for general use. */ int mk_wcwidth_cjk(wchar_t ucs) { /* sorted list of non-overlapping intervals of East Asian Ambiguous * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */ static const struct interval ambiguous[] = { { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 }, { 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 }, { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 }, { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 }, { 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED }, { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA }, { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 }, { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B }, { 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 }, { 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 }, { 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 }, { 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE }, { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 }, { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA }, { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 }, { 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB }, { 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB }, { 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 }, { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 }, { 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 }, { 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 }, { 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 }, { 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 }, { 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 }, { 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC }, { 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 }, { 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 }, { 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 }, { 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 }, { 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 }, { 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 }, { 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B }, { 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 }, { 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 }, { 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E }, { 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 }, { 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 }, { 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F }, { 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 }, { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF }, { 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B }, { 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 }, { 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 }, { 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 }, { 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 }, { 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 }, { 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 }, { 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 }, { 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 }, { 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F }, { 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF }, { 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD } }; /* binary search in table of non-spacing characters */ if (bisearch(ucs, ambiguous, sizeof(ambiguous) / sizeof(struct interval) - 1)) return 2; return mk_wcwidth(ucs); }
int main (int argc, char** argv) { UnitTest t (16); t.is (mk_wcwidth ('a'), 1, "U+0061 --> 1"); t.is (mk_wcwidth (0x5149), 2, "U+5149 --> 2"); t.is (mk_wcwidth (0x9a8c), 2, "U+9a8c --> 2"); t.is (mk_wcwidth (0x4e70), 2, "U+4e70 --> 2"); t.is (mk_wcwidth (0x94b1), 2, "U+94b1 --> 2"); t.is (mk_wcwidth (0x5305), 2, "U+5305 --> 2"); t.is (mk_wcwidth (0x91cd), 2, "U+91cd --> 2"); t.is (mk_wcwidth (0x65b0), 2, "U+65b0 --> 2"); t.is (mk_wcwidth (0x8bbe), 2, "U+8bbe --> 2"); t.is (mk_wcwidth (0x8ba1), 2, "U+8ba1 --> 2"); t.is (mk_wcwidth (0x5411), 2, "U+5411 --> 2"); t.is (mk_wcwidth (0x4e0a), 2, "U+4e0a --> 2"); t.is (mk_wcwidth (0x4e0b), 2, "U+4e0b --> 2"); t.is (mk_wcwidth (0x7bad), 2, "U+7bad --> 2"); t.is (mk_wcwidth (0x5934), 2, "U+5934 --> 2"); t.is (mk_wcwidth (0xff0c), 2, "U+ff0c --> 2"); // comma return 0; }