unsigned int SLsmg_strwidth (SLuchar_Type *u, SLuchar_Type *umax) { unsigned char display_8bit; int utf8_mode = UTF8_Mode; int col; if (u == NULL) return 0; display_8bit = (unsigned char) SLsmg_Display_Eight_Bit; if (utf8_mode) display_8bit = 0xA0; col = This_Col; while (u < umax) { SLuchar_Type ch; unsigned int nconsumed; SLwchar_Type wc; ch = *u; if (ch < 0x80) { u++; if ((ch >= 0x20) && (ch != 0x7F)) { col++; continue; } if ((ch == '\t') && (SLsmg_Tab_Width > 0)) { if (col >= 0) col = (1 + col/SLsmg_Tab_Width) * SLsmg_Tab_Width; else col = ((col + 1)/SLsmg_Tab_Width) * SLsmg_Tab_Width; continue; } if ((ch == '\n') && (SLsmg_Newline_Behavior != SLSMG_NEWLINE_PRINTABLE)) break; if ((ch == 0x8) && SLsmg_Backspace_Moves) { col--; continue; } #if SLSMG_HAS_EMBEDDED_ESCAPE if ((ch == 033) && Embedded_Escape_Mode) { SLsmg_Color_Type color; if (0 == parse_embedded_escape (u, umax, 0, &u, &color)) continue; } #endif col += 2; continue; } nconsumed = 1; if ((utf8_mode == 0) || (NULL == SLutf8_decode (u, umax, &wc, &nconsumed))) { if ((utf8_mode == 0) && (display_8bit && (*u >= display_8bit))) col++; else col += 4*nconsumed; u += nconsumed; continue; } u += nconsumed; if (wc < (SLwchar_Type)display_8bit) { col += 4; continue; } col += SLwchar_wcwidth (wc); } if (col < This_Col) return 0; return (unsigned int) (col - This_Col); }
int SLcurses_waddch (SLcurses_Window_Type *win, SLtt_Char_Type attr) { SLtt_Char_Type ch; SLsmg_Color_Type color; int width; int is_acs; if (win == NULL) return -1; if (win->_cury >= win->nrows) { /* Curses seems to move current position to top of window. */ win->_cury = win->_curx = 0; return -1; } win->modified = 1; ch = SLTT_EXTRACT_CHAR(attr); if (ch == 0) return -1; if (attr == ch) color = win->color; else { /* hack to pick up the default color for graphics chars */ if (((attr & A_COLOR) == 0) && ((attr & A_ALTCHARSET) != 0)) { SLCURSES_BUILD_CHAR(attr, attr, win->color); } color = map_attr_to_object (attr); } is_acs = attr & A_ALTCHARSET; if (SLwchar_iscntrl((SLwchar_Type)ch)) { if (ch == '\n') { SLcurses_wclrtoeol (win); return do_newline (win); } if (ch == '\r') { win->_curx = 0; return 0; } if (ch == '\b') { if (win->_curx > 0) win->_curx--; return 0; } if (ch == '\t') { int err; do err = SLcurses_waddch (win, (SLtt_Char_Type)' '); while (err == 0 && win->_curx % SLsmg_Tab_Width != 0); return err; } } width = SLwchar_isprint (ch) ? (SLsmg_is_utf8_mode () ? SLwchar_wcwidth (ch) : 1) : 0; if (win->_curx + width > win->ncols) { SLcurses_wclrtoeol (win); do_newline (win); } SLcurses_placechar (win, ch, width, color, is_acs); win->_curx += width; return 0; }
/* Note: if len is < 0, entire string will be used. */ int SLcurses_waddnstr (SLcurses_Window_Type *w, char *str, int len) { unsigned int nrows, ncols, crow, ccol; SLuchar_Type *u, *umax; int is_acs = 0; if ((w == NULL) || (str == NULL)) return -1; w->modified = 1; nrows = w->nrows; ncols = w->ncols; crow = w->_cury; ccol = w->_curx; if (w->scroll_max <= nrows) nrows = w->scroll_max; if (crow >= nrows) crow = 0; /* wrap back to top */ u = (SLuchar_Type *)str; umax = &u[len >= 0 ? (unsigned int)len : strlen(str)]; while (u < umax) { SLwchar_Type ch; unsigned int nconsumed; int width = 1; if (SLsmg_is_utf8_mode () && SLutf8_decode (u, umax, &ch, &nconsumed)) { u += nconsumed; if ((ch & A_CHARTEXT) != ch) { ch = (SLwchar_Type)0xFFFDL; /* Unicode replacement character */ width = 1; } else if (SLwchar_isprint (ch)) width = SLwchar_wcwidth (ch); else width = 0; /* FIXME: cope with <%02X> printstrings. */ } else { ch = (SLwchar_Type)*u++; if (ch < 0x20 || (ch >= 0x7f && ch < 0xa0)) width = 0; /* FIXME: use display_8bit */ } if (ch == '\t') width = 1; /* HACK forcing linewrap if ccol==ncols */ if (ch == 0) continue; /* Avoid adding a literal SLCURSES_NULLCHAR. */ /* FIXME; should this function be defined in terms of waddch? */ if (ch == '\n') { w->_cury = crow; w->_curx = ccol; SLcurses_wclrtoeol (w); do_newline (w); crow = w->_cury; ccol = w->_curx; continue; } if (ccol + width > ncols) { w->_curx = ccol; w->_cury = crow; SLcurses_wclrtoeol(w); /* no-op if width<=1 */ w->_curx = ccol = 0; w->_cury = ++crow; if (crow >= nrows) { do_newline (w); crow = w->_cury; ccol = w->_curx; } } if (ch == '\t') { /* assert (ccol < ncols); */ w->_curx = ccol; w->_cury = crow; do { SLcurses_placechar (w, (SLwchar_Type)' ', 1, w->color, is_acs); w->_curx = ++ccol; } while (ccol < ncols && ccol % SLsmg_Tab_Width != 0); continue; } SLcurses_placechar (w, ch, width, w->color, is_acs); w->_curx = (ccol += width); } w->_curx = ccol; w->_cury = crow; return 0; }
void SLsmg_write_wrapped_string (SLuchar_Type *u, int r, int c, unsigned int dr, unsigned int dc, int fill) { int maxc = (int) dc; unsigned char *p, *pmax; int utf8_mode = UTF8_Mode; unsigned char display_8bit = (unsigned char) SLsmg_Display_Eight_Bit; if (utf8_mode) display_8bit = 0xA0; if ((dr == 0) || (dc == 0)) return; if (u == NULL) u = (unsigned char *)""; p = u; pmax = u + strlen ((char *)u); dc = 0; while (1) { SLwchar_Type wc; unsigned int nconsumed; unsigned char ch = *p; unsigned int ddc; if ((ch == 0) || (ch == '\n')) { int diff; diff = maxc - (int) dc; SLsmg_gotorc (r, c); SLsmg_write_chars (u, p); if (fill && (diff > 0)) { unsigned char *blank = (unsigned char *)" "; while (diff--) SLsmg_write_chars (blank, blank+1); } if ((ch == 0) || (dr == 1)) break; r++; dc = 0; dr--; p++; u = p; continue; } /* If the width of the characters buffered so far extend to or beyond * the width of the box, then write them out and goto the * next line. Note that dc > maxc if the displayable width of * the last character to be written is greater than the width * of the box. This will be the case if (maxc<ddc) -- see below */ if ((int) dc >= maxc) goto write_chars_and_reset; nconsumed = 1; if (ch < 0x80) { p++; if ((ch >= 0x20) && (ch != 0x7F)) { dc++; continue; } /* Otherwise display as ^X */ dc += 2; continue; } nconsumed = 1; if ((utf8_mode == 0) || (NULL == SLutf8_decode (p, pmax, &wc, &nconsumed))) { if ((utf8_mode == 0) && (display_8bit && (*p >= display_8bit))) { dc++; p += nconsumed; continue; } ddc = 4*nconsumed; /* <XX> */ } else if (wc < (SLwchar_Type)display_8bit) ddc = 4; /* displays as <XX> */ else ddc = SLwchar_wcwidth (wc); dc += ddc; if (((int)dc > maxc) && (maxc > (int)ddc)) { dc -= ddc; goto write_chars_and_reset; } p += nconsumed; continue; write_chars_and_reset: SLsmg_gotorc (r, c); SLsmg_write_chars (u, p); while ((int)dc < maxc) { SLsmg_write_char (' '); dc++; } if (dr == 1) break; r++; dc = 0; dr--; u = p; } }
int SLcurses_winsch (SLcurses_Window_Type *w, int ch) { int is_acs = 0; int colsneeded; #ifndef HAVE_MEMMOVE int dest, src; #endif SLcurses_Cell_Type *line = w->lines[w->_cury]; /* Backtrack to start of this character. */ while (w->_curx > 0 && line[w->_curx].main == SLCURSES_NULLATTR) w->_curx--; if (ch == (SLcurses_Char_Type)'\t') ch = ' '; /* FIXME */ if (SLwchar_isprint (ch)) { if (SLsmg_is_utf8_mode ()) colsneeded = SLwchar_wcwidth (ch); else colsneeded = 1; } else colsneeded = 0; if (colsneeded == 0) { int x, i; SLcurses_Cell_Type *b = NULL; /* Back one character. */ for (x = w->_curx - 1; x >= 0; x--) { b = &line[x]; if (b->main != SLCURSES_NULLATTR) break; } if (x < 0) { /* Back to end of previous line. */ if (w->_cury == 0) return (-1); line = w->lines[w->_cury - 1]; for (x = w->ncols - 1; x >= 0; x--) { b = &line[x]; if (b->main != SLCURSES_NULLATTR) break; } if (x < 0) return (-1); } /* b is previous character; insert combining character ch in *b. */ for (i = 0; i < SLSMG_MAX_CHARS_PER_CELL-1; i++) if (b->combining[i] == SLCURSES_NULLCHAR) break; if (i < SLSMG_MAX_CHARS_PER_CELL-1) b->combining[i] = ch; return 0; } /* Remove trailing character(s) from line. */ if ((colsneeded > 0) && ((unsigned int)colsneeded <= w->ncols)) { int i; for (i = w->ncols - colsneeded; i > 0; i--) if (line[i].main != SLCURSES_NULLATTR) break; /* line[w->ncols-colsneeded..w->ncols-1] will be shifted off the end, * but if i < w->ncols-colsneeded, then line[i..w->ncols-colsneeded-1] * must be blanked because they are part of a multicolumn character * which is partially shifted off the end. */ while (i + colsneeded < (int)w->ncols) SLCURSES_BUILD_CELL(&line[i++], ' ', w->color, is_acs); } /* line[_curx+colsneeded..ncols-1] = line[_curx..ncols-1-colsneeded]; */ #ifdef HAVE_MEMMOVE memmove(&line[w->_curx+colsneeded], &line[w->_curx], ncols-(w->_curx+colsneeded)); #else dest = w->ncols - 1; for (src = dest - colsneeded; src >= (int)w->_curx; src--, dest--) line[dest] = line[src]; #endif if (w->_curx + colsneeded <= w->ncols) SLcurses_placechar (w, ch, colsneeded, w->color, is_acs); w->modified = 1; return 0; }
void SLsmg_write_chars (unsigned char *u, unsigned char *umax) { SLsmg_Char_Type *p, *pmax; SLsmg_Color_Type color; int flags; int col, start_col, max_col; int newline_flag; int utf8_mode = UTF8_Mode; unsigned char display_8bit; int last_was_double_width = 0; int alt_char_set_flag; unsigned int i; #if SLSMG_HAS_EMBEDDED_ESCAPE SLsmg_Color_Type default_color; #endif if (Smg_Inited == 0) return; if (u >= umax) return; display_8bit = (unsigned char) SLsmg_Display_Eight_Bit; if (utf8_mode) display_8bit = 0xA0; color = This_Color; /* If we are using unicode characters for the line drawing characters, then * do not attempt to use the terminals alternate character set */ alt_char_set_flag = (color & SLSMG_ACS_MASK); if (Current_ACS_Mode == ACS_MODE_UNICODE) color = color & ~SLSMG_ACS_MASK; #if SLSMG_HAS_EMBEDDED_ESCAPE default_color = color; /* used for ESC[m */ #endif top: /* get here only on newline */ newline_flag = 0; start_col = Start_Col; if (point_visible (0) == 0) return; col = This_Col; max_col = start_col + Screen_Cols; p = SL_Screen[This_Row - Start_Row].neew; pmax = p + Screen_Cols; if (col >= start_col) { p += (col - start_col); if ((p < pmax) && (p->nchars == 0)) { /* It looks like we are about to overwrite the right side of a * double width character. Let's see... */ if (col > start_col) { p--; if (p->nchars != 0) { p->nchars = 1; p->wchars[0] = ' '; } p++; } } } flags = SL_Screen[This_Row - Start_Row].flags; i = 0; while (u < umax) { SLwchar_Type wc; unsigned int width, nconsumed; if (*u < (SLuchar_Type) 0x80) /* ASCII */ { unsigned char ch; ch = (unsigned char) *u++; if (alt_char_set_flag) { wc = ACS_Map[ch]; ADD_CHAR_OR_BREAK(wc); continue; } if ((ch >= (SLuchar_Type)0x20) && (ch < (SLuchar_Type)0x7F)) { ADD_CHAR_OR_BREAK(ch); continue; } if ((ch == '\t') && (SLsmg_Tab_Width > 0)) { do { if (col < start_col) col++; else { ADD_CHAR_OR_BREAK(' '); NEXT_CHAR_CELL; } } while (col % SLsmg_Tab_Width); continue; } if ((ch == '\n') && (SLsmg_Newline_Behavior != SLSMG_NEWLINE_PRINTABLE)) { newline_flag = 1; break; } if ((ch == 0x8) && SLsmg_Backspace_Moves) { if (col != 0) { if (i != 0) { NEXT_CHAR_CELL; col--; p--; } col--; p--; } continue; } #if SLSMG_HAS_EMBEDDED_ESCAPE if ((ch == 033) && Embedded_Escape_Mode) { SLsmg_Color_Type next_color; if (0 == parse_embedded_escape (u, umax, default_color, &u, &next_color)) { if (i != 0) NEXT_CHAR_CELL; color = next_color; continue; } } #endif ADD_CHAR_OR_BREAK('^'); if (ch == 127) ch = '?'; else ch = ch + '@'; ADD_CHAR_OR_BREAK (ch); continue; } nconsumed = 1; if ((utf8_mode == 0) || (NULL == SLutf8_decode (u, umax, &wc, &nconsumed))) { unsigned int ii, jj; unsigned char hexbuf[8]; if ((utf8_mode == 0) && display_8bit && (*u >= display_8bit)) { ADD_CHAR_OR_BREAK(*u); } else for (ii = 0; ii < nconsumed; ii++) { sprintf ((char *)hexbuf, "<%02X>", u[ii]); for (jj = 0; jj < 4; jj++) { ADD_CHAR_OR_BREAK (hexbuf[jj]); } } u += nconsumed; continue; } u += nconsumed; if (wc < (SLwchar_Type)display_8bit) { unsigned char hexbuf[8]; unsigned int jj; sprintf ((char *)hexbuf, "<%02X>", (unsigned char) wc); for (jj = 0; jj < 4; jj++) { ADD_CHAR_OR_BREAK (hexbuf[jj]); } continue; } width = SLwchar_wcwidth (wc); if (width == 0) { /* Combining character--- must follow non-zero width char */ if (i == 0) continue; if (i < SLSMG_MAX_CHARS_PER_CELL) { ADD_TO_CHAR_CELL (wc); } continue; } if (width == 2) { if (col + 2 <= start_col) { col += 2; continue; } if (col + 1 == start_col) { /* double width character is clipped at left part of screen. * So, display right edge as a space */ col++; /* left edge */ ADD_CHAR_OR_BREAK('<'); continue; } if (i != 0) /* finish active cell */ NEXT_CHAR_CELL; if (last_was_double_width) { /* and right half of the cell */ last_was_double_width = 0; NEXT_CHAR_CELL; } if (col + 2 > max_col) { /* right side of character gets clipped */ ADD_TO_CHAR_CELL('>'); col++; break; } ADD_CHAR_OR_BREAK(wc); last_was_double_width = 1; continue; } ADD_CHAR_OR_BREAK(wc); } if (i != 0) { NEXT_CHAR_CELL; } if (last_was_double_width) { if (col < max_col) NEXT_CHAR_CELL; last_was_double_width = 0; } else if ((col < max_col) && (p->nchars == 0)) { /* The left side of a double with character was overwritten */ p->nchars = 1; p->wchars[0] = ' '; } SL_Screen[This_Row - Start_Row].flags = flags; This_Col = col; /* Why would u be NULL here?? */ if (SLsmg_Newline_Behavior == SLSMG_NEWLINE_IGNORED) { #if SLSMG_HAS_EMBEDDED_ESCAPE if (Embedded_Escape_Mode && (u != NULL)) parse_embedded_set_color (u, umax, default_color); #endif return; } if (newline_flag == 0) { #if SLSMG_HAS_EMBEDDED_ESCAPE SLuchar_Type *usave = u; #endif if (u == NULL) return; while (u < umax) { if (*u == '\n') break; u++; } if (u >= umax) { #if SLSMG_HAS_EMBEDDED_ESCAPE if (Embedded_Escape_Mode) parse_embedded_set_color (usave, umax, default_color); #endif return; } u++; } This_Row++; This_Col = 0; if (This_Row == Start_Row + (int)Screen_Rows) { if (SLsmg_Newline_Behavior == SLSMG_NEWLINE_SCROLLS) scroll_up (); } goto top; }
static void init_acs (int mode) { unsigned int i; SLCONST ACS_Def_Type *acs; if (Current_ACS_Mode == mode) return; for (i = 0; i < 0x80; i++) ACS_Map[i] = ' '; if (mode == ACS_MODE_AUTO) { if (UTF8_Mode && (tt_unicode_ok != NULL) && (*tt_unicode_ok > 0)) mode = ACS_MODE_UNICODE; else mode = ACS_MODE_TERMINFO; } switch (mode) { case ACS_MODE_UNICODE: SLsmg_Display_Eight_Bit = 0xA0; acs = UTF8_ACS_Map; while (acs->vt100_char != 0) { SLwchar_Type wch = acs->unicode; if (SLwchar_wcwidth (wch) != 1) wch = acs->unicode_narrow; ACS_Map[acs->vt100_char] = wch; acs++; } break; case ACS_MODE_TERMINFO: if ((tt_Has_Alt_Charset != NULL) && *tt_Has_Alt_Charset && (tt_Graphics_Char_Pairs != NULL) && (*tt_Graphics_Char_Pairs != NULL)) { unsigned char *p = (unsigned char *) *tt_Graphics_Char_Pairs; unsigned char *pmax = p + strlen ((char *) p); while (p < pmax) { unsigned char ch = *p++; ACS_Map[ch & 0x7F] = *p++; } break; } mode = ACS_MODE_ASCII; /* drop */ case ACS_MODE_ASCII: default: acs = UTF8_ACS_Map; while (acs->vt100_char != 0) { ACS_Map[acs->vt100_char] = acs->ascii; acs++; } break; } Current_ACS_Mode = mode; }
/* If the string u were written at the current positition, this function * returns the number of bytes necessary to reach the specified width. */ unsigned int SLsmg_strbytes (SLuchar_Type *u, SLuchar_Type *umax, unsigned int width) { SLuchar_Type *ustart; unsigned char display_8bit; int utf8_mode = UTF8_Mode; int col, col_max; if (u == NULL) return 0; display_8bit = (unsigned char) SLsmg_Display_Eight_Bit; if (utf8_mode) display_8bit = 0xA0; col = This_Col; col_max = col + width; ustart = u; while (u < umax) { SLuchar_Type ch; SLwchar_Type wc; unsigned int nconsumed = 1; ch = *u; if (ch < 0x80) { if ((ch >= 0x20) && (ch != 0x7F)) col++; else if ((ch == '\t') && (SLsmg_Tab_Width > 0)) { if (col >= 0) col = (1 + col/SLsmg_Tab_Width) * SLsmg_Tab_Width; else col = ((col + 1)/SLsmg_Tab_Width) * SLsmg_Tab_Width; } else if ((ch == '\n') && (SLsmg_Newline_Behavior != SLSMG_NEWLINE_PRINTABLE)) break; else if ((ch == 0x8) && SLsmg_Backspace_Moves) col--; #if SLSMG_HAS_EMBEDDED_ESCAPE else if ((ch == 033) && Embedded_Escape_Mode) { SLsmg_Color_Type color; SLuchar_Type *u1 = u+1; if (-1 == parse_embedded_escape (u1, umax, 0, &u1, &color)) col += 2; nconsumed = (u1 - u); } #endif else col += 2; } else if ((utf8_mode == 0) || (NULL == SLutf8_decode (u, umax, &wc, &nconsumed))) { if ((utf8_mode == 0) && (display_8bit && (*u >= display_8bit))) col++; else col += 4*nconsumed; /* <XX> */ } else if (wc < (SLwchar_Type)display_8bit) col += 4; else col += SLwchar_wcwidth (wc); if (col >= col_max) break; u += nconsumed; } return (unsigned int) (u - ustart); }
SLuchar_Type *SLutf8_bskip_chars (SLuchar_Type *smin, SLuchar_Type *s, unsigned int num, unsigned int *dnum, int ignore_combining) { unsigned int n; SLuchar_Type *smax = s; n = 0; while ((n < num) && (s > smin)) { unsigned char ch; unsigned int dn; s--; ch = *s; if (ch < 0x80) { n++; smax = s; continue; } dn = 0; while ((s != smin) && (Len_Map[ch] == 0) && (dn < SLUTF8_MAX_MBLEN)) { s--; ch = *s; dn++; } if (ch <= 0xBF) { /* Invalid sequence */ n++; smax--; s = smax; continue; } if (ch > 0xBF) { SLwchar_Type w; SLuchar_Type *s1; if ((NULL == (s1 = SLutf8_decode (s, smax, &w, NULL))) || (s1 != smax)) { /* This means we backed up over an invalid sequence */ dn = (unsigned int) (smax - s); n++; smax--; s = smax; continue; } if ((ignore_combining == 0) || (0 != SLwchar_wcwidth (w))) n++; smax = s; } } if (dnum != NULL) *dnum = n; return s; }
SLuchar_Type *SLutf8_skip_chars (SLuchar_Type *s, SLuchar_Type *smax, unsigned int num, unsigned int *dnum, int ignore_combining) { unsigned int n; n = 0; while ((n < num) && (s < smax)) { unsigned int len = Len_Map[*s]; if (len <= 1) { n++; s++; continue; } if (s + len > smax) { s++; n++; continue; } if (is_invalid_or_overlong_utf8 (s, len)) { s++; n++; continue; } if (ignore_combining) { SLwchar_Type w = fast_utf8_decode (s, len); if (0 != SLwchar_wcwidth (w)) n++; s += len; continue; } n++; s += len; } if (ignore_combining) { while (s < smax) { SLwchar_Type w; unsigned int nconsumed; if (NULL == SLutf8_decode (s, smax, &w, &nconsumed)) break; if (0 != SLwchar_wcwidth (w)) break; s += nconsumed; } } if (dnum != NULL) *dnum = n; return s; }