/*======================================================================*\ |* Editor mined *| |* display output functions *| \*======================================================================*/ #include "mined.h" #include "io.h" #include "termprop.h" #include /*======================================================================*\ |* Scroll bar display *| \*======================================================================*/ static void disp_scrollbar_cellend () { } static void disp_scrollbar_end () { if (! standout_glitch) { disp_scrollbar_off (); } } /* mined displays last_y + 1 lines in a display area of YMAX lines */ /* the file has (approx.?) total_lines lines */ /* the file position was in line # line_number */ /* debug traces: */ #define dont_debug_scrollbar #define dont_debug_scrollbar_calc #define dont_debug_partial_scroll #define dont_debug_dirty /* visible debug scrollbar: */ #define dont_debug_lazy_scrollbar static int prev_disp_start = 0; static int prev_disp_end = 0; static char shiftskipdouble = ''; /* indicator for shifted double width char */ static FLAG scrollbar_dirty = True; /* does scrollbar need refresh ? */ static int first_dirty = -1; static int last_dirty = -1; #ifdef debug_dirty #define printf_dirty(s, n) printf ("%s %d - (prev %d..%d) [%d dirty %d..%d]\n", s, n, prev_disp_start, prev_disp_end, scrollbar_dirty, first_dirty, last_dirty); #else #define printf_dirty(s, n) #endif static void set_scrollbar_dirty (scry) int scry; { scrollbar_dirty = True; if (scry < first_dirty || first_dirty < 0) { first_dirty = scry; } if (scry > last_dirty) { last_dirty = scry; } #ifdef debug_partial_scroll printf ("scrollbar_dirty @ %d, -> dirty %d..%d\n", scry, first_dirty, last_dirty); #endif printf_dirty ("set_dirty", scry); } void scrollbar_scroll_up (from) int from; { int unit = utf8_screen && fine_scrollbar ? 8 : 1; if (prev_disp_start >= (from + 1) * unit) { prev_disp_start -= unit; } if (prev_disp_end >= (from + 1) * unit) { prev_disp_end -= unit; } set_scrollbar_dirty (SCREENMAX - 1); #ifdef debug_partial_scroll printf ("scrollbar_scroll_up from %d, -> prev %d..%d\n", from, prev_disp_start, prev_disp_end); #endif printf_dirty ("scroll_up", from); } void scrollbar_scroll_down (from) int from; { int unit = utf8_screen && fine_scrollbar ? 8 : 1; if (prev_disp_start >= from * unit) { prev_disp_start += unit; } if (prev_disp_end >= from * unit) { prev_disp_end += unit; } set_scrollbar_dirty (from); #ifdef debug_partial_scroll printf ("scrollbar_scroll_down from %d, -> prev %d..%d\n", from, prev_disp_start, prev_disp_end); #endif printf_dirty ("scroll_down", from); } static FLAG fine_grained_scrollbar (force) FLAG force; { /* calculate scroll bar display using Unicode character cell vertical eighth blocks U+2581..U+2587 ▁▂▃▄▅▆▇ as follows: * screen has lines 0...last_y, screen_lines = last_y + 1, with fields = screen_lines * 8, e.g. 10 lines 0...9, 80 fields 0...79; * to be mapped to buffer line numbers 1...total_lines; scroll block size in fields is s / fields = screen_lines / total_lines, s = screen_lines * fields / total_lines, minimum 1 (display) / 7 (Unicode) / 8 (algorithm), max_start = fields - s; * scroll block start position is in range 0...(80 - s), to be mapped to position of last screen line last_line_number = (line_number - y + last_y): if last_line_number <= screen_lines ==> p = 0 if last_line_number == total_lines ==> p = max_start so roughly: p / max_start = (last_line_number - screen_lines) / (total_lines - screen_lines); but to accomodate rounding problems and avoid zero division map range last_line_number = screen_lines + 1 ==> p = start1, last_line_number = total_lines - 1 ==> p = max_start - 1, where start1 corresponds to the delta caused by scrolling by 1 line; start1 / fields = 1 / (total_lines - screen_lines), min 1, but replace this with an adjustment (see below) for better computation; - distribute equally, so map (max_start - start1) fields to (total_lines - 1 - screen_lines) lines where both will taken to zero by an offset for scaling: fields start1 ... max_start-1 ==> consider result to be p - start1 lines screen_lines + 1 ... total_lines - 1 ==> consider ref_last/total = last/total_line_number - (screen_lines + 1): p - start1 / max_start = (last_line_number - screen_lines - 1) / (total_line_number - screen_lines - 1) * scroll block extends from p to p + s - 1 */ int unit = utf8_screen && fine_scrollbar ? 8 : 1; int screen_lines; long fields; int s; int max_start; long last_line_number; int disp_start; int disp_end; int i; int scri; FLAG painted = False; int slices = 0; int oldslices = 0; FLAG klopsinslot; FLAG oldklopsinslot; screen_lines = last_y + 1; fields = screen_lines * unit; s = fields * screen_lines / total_lines; if (s < unit) { s = unit; } max_start = fields - s; last_line_number = line_number - y + last_y; if (last_line_number <= screen_lines) { disp_start = 0; } else if (last_line_number == total_lines) { disp_start = max_start; } else { /* compensate by + 1 for adjustment at the beginning */ disp_start = max_start * (last_line_number - screen_lines - 1 + 1) / (total_lines - screen_lines - 1); /* assure distance if not quite at beginning or end */ if (disp_start == 0) { disp_start = 1; } else if (disp_start >= max_start) { disp_start = max_start - 1; } } disp_end = disp_start + s - 1; #ifdef debug_scrollbar_calc printf ("last_line_number %d/%d, screen_lines %d (0-%d)\n", last_line_number, total_lines, screen_lines, last_y); printf (" size %d, maxstart %d, ~ * %d / %d, pos %d-%d/%d\n", s, max_start, last_line_number - screen_lines, total_lines - screen_lines, disp_start, disp_end, fields); #endif if (disp_scrollbar) { #ifdef debug_scrollbar if (update_scrollbar_lazy) { printf ("scrollbar (%d) %d - %d (prev. %d - %d)\n", force, disp_start, disp_end, prev_disp_start, prev_disp_end); } #endif /* last_y / SCREENMAX */ for (i = 0; i < fields; i ++) { if (i >= disp_start && i <= disp_end) { slices ++; klopsinslot = True; } else { klopsinslot = False; } if (i >= prev_disp_start && i <= prev_disp_end) { oldslices ++; oldklopsinslot = True; } else { oldklopsinslot = False; } if (((i + 1) % unit) == 0) { scri = i / unit; if (slices != oldslices || klopsinslot != oldklopsinslot || force || (scrollbar_dirty && scri >= first_dirty && scri <= last_dirty) ) { painted = True; set_cursor (XMAX, scri); if (slices == 0) { disp_scrollbar_background (); putchar (' '); disp_scrollbar_cellend (); } else if (slices == unit) { disp_scrollbar_foreground (); putchar (' '); disp_scrollbar_cellend (); #ifdef debug_scrollbar_calc if (klopsinslot == False) { printf ("@ %d (%d) ", scri, i / unit * unit); } printf ("%d", unit); #endif } else { /* choose among the eighths blocks */ /* U+2581..U+2587 ▁▂▃▄▅▆▇ */ if (klopsinslot) { /* display top segment part */ disp_scrollbar_background (); put_unichar (0x2580 + slices); disp_scrollbar_cellend (); #ifdef debug_scrollbar_calc if (! klopsinslot) { printf ("@ %d (%d) ", scri, i + 1 - slices); } printf ("%d", slices); #endif } else { /* display bottom segment */ disp_scrollbar_foreground (); put_unichar (0x2588 - slices); disp_scrollbar_cellend (); #ifdef debug_scrollbar_calc printf ("%d", slices); #endif } } #ifdef debug_lazy_scrollbar } else { painted = True; set_cursor (XMAX, scri); if (slices > 0) { disp_scrollbar_foreground (); } else { disp_scrollbar_background (); } putchar ('X'); disp_scrollbar_cellend (); #endif } slices = 0; oldslices = 0; } } disp_scrollbar_end (); #ifdef debug_scrollbar_calc printf ("\n"); #endif } printf_dirty ("scrollbar", force); prev_disp_start = disp_start; prev_disp_end = disp_end; scrollbar_dirty = False; first_dirty = SCREENMAX; last_dirty = -1; printf_dirty ("> scrollbar", force); return painted; } #ifdef use_cell_scrollbar static FLAG cell_grained_scrollbar (force) FLAG force; { /* last_y / YMAX */ int disp_start = ((long) line_number - y) * last_y / total_lines; int disp_end = ((long) line_number - y + last_y + 1) * last_y / total_lines; int i; FLAG painted = False; FLAG isin_newklops, isin_oldklops; if (disp_scrollbar) { #ifdef debug_scrollbar if (update_scrollbar_lazy) { printf ("scrollbar (%d) %d - %d (prev. %d - %d)\n", force, disp_start, disp_end, prev_disp_start, prev_disp_end); } #endif /* last_y / SCREENMAX */ for (i = 0; i <= last_y; i ++) { isin_newklops = i >= disp_start && i <= disp_end; isin_oldklops = i >= prev_disp_start && i <= prev_disp_end; if (isin_newklops != isin_oldklops || force) { painted = True; set_cursor (XMAX, i); if (isin_newklops) { #ifdef CJKterm_not_coloured if (cjk_term) { reverse_on (); putchar ('<'); reverse_off (); } else #endif { disp_scrollbar_foreground (); putchar (' '); disp_scrollbar_cellend (); } } else { disp_scrollbar_background (); putchar (' '); disp_scrollbar_cellend (); } #ifdef debug_lazy_scrollbar } else { painted = True; set_cursor (XMAX, i); if (isin_newklops) { disp_scrollbar_foreground (); } else { disp_scrollbar_background (); } putchar ('X'); disp_scrollbar_cellend (); #endif } } disp_scrollbar_end (); } prev_disp_start = disp_start; prev_disp_end = disp_end; scrollbar_dirty = False; first_dirty = SCREENMAX; last_dirty = -1; return painted; } FLAG display_scrollbar (update) FLAG update; { if (utf8_screen && fine_scrollbar) { return fine_grained_scrollbar (update == False); } else { return cell_grained_scrollbar (update == False); } } #else FLAG display_scrollbar (update) FLAG update; { return fine_grained_scrollbar (update == False); } #endif /*======================================================================*\ |* Marked character output *| \*======================================================================*/ static character char7bit (c) character c; { if (c >= 0xA0 && c < 0xC0) { /* " ¡¢£¤¥¦§\¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿" Latin-1 */ return " !cL%Y|S\"Ca<--R_0+23'mP.,10>///?" [c - 0xA0]; } else if (c == (character) '') { return 'x'; } else if (c == (character) '') { return ':'; } else if (c == (character) '') { return ';'; } else { return '%'; } } static void putnarrowchar (unichar) unsigned long unichar; { if (mapped_term || cjk_term) { unsigned long termchar = mappedtermchar (unichar); if (no_char (termchar)) { __putchar (char7bit (unichar)); } else if (termchar >= 0x100) { __putchar (char7bit (unichar)); } else { __putchar (termchar); } } else if (iswide (unichar)) { if (unichar == 0xB7) { /* · */ put_unichar ('.'); } else if (unichar == 0xA4) { /* ¤ */ putnarrowchar (0xB7); /* · */ } else if (unichar == 0x2028) { /* LINE SEPARATOR */ put_unichar (0xAB); /* « */ } else if (unichar == 0x2029) { /* PARAGRAPH SEPARATOR */ put_unichar ('P'); } else if (unichar == 0x00B6) { /* ¶ */ put_unichar ('P'); } else if (unichar == 0xBA) { /* º */ put_unichar ('0'); } else { putnarrowchar (0xA4); /* ¤ */ } } else { put_unichar (unichar); } } static void putnarrowutf (utfmarker) char * utfmarker; { unsigned long unichar; int utflen; utf8_info (utfmarker, & utflen, & unichar); if (iswide (unichar)) { putnarrowchar (unichar); } else { put_unichar (unichar); } } #define indicate_illegal_UTF indicate_marked #define indicate_UTF indicate_marked /** Indicate highlighted special character property (e.g. illegal code). */ static void indicate_marked (c) unsigned long c; { if (char_on_status_line) { reverse_off (); } unidisp_on (); putnarrowchar (c); unidisp_off (); if (char_on_status_line) { reverse_on (); } } /** Indicate coulored special character. */ static void indicate_special (c) character c; { if (char_on_status_line) { reverse_off (); } unimarkdisp_on (); putnarrowchar ((unsigned long) c); unimarkdisp_off (); if (char_on_status_line) { reverse_on (); } } /* * put mark character, possibly switching alternate character set * putmarkmode and endmarkmode are only called by putmark and for * display of TAB markers */ static FLAG dim_mode = False; static FLAG mark_alt_cset = False; static void putmarkmode (marker, utfmarker, dim_me) character marker; char * utfmarker; FLAG dim_me; { if (dim_me && ! dim_mode) { dim_on (); dim_mode = True; } if (utf8_screen) { if (utfmarker != NIL_PTR && * utfmarker != '\0') { putnarrowutf (utfmarker); } else { if (marker >= '`' && marker <= '') { if (! mark_alt_cset) { altcset_on (); mark_alt_cset = True; } putchar (marker); } else { putnarrowchar (marker); } } } else if (marker >= '`' && marker <= '') { if (! mark_alt_cset) { altcset_on (); mark_alt_cset = True; } putchar (marker); } else { if (mark_alt_cset) { altcset_off (); mark_alt_cset = False; } if (mapped_term) { unsigned long termchar = mappedtermchar (marker); if (no_char (termchar)) { __putchar (char7bit (marker)); } else { __putchar (termchar); } } else { putchar (marker); } } } static void endmarkmode () { if (dim_mode) { dim_off (); dim_mode = False; } if (mark_alt_cset) { altcset_off (); mark_alt_cset = False; } } /* Output a line status marker. */ void putmark (marker, utfmarker) char marker; char * utfmarker; { putmarkmode (marker, utfmarker, True); endmarkmode (); } static void putUmark (marker, utfmarker) character marker; char * utfmarker; { unimarkdisp_on (); putmarkmode (marker, utfmarker, False); endmarkmode (); unimarkdisp_off (); } void put_menu_marker () { /* unidisp_on (); If utf8_screen Then put_unichar (menu_marker); Else putchar ('*'); Fi unidisp_off (); */ unidisp_on (); putmarkmode (MENU_marker, UTF_MENU_marker, False); endmarkmode (); unidisp_off (); } static void putshiftmark (marker, utfmarker) character marker; char * utfmarker; { if (! dim_mode) { dim_on (); dim_mode = True; } reverse_on (); putmarkmode (marker, utfmarker, False); reverse_off (); endmarkmode (); } FLAG marker_defined (marker, utfmarker) character marker; char * utfmarker; { return marker || (utf8_screen && utfmarker && * utfmarker); } #define token_output static void putret (type) unsigned char type; { if (type == lineend_LF) { putmark (RET_marker, UTF_RET_marker); } else if (type == lineend_CRLF) { /* MSDOS line separator */ #ifdef token_output set_colour_token (4); /* blue */ #endif putmark (DOSRET_marker, UTF_DOSRET_marker); } else if (type == lineend_CR) { /* Mac line separator */ #ifdef token_output set_colour_token (3); /* yellow */ #endif putmark (MACRET_marker, UTF_MACRET_marker); } else if (type == lineend_NONE) { putmark ('', "¬"); } else if (type == lineend_NUL) { putmark ('', "º"); } else if (type == lineend_LS) { /* Unicode line separator U+2028: 
 */ putUmark (RET_marker, UTF_RET_marker); } else if (type == lineend_PS) { /* Unicode paragraph separator U+2029: 
 */ putUmark (PARA_marker, UTF_PARA_marker); } else { putmark ('', "¤"); } } static int put_cjktermchar _((unsigned long cjkchar)); static void putCJKtab () { unsigned long mark = mappedtermchar (CJK_TAB_marker); dim_on (); if (no_char (mark)) { put_cjkchar ('.'); put_cjkchar ('.'); } else { put_cjktermchar (mark); } dim_off (); } static void putCJKret (type) unsigned char type; { /* markers available in all CJK encodings: 300A 《 FF20 @ 03BC μ 00B0 ° 00A7 § */ unsigned long umark; unsigned long mark; if (type == lineend_LF) { umark = 0x300A; /* 《 */ } else if (type == lineend_CRLF) { /* MSDOS line separator */ umark = 0x03BC; /* μ */ } else if (type == lineend_CR) { /* Mac line separator */ umark = 0xFF20; /* @ */ } else if (type == lineend_NONE) { umark = '-'; } else if (type == lineend_NUL) { umark = 0x00B0; /* ° */ } else if (type == lineend_LS) { /* Unicode line separator U+2028 */ putUmark ('<', NIL_PTR); return; } else if (type == lineend_PS) { /* Unicode paragraph separator U+2029 */ putUmark (0x00A7, NIL_PTR); return; } else { umark = 0x300A; /* 《 */ } mark = mappedtermchar (umark); dim_on (); if (no_char (mark)) { put_cjkchar ('<'); put_cjkchar ('<'); } else { put_cjktermchar (mark); } dim_off (); } /*======================================================================*\ |* Character output *| \*======================================================================*/ static int utfcount = 0; static unsigned long unichar; static unsigned short prev_cjkchar = 0L; struct interval { unsigned long first; unsigned long last; }; /* struct interval list_Quotation_Mark [] = struct interval list_Dash [] = */ #include "charprop.t" static int lookup (ucs, table, length) unsigned long ucs; struct interval * table; int length; { int min = 0; int mid; int max = length - 1; if (ucs < table [0].first || ucs > table [max].last) { return 0; } while (max >= min) { mid = (min + max) / 2; if (ucs > table [mid].last) { min = mid + 1; } else if (ucs < table [mid].first) { max = mid - 1; } else { return 1; } } return 0; } #define dont_debug_put_cjk #ifdef debug_put_cjk #define trace_put_cjk(tag, c) printf ("put_cjkchar %04X %s\n", c, tag) #else #define trace_put_cjk(tag, c) #endif /** check if character is not a valid (assigned) Unicode terminal character (i.e. considering the auto-detected Unicode version of the terminal) */ static FLAG no_validunichar (u) unsigned long u; { return no_unichar (u) || ! term_isassigned (u); } /** put CJK character to screen; to be called only if cjk_term == True returns screen length */ static int put_cjkcharacter (term, cjkchar, width) FLAG term; unsigned long cjkchar; int width; { character cjkbytes [5]; character * cp; unsigned long unichar; char encoding_tag = term ? term_encoding_tag : text_encoding_tag; (void) cjkencode_char (term, cjkchar, cjkbytes); if (! valid_cjkchar (term, cjkchar, cjkbytes) && (suppress_invalid_cjk || ! cjk_term)) { trace_put_cjk ("! valid", cjkchar); /* character code does not follow encoding pattern */ indicate_marked ('#'); if (cjk_term && ! cjk_uni_term) { trace_put_cjk ("! valid 1", cjkchar); if (encoding_tag == 'J' && (cjkchar >> 8) == 0x8E) { return 1; } else { indicate_marked (' '); return 2; } } else if (utf_cjk_wide_padding && cjkchar >= 0x100) { trace_put_cjk ("! valid 2", cjkchar); indicate_marked (' '); return 2; } } else if (cjk_term) { trace_put_cjk ("cjk_term", cjkchar); if (width < 0) { if (cjkchar >= 0x100) { if (encoding_tag == 'J' && (cjkchar >> 8) == 0x8E) { width = 1; } else { width = 2; } } else { width = 1; } } unichar = lookup_encodedchar (cjkchar); if (unichar == 0xA0 /* nbsp */) { indicate_special (''); /* indicate nbsp */ return 1; } /* remap cjkchar to cjk_term */ if (! term && remap_chars ()) { trace_put_cjk ("... mapped unichar", unichar); if (no_unichar (unichar)) { indicate_marked ('?'); if (width == 2) { indicate_marked (' '); } return width; } cjkchar = mappedtermchar (unichar); trace_put_cjk ("... mapped c", cjkchar); if (no_char (cjkchar)) { if (iscombining_unichar (unichar)) { indicate_marked ('\''); } else { indicate_marked ('%'); /* UNI_marker ? */ } if (width == 2) { indicate_marked (' '); } return width; } (void) cjkencode_char (True, cjkchar, cjkbytes); term = True; } if (suppress_extended_cjk && ((encoding_tag == 'G' && cjkchar >= 0x80000000 && (term ? ! gb18030_term : term_encoding_tag != 'G')) || (encoding_tag == 'J' && cjkchar >= 0x8F0000 && (term ? ! euc3_term : term_encoding_tag != 'J')) || (encoding_tag == 'C' && cjkchar >= 0x8E000000 && (term ? ! euc4_term : term_encoding_tag != 'C')) || (cjklow_term == False && ((cjkchar >= 0x8000 && cjkchar < 0xA100 && (encoding_tag != 'J' || (cjkchar >> 8) != 0x8E) ) || ((cjkchar & 0xFF) >= 0x80 && (cjkchar & 0xFF) < 0xA0) ) ) )) { /* character code is in extended encoding range and is assumed not to be displayable by terminal */ trace_put_cjk ("... #", cjkchar); indicate_special ('#'); if (width == 2) { indicate_special (' '); } return width; } else if (suppress_unknown_cjk && no_validunichar (term ? lookup_mappedtermchar (cjkchar) : lookup_encodedchar (cjkchar)) ) { /* character code has no mapping to Unicode */ trace_put_cjk ("... ?", cjkchar); indicate_marked ('?'); if (width == 2) { indicate_marked (' '); } return width; } else { trace_put_cjk ("... ", cjkchar); cp = cjkbytes; while (* cp != '\0') { putchar (* cp ++); } return width; } } else { unichar = lookup_encodedchar (cjkchar); if (no_unichar (unichar)) { indicate_marked ('?'); if (utf_cjk_wide_padding && cjkchar >= 0x100) { indicate_marked (' '); return 2; } } else { put_unichar (unichar); if (iswide (unichar)) { return 2; } else if (utf_cjk_wide_padding && cjkchar >= 0x100) { /* simulate double screen width of CJK character even if corresponding Unicode character has only single width */ __putchar (' '); return 2; } } } return 1; } /** put CJK character (text encoding) to screen; to be called only if cjk_term == True returns screen length */ int put_cjkchar (cjkchar) unsigned long cjkchar; { return put_cjkcharacter (False, cjkchar, -1); } /** put CJK terminal character (terminal encoding) to screen; to be called only if cjk_term == True returns screen length */ static int put_cjktermchar (cjkchar) unsigned long cjkchar; { return put_cjkcharacter (True, cjkchar, -1); } /** put joined character for separate display to screen */ static void put_unjoined (unichar) unsigned long unichar; { /* prevent terminal ligature by substituting joining character with its ISOLATED FORM */ unsigned long subst = isolated_alef (unichar); if ((cjk_term || mapped_term) && no_char (mappedtermchar (subst))) { /* use TATWEEL instead; could use one of U+061F ؟ ARABIC QUESTION MARK U+066D ٭ ARABIC FIVE POINTED STAR U+0640 ـ ARABIC TATWEEL (or rather substitute the base char U+0644 ل ARABIC LETTER LAM) */ put_unichar (0x0640); } else { put_unichar (subst); } } static void put_uniend () { if (utf8_text && utfcount > 0) { /* previous character not terminated properly */ indicate_illegal_UTF ((character) ''); utfcount = 0; } } #define REPLACEMENT_CHARACTER 0xFFFD /* * put Unicode (UCS-4, actually) character to screen; * put as UTF-8 on UTF-8 terminal, or as Latin-1 otherwise 7 bits 0xxxxxxx 8..11 110xxxxx 10xxxxxx 12..16 1110xxxx 10xxxxxx 10xxxxxx 17..21 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 22..26 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 27..31 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ void put_unichar (unichar) unsigned long unichar; { if (unassigned_single_width) { if (rxvt_version > 0) { /* handle weird mapping of non-Unicode ranges */ if (unichar < 0x80000000) { unichar &= 0x1FFFFF; } } } if (mapped_text && no_unichar (unichar)) { indicate_marked ('?'); } else if (unichar < ' ') { indicate_UTF (unichar + '@'); } else if (unichar == 0x7F) { indicate_UTF ('?'); } else if (unichar >= 0x80 && unichar <= 0x9F) { if (unichar == 0x9F) { indicate_UTF ('?'); } else { indicate_UTF (unichar - 0x20); } } else if (unichar == 0xA0 /* nbsp */) { indicate_special (''); /* indicate nbsp in UTF-8 / mapped terminal */ } else if (suppress_EF && (unichar & 0xFFFE) == 0xFFFE) { indicate_illegal_UTF (REPLACEMENT_CHARACTER); if (iswide (unichar)) { indicate_illegal_UTF (' '); } } else if (suppress_non_Unicode && unichar >= 0x110000 && unichar < 0x80000000) { indicate_illegal_UTF (REPLACEMENT_CHARACTER); if (iswide (unichar)) { indicate_illegal_UTF (' '); } } else if (suppress_surrogates && unichar >= 0xD800 && unichar <= 0xDFFF) { indicate_illegal_UTF (REPLACEMENT_CHARACTER); if (iswide (unichar)) { indicate_illegal_UTF (' '); } } else if (utf8_screen) { if (unichar < 0x80) { __putchar (unichar); } else if (unichar < 0x800) { __putchar (0xC0 | (unichar >> 6)); __putchar (0x80 | (unichar & 0x3F)); } else if (unichar < 0x10000) { __putchar (0xE0 | (unichar >> 12)); __putchar (0x80 | ((unichar >> 6) & 0x3F)); __putchar (0x80 | (unichar & 0x3F)); } else if (unichar < 0x200000) { __putchar (0xF0 | (unichar >> 18)); __putchar (0x80 | ((unichar >> 12) & 0x3F)); __putchar (0x80 | ((unichar >> 6) & 0x3F)); __putchar (0x80 | (unichar & 0x3F)); } else if (unichar < 0x4000000) { __putchar (0xF8 | (unichar >> 24)); __putchar (0x80 | ((unichar >> 18) & 0x3F)); __putchar (0x80 | ((unichar >> 12) & 0x3F)); __putchar (0x80 | ((unichar >> 6) & 0x3F)); __putchar (0x80 | (unichar & 0x3F)); } else if (unichar < 0x80000000) { __putchar (0xFC | (unichar >> 30)); __putchar (0x80 | ((unichar >> 24) & 0x3F)); __putchar (0x80 | ((unichar >> 18) & 0x3F)); __putchar (0x80 | ((unichar >> 12) & 0x3F)); __putchar (0x80 | ((unichar >> 6) & 0x3F)); __putchar (0x80 | (unichar & 0x3F)); } else { /* special encoding of 2 Unicode chars, mapped from 1 CJK character */ put_unichar (unichar & 0xFFFF); unichar = (unichar >> 16) & 0x7FFF; if (combining_screen || ! iscombining (unichar)) { put_unichar (unichar); } else { /* if it's a combining char but the screen cannot handle it, just ignore it for now */ } } } else { unsigned long termchar; if (cjk_term) { termchar = mappedtermchar (unichar); if (! no_char (termchar)) { (void) put_cjkcharacter (True, termchar, 1 + iswide (unichar)); return; } } else if (mapped_term) { termchar = mappedtermchar (unichar); if (! no_char (termchar)) { __putchar (termchar); return; } } else if (unichar < 0x100) { __putchar (unichar); return; } /* character cannot be displayed on terminal; display indication or substitution */ if (iscombining_unichar (unichar)) { indicate_UTF ('\''); } else { if (unichar >= 0xFF01 && unichar <= 0xFF5E) { /* FULLWIDTH forms */ indicate_UTF (unichar - 0xFEE0); } else if (unichar == 0xFFE0) { /* FULLWIDTH CENT SIGN */ indicate_UTF ((character) 0xA2); } else if (unichar == 0xFFE1) { /* FULLWIDTH POUND SIGN */ indicate_UTF ((character) 0xA3); } else if (unichar == 0xFFE2) { /* FULLWIDTH NOT SIGN */ indicate_UTF ((character) 0xAC); } else if (unichar == 0xFFE3) { /* FULLWIDTH MACRON */ indicate_UTF ((character) 0xAF); } else if (unichar == 0xFFE4) { /* FULLWIDTH BROKEN BAR */ indicate_UTF ((character) 0xA6); } else if (unichar == 0xFFE5) { /* FULLWIDTH YEN SIGN */ indicate_UTF ((character) 0xA5); } else if (unichar == 0x20AC) { /* EURO SIGN */ indicate_UTF ('E'); } else if (unichar == 0x2713) { /* ✓ */ indicate_UTF ('V'); } else if (lookup (unichar, list_Quotation_Mark, arrlen (list_Quotation_Mark))) { if (unichar == 0xAB || unichar == 0x2039) { indicate_UTF ('<'); } else if (unichar == 0xBB || unichar == 0x203A) { indicate_UTF ('>'); } else { indicate_UTF ('"'); } } else if (lookup (unichar, list_Dash, arrlen (list_Dash))) { if (unichar == 0x301C || unichar == 0x3030) { indicate_UTF ('~'); } else { indicate_UTF ('-'); } } else if (unichar != (character) UNI_marker) { indicate_UTF ((character) UNI_marker); } else { indicate_UTF (char7bit (UNI_marker)); } } if (iswide (unichar)) { indicate_UTF (' '); } } } /* * put_char () puts a character byte to the screen (via buffer) * If UTF-8 text is being output through put_char () but the screen * is not in UTF-8 mode, put_char () transforms the byte sequences. * In CJK mode, this function should not be called anymore with * multibyte CJK codes (Shift-JIS single-byte is OK). */ static void put_char (c) character c; { if (utf8_text) { if (c < 0x80) { put_uniend (); __putchar (c); } else if ((c & 0xC0) == 0x80) { if (utfcount == 0) { indicate_illegal_UTF ('8'); return; } unichar = (unichar << 6) | (c & 0x3F); utfcount --; if (utfcount == 0) { /* final UTF-8 byte */ put_unichar (unichar); } else { /* character continues */ return; } } else { /* first UTF-8 byte */ if (utfcount > 0) { /* previous character not terminated properly */ indicate_illegal_UTF ((character) ''); utfcount = 0; } if ((c & 0xE0) == 0xC0) { utfcount = 2; unichar = c & 0x1F; } else if ((c & 0xF0) == 0xE0) { utfcount = 3; unichar = c & 0x0F; } else if ((c & 0xF8) == 0xF0) { utfcount = 4; unichar = c & 0x07; } else if ((c & 0xFC) == 0xF8) { utfcount = 5; unichar = c & 0x03; } else if ((c & 0xFE) == 0xFC) { utfcount = 6; unichar = c & 0x01; } else { /* illegal UTF-8 code 254 (0xFE) or 255 (0xFF) */ indicate_illegal_UTF ('4' + (c & 1)); return; } utfcount --; return; } } else if (cjk_text && cjk_term == False) { /* prev_cjkchar mechanism obsolete (would not suffice anymore...) */ if (prev_cjkchar != 0 || (c >= 0x80 && ! multichar (c))) { put_cjkchar ((prev_cjkchar << 8) | c); prev_cjkchar = 0; } else if (multichar (c)) { prev_cjkchar = c; } else { __putchar (c); } } else { if (unicode (c) == 0xA0 /* nbsp */) { indicate_special (''); /* indicate nbsp in Latin-1 terminal */ } else { __putchar (c); } } } /* * putcharacter (c) outputs a single-byte non-UTF character */ void putcharacter (c) character c; { if (mapped_text) { put_unichar (lookup_encodedchar (c)); } else if (utf8_screen && ! utf8_text) { put_unichar (c); } else if (mapped_term) { put_unichar (c); } else if (cjk_term && ! utf8_text && ! cjk_text) { /* remap non-ASCII Latin-1 char to cjk_term */ put_unichar (c); } else { put_char (c); } } /*======================================================================*\ |* Text display *| \*======================================================================*/ #define default_script -999 static char syntax_marker = syntax_none; static int script_colour = default_script; void put_blanks (endpos) int endpos; { int startpos = 0; while (startpos ++ <= endpos) { putchar (' '); } } static void clear_wholeline () { if (can_clear_eol) { clear_eol (); } else { put_blanks (XMAX); } } void clear_lastline () { if (can_clear_eol) { clear_eol (); } else { put_blanks (XMAX - 1); } } static void disp_syntax (syntax_marker_was, syntax_marker) char syntax_marker_was; char syntax_marker; { if (syntax_marker != syntax_marker_was) { if (syntax_marker & syntax_JSP) { dispHTML_jsp (); } else if (syntax_marker & syntax_comment) { dispHTML_comment (); } else if (syntax_marker & syntax_HTML) { dispHTML_code (); } else { dispHTML_off (); } } } static void disp_script (script_colour) int script_colour; { if (script_colour == default_script) { disp_normal (); } else { disp_colour (script_colour); } } static struct colour_mapping { char * scriptname; int colour; int colour0; } colour_table [] = { #include "colours.t" }; /** Determine display colour for character script. */ static void map_script_colour (scriptname, sc, sc0) char * scriptname; int * sc; int * sc0; { int min = 0; int max = sizeof (colour_table) / sizeof (struct colour_mapping) - 1; int mid; int cmp; /* binary search in table */ while (max >= min) { mid = (min + max) / 2; cmp = strcmp (colour_table [mid].scriptname, scriptname); if (cmp < 0) { min = mid + 1; } else if (cmp > 0) { max = mid - 1; } else { * sc = colour_table [mid].colour; * sc0 = colour_table [mid].colour0; return; } } * sc = default_script; * sc0 = -1; } static void restore_attr () { if (dim_HTML) { disp_syntax (0, syntax_marker); } if (script_colour > 0) { disp_script (script_colour); } } #define dont_debug_put_line #ifdef debug_put_line #define trace_put_line(params) printf params #else #define trace_put_line(params) #endif #define dont_debug_width /* * Put_line prints the given line on the standard output. * If offset is not zero, printing will start at that x-coordinate. * If the FLAG clear_line is True, then the screen line will be cleared * when the end of the line has been reached. line_print (ly, line) is put_line (ly, line, 0, True, False) */ void put_line (ly, line, offset, clear_line, positioning) int ly; /* current screen line */ LINE * line; /* line to print */ int offset; /* offset to start if positioning == False */ /* position if positioning == True */ FLAG clear_line; /* clear to eoln if True */ FLAG positioning; /* positioning inside line if True (for prop. fonts) */ { char * textp = line->text; char * parap; int count = line->shift_count * - SHIFT_SIZE; int count_ini = count; int offset_start; int offset_stop; int charwidth; FLAG separate_combining = True; /* at line beginning, after TAB */ FLAG save_combining_mode = combining_mode; char syntax_marker_was; char syntax_marker_new; char * password = NIL_PTR; if (hide_password) { password = strcontains (textp, "assword"); if (password) { password += 7; while (* password == ':' || white_space (* password)) { password ++; } } } syntax_marker = line->prev->syntax_marker; syntax_marker_was = syntax_none; syntax_marker_new = syntax_marker; script_colour = default_script; if (positioning) { offset_start = 0; offset_stop = offset; } else { offset_start = offset; offset_stop = XBREAK; } /* Skip all chars as indicated by the offset_start and the shift_count field */ while (count < offset_start) { syntax_marker_new = syntax_state (syntax_marker_new, textp); if (* textp == '<' || * textp == '>') { syntax_marker_was = syntax_marker; syntax_marker = syntax_marker_new; } advance_char_scr (& textp, & count, line->text); } if (standout_glitch) { clear_eol (); set_scrollbar_dirty (ly); disp_normal (); } if (count_ini < 0 && offset_start == 0) { /* displaying line shifted out left, starting on screen column 0 */ if (marker_defined (SHIFT_BEG_marker, UTF_SHIFT_BEG_marker)) { /* display the shift marker */ if (cjk_term) { putshiftmark ('<', NIL_PTR); } else { putshiftmark (SHIFT_BEG_marker, UTF_SHIFT_BEG_marker); } if (count == 0) { if (! is_tab (* textp)) { syntax_marker_new = syntax_state (syntax_marker_new, textp); if (* textp == '<' || * textp == '>') { syntax_marker_was = syntax_marker; syntax_marker = syntax_marker_new; } if (iswide (unicodevalue (textp))) { /* skipped character is double-width, indicate */ if (cjk_term) { putmark ('.', NIL_PTR); } else { putmark (shiftskipdouble, NIL_PTR); } count ++; } /* skip character replaced by shift marker */ advance_char (& textp); } count ++; } else { /* last character was double-width, already skipped */ } } else if (count > 0) { /* last character was double-width, already skipped */ if (cjk_term) { putmark ('.', NIL_PTR); } else { putmark (shiftskipdouble, NIL_PTR); } } } restore_attr (); if (offset_start > 0 && * (textp - 1) != '\t') { /* fix display of isolated combinings in case of partial line display */ separate_combining = False; } while (True) { unsigned long unichar; int follow; unsigned long cjkchar; if (separate_isolated_combinings) { if (separate_combining) { combining_mode = False; separate_combining = False; } else { combining_mode = save_combining_mode; } } if (* textp == '\n') { charwidth = 1; break; } if (utf8_text) { utf8_info (textp, & follow, & unichar); charwidth = uniscrwidth (unichar, textp, line->text); } else if (cjk_text) { cjkchar = charvalue (textp); unichar = lookup_encodedchar (cjkchar); charwidth = cjkscrwidth (cjkchar, textp, line->text); #ifdef debug_width printf ("cjk %04X u %04X w %d\n", cjkchar, unichar, charwidth); #endif } else if (mapped_text) { unichar = lookup_encodedchar ((character) * textp); charwidth = cjkscrwidth ((character) * textp, textp, line->text); } else /* Latin-1 */ { unichar = (character) * textp; if (cjk_term || cjk_width_data_version) { charwidth = uniscrwidth (unichar, textp, line->text); } else { charwidth = 1; } } if (unassigned_single_width) { if (rxvt_version > 0) { /* handle weird mapping of non-Unicode ranges */ if (unichar < 0x80000000) { unichar &= 0x1FFFFF; } } } if (count >= offset_stop + 1 - charwidth) { break; } if (dim_HTML) { syntax_marker_new = syntax_state (syntax_marker_new, textp); if (* textp == '<' || * textp == '>') { syntax_marker_was = syntax_marker; syntax_marker = syntax_marker_new; } if (* textp == '<') { disp_syntax (syntax_marker_was, syntax_marker); } } if (is_tab (* textp)) { /* Expand tabs to spaces */ int tab_count = tab (count); int tab_mid = count + (tab_count - count) / 2 + 1; if (separate_isolated_combinings) { separate_combining = True; } put_uniend (); if (cjk_term) { if ((count & 1) == 1) { count ++; if (cjk_tab_width == 1) { putCJKtab (); } else { __putchar (' '); } } while (count < offset_stop && count < tab_count) { putCJKtab (); count ++; if (cjk_tab_width == 2) { count ++; } } } else if (marker_defined (TAB0_marker, UTF_TAB0_marker)) { count ++; putmarkmode (TAB0_marker, UTF_TAB0_marker, True); while (count < offset_stop && count < tab_count - 1) { count ++; putmarkmode (TAB_marker, UTF_TAB_marker, True); } if (count < offset_stop && count < tab_count) { count ++; if (marker_defined (TAB2_marker, UTF_TAB2_marker )) { putmarkmode (TAB2_marker, UTF_TAB2_marker, True); } else { putmarkmode (TAB_marker, UTF_TAB_marker, True); } } } else while (count < offset_stop && count < tab_count) { count ++; if (count == tab_mid && marker_defined (TABmid_marker, UTF_TABmid_marker)) { putmarkmode (TABmid_marker, UTF_TABmid_marker, True); } else { putmarkmode (TAB_marker, UTF_TAB_marker, True); } } endmarkmode (); restore_attr (); textp ++; } else if (password && textp >= password && ! white_space (* textp)) { int len; put_uniend (); ctrldisp_on (); for (len = 0; len < charwidth; len ++) { putcharacter ('*'); } ctrldisp_off (); advance_char (& textp); if (white_space (* textp)) { /*password = NIL_PTR;*/ password = strcontains (textp, "assword"); if (password) { password += 7; while (* password == ':' || white_space (* password)) { password ++; } } } count += charwidth; } else if (unichar == 0xA0 /* nbsp */) { put_uniend (); indicate_special (''); restore_attr (); advance_char (& textp); count += charwidth; } else if (iscontrol (unichar)) { /* this covers only 1 byte controls; GB18030 "C1" controls are handled elsewhere */ put_uniend (); if (unichar >= 0x80) { if (unichar == 0x9F) { indicate_UTF ('?'); } else { indicate_UTF (unichar - 0x20); } } else { ctrldisp_on (); putcharacter (controlchar (unichar)); ctrldisp_off (); } restore_attr (); advance_char (& textp); count ++; } else { FLAG disp_separate_combining = False; FLAG disp_separate_joining = False; char syntax_byte_printed; syntax_byte_printed = * textp; if (utf8_text) { int last_script_colour; int script_colour0; follow --; last_script_colour = script_colour; map_script_colour (script (unichar), & script_colour, & script_colour0); if (script_colour != last_script_colour) { if (script_colour0 > 0) { disp_script (script_colour0); } if (colours_256 || script_colour0 <= 0) { disp_script (script_colour); } } if (iscombined (unichar, textp, line->text)) { if (combining_screen && ! combining_mode) { /* enforce separated display */ disp_separate_combining = True; combiningdisp_on (); if (iswide (unichar)) { put_unichar (0x3000); count += 2; } else { if (isjoined (unichar, textp, line->text)) { disp_separate_joining = True; #ifdef mlterm_fixed /* Separate display of Arabic ligature components; don't output base blank and try to suppress Arabic ligature shaping with one of 200B;ZERO WIDTH SPACE 200C;ZERO WIDTH NON-JOINER 200D;ZERO WIDTH JOINER FEFF;ZERO WIDTH NO-BREAK SPACE - none works in mlterm */ put_unichar (0x200C); #else /* Transform character to its isolated form; see below */ #endif } else { putcharacter (' '); } count += 1; } } else { if (! combining_screen) { disp_separate_combining = True; combiningdisp_on (); count += charwidth; } } } else { if (iscombining_unichar (unichar)) { disp_separate_combining = True; combiningdisp_on (); } count += charwidth; } #ifndef mlterm_fixed if (disp_separate_joining) { /* prevent terminal ligature by substituting joining character with its ISOLATED FORM */ put_unichar (isolated_alef (unichar)); /* skip rest of joining char */ textp ++; while (follow > 0 && (* textp & 0xC0) == 0x80) { textp ++; follow --; } } else #endif { put_char (* textp ++); while (follow > 0 && (* textp & 0xC0) == 0x80) { put_char (* textp ++); follow --; } } if (disp_separate_combining) { combiningdisp_off (); restore_attr (); } } else if (cjk_text) { if (multichar (* textp)) { int charlen; character cjkbytes [5]; int cjklen = CJK_len (textp); char * this_textp = textp; charlen = cjkencode (cjkchar, cjkbytes); trace_put_line (("%04X %d + %d ", cjkchar, count, charwidth)); while (cjklen > 0 && * textp != '\n' && * textp != '\0') { textp ++; cjklen --; charlen --; } if (cjklen != 0 || charlen != 0) { /* incomplete CJK char */ indicate_marked ('<'); count ++; if (utf_cjk_wide_padding) { if (charlen == 0 || charlen == -3) { indicate_marked (' '); count ++; } } } else { trace_put_line (("- put %04X ", cjkchar)); if (iscombined (unichar, this_textp, line->text)) { if (combining_screen && ! combining_mode) { /* enforce separated display */ disp_separate_combining = True; combiningdisp_on (); if (charwidth == 2) { put_unichar (0x3000); } else if (isjoined (unichar, this_textp, line->text)) { disp_separate_joining = True; } else { putcharacter (' '); } } else { if (! combining_screen) { disp_separate_combining = True; combiningdisp_on (); } } } else if (iscombining_unichar (unichar)) { disp_separate_combining = True; combiningdisp_on (); } if (disp_separate_joining) { put_unjoined (unichar); } else { put_cjkcharacter (False, cjkchar, charwidth); } if (disp_separate_combining) { combiningdisp_off (); restore_attr (); } count += charwidth; } trace_put_line (("-> %d\n", count)); } else { put_cjkchar ((character) * textp); textp ++; count += charwidth; } } else /* ! utf_text && ! cjk_text */ { if (mapped_text) { if (iscombined (unichar, textp, line->text)) { if (combining_screen && ! combining_mode) { /* enforce separated display */ disp_separate_combining = True; combiningdisp_on (); if (isjoined (unichar, textp, line->text)) { disp_separate_joining = True; } else { putcharacter (' '); } } else { if (! combining_screen) { disp_separate_combining = True; combiningdisp_on (); } } } } if (mapped_text && unichar == 0xA0 /* nbsp */) { indicate_special (''); } else { if (disp_separate_joining) { put_unjoined (unichar); } else { putcharacter ((character) * textp); } } if (disp_separate_combining) { combiningdisp_off (); restore_attr (); } textp ++; count += charwidth; } if (dim_HTML && syntax_byte_printed == '>') { disp_syntax (syntax_marker_was, syntax_marker); } } } if (separate_isolated_combinings) { combining_mode = save_combining_mode; } put_uniend (); if (script_colour != default_script) { disp_script (default_script); } if (dim_HTML) { /* now reset HTML display attribute */ disp_syntax (syntax_marker, 0); } if (positioning) { /* self-made cursor for terminals (such as xterm) which have display problems with proportional screen fonts and their cursor */ reverse_on (); if (* textp != '\n') { if (utf8_text) { put_unichar (charvalue (textp)); put_uniend (); } else if (cjk_text) { put_cjkchar (charvalue (textp)); } else { putcharacter (* textp); } } else if (cjk_term) { putCJKret (line->return_type); } else if (RET_marker != '\0') { if (PARA_marker != '\0' && paradisp && line->return_type != lineend_LS && line->return_type != lineend_PS) { parap = textp; parap --; if (* parap == ' ' || * parap == '\t') { putret (line->return_type); } else { putmark (PARA_marker, UTF_PARA_marker); } } else { putret (line->return_type); } } else { putchar (' '); } reverse_off (); set_cursor (0, 0); } else /* (positioning == False) */ { /* If line is longer than XBREAK chars, print the shift_mark */ if (count <= XBREAK && * textp != '\n') { if (count < XBREAK && charwidth == 2) { if (cjk_term) { putmark ('.', NIL_PTR); } else { putmark (shiftskipdouble, NIL_PTR); } count ++; } if (cjk_term) { putshiftmark ('>', NIL_PTR); count ++; } else { putshiftmark (SHIFT_marker, UTF_SHIFT_marker); count ++; } if (count == XBREAK) { putchar (' '); count ++; } } /* Mark end of line if so desired */ if (* textp == '\n') { if (cjk_term) { if (RET_marker >= ' ' && (character) RET_marker <= '@') { putmark (RET_marker, NIL_PTR); } else { putCJKret (line->return_type); /* to ensure it fits, scrollbar_width is set to 1 in CJK terminal mode even if scrollbar is switched off */ if (cjk_lineend_width == 2) { count ++; } } } else if (RET_marker != '\0') { if (PARA_marker != '\0' && paradisp && line->return_type != lineend_LS && line->return_type != lineend_PS) { parap = textp; parap --; if (* parap == ' ') { putret (line->return_type); } else { putmark (PARA_marker, UTF_PARA_marker); } } else { putret (line->return_type); if (standout_glitch && (line->return_type == lineend_LS || line->return_type == lineend_PS)) { putchar (' '); count ++; if (count > XBREAK) { set_scrollbar_dirty (ly); } } } count ++; if (marker_defined (RETfill_marker, UTF_RETfill_marker)) { while (count < XBREAK) { putmark (RETfill_marker, UTF_RETfill_marker); count ++; } if (count <= XBREAK) { if (marker_defined (RETfini_marker, UTF_RETfini_marker)) { putmark (RETfini_marker, UTF_RETfini_marker); count ++; } else { putmark (RETfill_marker, UTF_RETfill_marker); count ++; } } } } } #ifdef debug_width static FLAG mark_ret = UNSURE; if (mark_ret == UNSURE) { mark_ret = getenv ("mark_ret") != NIL_PTR; } if (mark_ret) { set_cursor (count + 1, ly); putchar ('*'); count ++; } #endif /* Clear the rest of the line if clear_line is True */ if (clear_line) { set_scrollbar_dirty (ly); if (can_clear_eol) { if (count <= XBREAK) { clear_eol (); } } else { while (count ++ <= XBREAK) { /* clear up to XMAX */ putchar (' '); } } } } } /* * set_cursor_xy sets the cursor by either directly calling set_cursor * or, in the case of proportional font support, reprinting the line * up to the x position */ void set_cursor_xy () { if (proportional) { set_cursor (0, y); if (x != 0) { put_line (y, cur_line, x, False, True); } /* cur_line may still be undefined if x == 0 */ } else { set_cursor (x, y); } } /* * Display line at screen line y_pos if it lies between y_min and y_max. * If it is no text line (end of file), clear screen line. */ static void display_line_at (y_pos, line, y_min, y_max, first) int y_pos; int y_min; int y_max; register LINE * line; FLAG first; { line = proceed (line, y_pos - y_min); if (y_pos >= y_min && y_pos <= y_max) { set_cursor (0, y_pos); if (line == tail) { clear_wholeline (); } else { if (first == False) { if (display_delay >= 0) { flush (); } #ifdef msdos if (display_delay > 0) { delay (display_delay); } #else #ifdef use_usleep if (display_delay > 0) { (void) usleep (1000 * display_delay); } #else if (display_delay > 0) { (void) char_ready_within (display_delay); } #endif #endif } line_print (y_pos, line); } } } /* * Display () shows count + 1 lines on the terminal starting at the given * coordinates. At end of file, the rest of the screen is blanked. * When count is negative, a backwards print from 'line' will be done. */ void display (y_coord, line, count, new_pos) int y_coord; register LINE * line; register int count; int new_pos; { int y_max = y_coord + count; int y_off; /* Find new startline if count is negative */ if (count < 0) { line = proceed (line, count); count = - count; } #ifdef obsolete clean_menus (); This led to recursive calls of display () resulting in wrong display; menus are now cleared before invoking functions from menu. #endif #define boring_old_top_down_display #ifdef old_top_down_display /* old code, building the display from top to bottom (how boring): */ /* with this code, XBREAK must be set to XMAX - 1 */ /* Print the lines */ while (line != tail && count -- >= 0) { set_cursor (0, y_coord); line_print (y_coord, line); line = line->next; y_coord ++; } /* Print the blank lines (if any) */ if (loading == False) { while (count -- >= 0) { clear_eol (); putchar ('\n'); } } #else display_line_at (new_pos, line, y_coord, y_max, True); y_off = 0; while (y_off <= count) { y_off ++; if (winchg) { return; } display_line_at (new_pos - y_off, line, y_coord, y_max, False); if (winchg) { return; } display_line_at (new_pos + y_off, line, y_coord, y_max, False); } #endif } /*======================================================================*\ |* End *| \*======================================================================*/