output.c revision 161475
1214501Srpaulo/* 2214501Srpaulo * Copyright (C) 1984-2005 Mark Nudelman 3214501Srpaulo * 4214501Srpaulo * You may distribute under the terms of either the GNU General Public 5252726Srpaulo * License or the Less License, as specified in the README file. 6252726Srpaulo * 7214501Srpaulo * For more information about less, or for information on how to 8214501Srpaulo * contact the author, see the README file. 9214501Srpaulo */ 10214501Srpaulo 11214501Srpaulo 12214501Srpaulo/* 13252726Srpaulo * High level routines dealing with the output to the screen. 14214501Srpaulo */ 15214501Srpaulo 16214501Srpaulo#include "less.h" 17214501Srpaulo#if MSDOS_COMPILER==WIN32C 18214501Srpaulo#include "windows.h" 19214501Srpaulo#endif 20214501Srpaulo 21214501Srpaulopublic int errmsgs; /* Count of messages displayed by error() */ 22214501Srpaulopublic int need_clr; 23214501Srpaulopublic int final_attr; 24214501Srpaulo 25214501Srpauloextern int sigs; 26214501Srpauloextern int sc_width; 27214501Srpauloextern int so_s_width, so_e_width; 28214501Srpauloextern int screen_trashed; 29214501Srpauloextern int any_display; 30214501Srpauloextern int is_tty; 31214501Srpaulo 32214501Srpaulo#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 33214501Srpauloextern int ctldisp; 34214501Srpauloextern int nm_fg_color, nm_bg_color; 35214501Srpauloextern int bo_fg_color, bo_bg_color; 36214501Srpauloextern int ul_fg_color, ul_bg_color; 37214501Srpauloextern int so_fg_color, so_bg_color; 38214501Srpauloextern int bl_fg_color, bl_bg_color; 39214501Srpaulo#endif 40214501Srpaulo 41214501Srpaulo/* 42214501Srpaulo * Display the line which is in the line buffer. 43214501Srpaulo */ 44214501Srpaulo public void 45214501Srpauloput_line() 46214501Srpaulo{ 47214501Srpaulo register int c; 48214501Srpaulo register int i; 49214501Srpaulo int a; 50214501Srpaulo 51214501Srpaulo if (ABORT_SIGS()) 52214501Srpaulo { 53214501Srpaulo /* 54214501Srpaulo * Don't output if a signal is pending. 55214501Srpaulo */ 56214501Srpaulo screen_trashed = 1; 57214501Srpaulo return; 58214501Srpaulo } 59214501Srpaulo 60214501Srpaulo final_attr = AT_NORMAL; 61214501Srpaulo 62214501Srpaulo for (i = 0; (c = gline(i, &a)) != '\0'; i++) 63214501Srpaulo { 64214501Srpaulo at_switch(a); 65214501Srpaulo final_attr = a; 66214501Srpaulo if (c == '\b') 67214501Srpaulo putbs(); 68214501Srpaulo else 69214501Srpaulo putchr(c); 70214501Srpaulo } 71214501Srpaulo 72214501Srpaulo at_exit(); 73214501Srpaulo} 74214501Srpaulo 75214501Srpaulostatic char obuf[OUTBUF_SIZE]; 76214501Srpaulostatic char *ob = obuf; 77214501Srpaulo 78214501Srpaulo/* 79214501Srpaulo * Flush buffered output. 80214501Srpaulo * 81214501Srpaulo * If we haven't displayed any file data yet, 82214501Srpaulo * output messages on error output (file descriptor 2), 83214501Srpaulo * otherwise output on standard output (file descriptor 1). 84214501Srpaulo * 85214501Srpaulo * This has the desirable effect of producing all 86214501Srpaulo * error messages on error output if standard output 87214501Srpaulo * is directed to a file. It also does the same if 88214501Srpaulo * we never produce any real output; for example, if 89214501Srpaulo * the input file(s) cannot be opened. If we do 90214501Srpaulo * eventually produce output, code in edit() makes 91214501Srpaulo * sure these messages can be seen before they are 92214501Srpaulo * overwritten or scrolled away. 93214501Srpaulo */ 94214501Srpaulo public void 95214501Srpauloflush() 96214501Srpaulo{ 97214501Srpaulo register int n; 98214501Srpaulo register int fd; 99214501Srpaulo 100214501Srpaulo n = ob - obuf; 101214501Srpaulo if (n == 0) 102214501Srpaulo return; 103214501Srpaulo#if MSDOS_COMPILER==WIN32C 104214501Srpaulo if (is_tty && any_display) 105214501Srpaulo { 106214501Srpaulo char *op; 107252726Srpaulo DWORD nwritten = 0; 108214501Srpaulo CONSOLE_SCREEN_BUFFER_INFO scr; 109214501Srpaulo int row; 110214501Srpaulo int col; 111214501Srpaulo int olen; 112214501Srpaulo extern HANDLE con_out; 113214501Srpaulo 114214501Srpaulo olen = ob - obuf; 115214501Srpaulo /* 116214501Srpaulo * There is a bug in Win32 WriteConsole() if we're 117214501Srpaulo * writing in the last cell with a different color. 118214501Srpaulo * To avoid color problems in the bottom line, 119214501Srpaulo * we scroll the screen manually, before writing. 120214501Srpaulo */ 121214501Srpaulo GetConsoleScreenBufferInfo(con_out, &scr); 122214501Srpaulo col = scr.dwCursorPosition.X; 123214501Srpaulo row = scr.dwCursorPosition.Y; 124214501Srpaulo for (op = obuf; op < obuf + olen; op++) 125214501Srpaulo { 126214501Srpaulo if (*op == '\n') 127214501Srpaulo { 128214501Srpaulo col = 0; 129214501Srpaulo row++; 130214501Srpaulo } else if (*op == '\r') 131214501Srpaulo { 132214501Srpaulo col = 0; 133214501Srpaulo } else 134214501Srpaulo { 135214501Srpaulo col++; 136214501Srpaulo if (col >= sc_width) 137214501Srpaulo { 138214501Srpaulo col = 0; 139214501Srpaulo row++; 140214501Srpaulo } 141214501Srpaulo } 142214501Srpaulo } 143214501Srpaulo if (row > scr.srWindow.Bottom) 144214501Srpaulo win32_scroll_up(row - scr.srWindow.Bottom); 145214501Srpaulo WriteConsole(con_out, obuf, olen, &nwritten, NULL); 146214501Srpaulo ob = obuf; 147214501Srpaulo return; 148214501Srpaulo } 149214501Srpaulo#else 150214501Srpaulo#if MSDOS_COMPILER==MSOFTC 151214501Srpaulo if (is_tty && any_display) 152214501Srpaulo { 153214501Srpaulo *ob = '\0'; 154214501Srpaulo _outtext(obuf); 155214501Srpaulo ob = obuf; 156214501Srpaulo return; 157214501Srpaulo } 158214501Srpaulo#else 159214501Srpaulo#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 160214501Srpaulo if (is_tty && any_display) 161214501Srpaulo { 162214501Srpaulo *ob = '\0'; 163214501Srpaulo if (ctldisp != OPT_ONPLUS) 164214501Srpaulo cputs(obuf); 165214501Srpaulo else 166214501Srpaulo { 167214501Srpaulo /* 168214501Srpaulo * Look for SGR escape sequences, and convert them 169214501Srpaulo * to color commands. Replace bold, underline, 170214501Srpaulo * and italic escapes into colors specified via 171214501Srpaulo * the -D command-line option. 172214501Srpaulo */ 173214501Srpaulo char *anchor, *p, *p_next; 174214501Srpaulo int buflen = ob - obuf; 175214501Srpaulo unsigned char fg, bg, norm_attr; 176214501Srpaulo /* 177214501Srpaulo * Only dark colors mentioned here, so that 178214501Srpaulo * bold has visible effect. 179214501Srpaulo */ 180214501Srpaulo static enum COLORS screen_color[] = { 181214501Srpaulo BLACK, RED, GREEN, BROWN, 182214501Srpaulo BLUE, MAGENTA, CYAN, LIGHTGRAY 183214501Srpaulo }; 184214501Srpaulo 185214501Srpaulo /* Normal text colors are used as baseline. */ 186214501Srpaulo bg = nm_bg_color & 0xf; 187214501Srpaulo fg = nm_fg_color & 0xf; 188214501Srpaulo norm_attr = (bg << 4) | fg; 189214501Srpaulo for (anchor = p_next = obuf; 190214501Srpaulo (p_next = memchr (p_next, ESC, 191214501Srpaulo buflen - (p_next - obuf))) 192214501Srpaulo != NULL; ) 193214501Srpaulo { 194214501Srpaulo p = p_next; 195214501Srpaulo 196214501Srpaulo /* 197214501Srpaulo * Handle the null escape sequence 198214501Srpaulo * (ESC-[m), which is used to restore 199214501Srpaulo * the original color. 200214501Srpaulo */ 201214501Srpaulo if (p[1] == '[' && is_ansi_end(p[2])) 202214501Srpaulo { 203214501Srpaulo textattr(norm_attr); 204214501Srpaulo p += 3; 205214501Srpaulo anchor = p_next = p; 206214501Srpaulo continue; 207214501Srpaulo } 208214501Srpaulo 209214501Srpaulo if (p[1] == '[') /* "Esc-[" sequence */ 210214501Srpaulo { 211214501Srpaulo /* 212214501Srpaulo * If some chars seen since 213214501Srpaulo * the last escape sequence, 214214501Srpaulo * write it out to the screen 215214501Srpaulo * using current text attributes. 216214501Srpaulo */ 217214501Srpaulo if (p > anchor) 218214501Srpaulo { 219214501Srpaulo *p = '\0'; 220214501Srpaulo cputs (anchor); 221214501Srpaulo *p = ESC; 222214501Srpaulo anchor = p; 223214501Srpaulo } 224214501Srpaulo p += 2; 225214501Srpaulo p_next = p; 226214501Srpaulo while (!is_ansi_end(*p)) 227214501Srpaulo { 228214501Srpaulo char *q; 229214501Srpaulo long code = strtol(p, &q, 10); 230214501Srpaulo 231214501Srpaulo if (!*q) 232214501Srpaulo { 233214501Srpaulo /* 234214501Srpaulo * Incomplete sequence. 235214501Srpaulo * Leave it unprocessed 236214501Srpaulo * in the buffer. 237214501Srpaulo */ 238214501Srpaulo int slop = q - anchor; 239214501Srpaulo strcpy(obuf, anchor); 240214501Srpaulo ob = &obuf[slop]; 241214501Srpaulo return; 242214501Srpaulo } 243214501Srpaulo 244214501Srpaulo if (q == p 245214501Srpaulo || code > 49 || code < 0 246214501Srpaulo || (!is_ansi_end(*q) 247214501Srpaulo && *q != ';')) 248214501Srpaulo { 249214501Srpaulo p_next = q; 250214501Srpaulo break; 251214501Srpaulo } 252214501Srpaulo if (*q == ';') 253214501Srpaulo q++; 254214501Srpaulo 255214501Srpaulo switch (code) 256214501Srpaulo { 257214501Srpaulo case 1: /* bold on */ 258214501Srpaulo fg = bo_fg_color; 259214501Srpaulo bg = bo_bg_color; 260214501Srpaulo break; 261214501Srpaulo case 3: /* italic on */ 262214501Srpaulo fg = so_fg_color; 263214501Srpaulo bg = so_bg_color; 264214501Srpaulo break; 265214501Srpaulo case 4: /* underline on */ 266214501Srpaulo fg = ul_fg_color; 267214501Srpaulo bg = ul_bg_color; 268214501Srpaulo break; 269214501Srpaulo case 8: /* concealed on */ 270214501Srpaulo fg = (bg & 7) | 8; 271214501Srpaulo break; 272214501Srpaulo case 0: /* all attrs off */ 273214501Srpaulo case 22:/* bold off */ 274214501Srpaulo case 23:/* italic off */ 275214501Srpaulo case 24:/* underline off */ 276214501Srpaulo fg = nm_fg_color; 277214501Srpaulo bg = nm_bg_color; 278214501Srpaulo break; 279214501Srpaulo case 30: case 31: case 32: 280214501Srpaulo case 33: case 34: case 35: 281214501Srpaulo case 36: case 37: 282214501Srpaulo fg = (fg & 8) | (screen_color[code - 30]); 283214501Srpaulo break; 284214501Srpaulo case 39: /* default fg */ 285214501Srpaulo fg = nm_fg_color; 286214501Srpaulo break; 287214501Srpaulo case 40: case 41: case 42: 288214501Srpaulo case 43: case 44: case 45: 289214501Srpaulo case 46: case 47: 290214501Srpaulo bg = (bg & 8) | (screen_color[code - 40]); 291214501Srpaulo break; 292214501Srpaulo case 49: /* default fg */ 293214501Srpaulo bg = nm_bg_color; 294214501Srpaulo break; 295214501Srpaulo } 296214501Srpaulo p = q; 297214501Srpaulo } 298214501Srpaulo if (is_ansi_end(*p) && p > p_next) 299214501Srpaulo { 300214501Srpaulo bg &= 15; 301214501Srpaulo fg &= 15; 302214501Srpaulo textattr ((bg << 4)| fg); 303214501Srpaulo p_next = anchor = p + 1; 304214501Srpaulo } else 305214501Srpaulo break; 306214501Srpaulo } else 307214501Srpaulo p_next++; 308214501Srpaulo } 309214501Srpaulo 310214501Srpaulo /* Output what's left in the buffer. */ 311214501Srpaulo cputs (anchor); 312214501Srpaulo } 313214501Srpaulo ob = obuf; 314214501Srpaulo return; 315214501Srpaulo } 316214501Srpaulo#endif 317214501Srpaulo#endif 318214501Srpaulo#endif 319214501Srpaulo fd = (any_display) ? 1 : 2; 320214501Srpaulo if (write(fd, obuf, n) != n) 321214501Srpaulo screen_trashed = 1; 322214501Srpaulo ob = obuf; 323214501Srpaulo} 324214501Srpaulo 325214501Srpaulo/* 326214501Srpaulo * Output a character. 327214501Srpaulo */ 328214501Srpaulo public int 329214501Srpauloputchr(c) 330214501Srpaulo int c; 331214501Srpaulo{ 332214501Srpaulo#if 0 /* fake UTF-8 output for testing */ 333214501Srpaulo extern int utf_mode; 334214501Srpaulo if (utf_mode) 335214501Srpaulo { 336214501Srpaulo static char ubuf[MAX_UTF_CHAR_LEN]; 337214501Srpaulo static int ubuf_len = 0; 338214501Srpaulo static int ubuf_index = 0; 339214501Srpaulo if (ubuf_len == 0) 340214501Srpaulo { 341214501Srpaulo ubuf_len = utf_len(c); 342214501Srpaulo ubuf_index = 0; 343214501Srpaulo } 344214501Srpaulo ubuf[ubuf_index++] = c; 345214501Srpaulo if (ubuf_index < ubuf_len) 346214501Srpaulo return c; 347214501Srpaulo c = get_wchar(ubuf) & 0xFF; 348214501Srpaulo ubuf_len = 0; 349214501Srpaulo } 350214501Srpaulo#endif 351214501Srpaulo if (need_clr) 352214501Srpaulo { 353214501Srpaulo need_clr = 0; 354214501Srpaulo clear_bot(); 355214501Srpaulo } 356214501Srpaulo#if MSDOS_COMPILER 357214501Srpaulo if (c == '\n' && is_tty) 358214501Srpaulo { 359214501Srpaulo /* remove_top(1); */ 360214501Srpaulo putchr('\r'); 361214501Srpaulo } 362214501Srpaulo#else 363214501Srpaulo#ifdef _OSK 364214501Srpaulo if (c == '\n' && is_tty) /* In OS-9, '\n' == 0x0D */ 365214501Srpaulo putchr(0x0A); 366214501Srpaulo#endif 367214501Srpaulo#endif 368214501Srpaulo /* 369214501Srpaulo * Some versions of flush() write to *ob, so we must flush 370214501Srpaulo * when we are still one char from the end of obuf. 371214501Srpaulo */ 372214501Srpaulo if (ob >= &obuf[sizeof(obuf)-1]) 373214501Srpaulo flush(); 374214501Srpaulo *ob++ = c; 375214501Srpaulo return (c); 376214501Srpaulo} 377214501Srpaulo 378214501Srpaulo/* 379214501Srpaulo * Output a string. 380214501Srpaulo */ 381214501Srpaulo public void 382214501Srpauloputstr(s) 383214501Srpaulo register char *s; 384214501Srpaulo{ 385214501Srpaulo while (*s != '\0') 386214501Srpaulo putchr(*s++); 387214501Srpaulo} 388214501Srpaulo 389214501Srpaulo 390214501Srpaulo/* 391214501Srpaulo * Convert an integral type to a string. 392214501Srpaulo */ 393214501Srpaulo#define TYPE_TO_A_FUNC(funcname, type) \ 394214501Srpaulovoid funcname(num, buf) \ 395214501Srpaulo type num; \ 396214501Srpaulo char *buf; \ 397214501Srpaulo{ \ 398214501Srpaulo int neg = (num < 0); \ 399214501Srpaulo char tbuf[INT_STRLEN_BOUND(num)+2]; \ 400214501Srpaulo register char *s = tbuf + sizeof(tbuf); \ 401214501Srpaulo if (neg) num = -num; \ 402252726Srpaulo *--s = '\0'; \ 403252726Srpaulo do { \ 404252726Srpaulo *--s = (num % 10) + '0'; \ 405252726Srpaulo } while ((num /= 10) != 0); \ 406252726Srpaulo if (neg) *--s = '-'; \ 407252726Srpaulo strcpy(buf, s); \ 408214501Srpaulo} 409214501Srpaulo 410214501SrpauloTYPE_TO_A_FUNC(postoa, POSITION) 411214501SrpauloTYPE_TO_A_FUNC(linenumtoa, LINENUM) 412214501SrpauloTYPE_TO_A_FUNC(inttoa, int) 413214501Srpaulo 414214501Srpaulo/* 415214501Srpaulo * Output an integer in a given radix. 416214501Srpaulo */ 417214501Srpaulo static int 418214501Srpauloiprint_int(num) 419214501Srpaulo int num; 420214501Srpaulo{ 421214501Srpaulo char buf[INT_STRLEN_BOUND(num)]; 422214501Srpaulo 423214501Srpaulo inttoa(num, buf); 424214501Srpaulo putstr(buf); 425214501Srpaulo return (strlen(buf)); 426214501Srpaulo} 427214501Srpaulo 428214501Srpaulo/* 429214501Srpaulo * Output a line number in a given radix. 430214501Srpaulo */ 431214501Srpaulo static int 432214501Srpauloiprint_linenum(num) 433214501Srpaulo LINENUM num; 434214501Srpaulo{ 435214501Srpaulo char buf[INT_STRLEN_BOUND(num)]; 436214501Srpaulo 437214501Srpaulo linenumtoa(num, buf); 438214501Srpaulo putstr(buf); 439214501Srpaulo return (strlen(buf)); 440214501Srpaulo} 441214501Srpaulo 442214501Srpaulo/* 443214501Srpaulo * This function implements printf-like functionality 444214501Srpaulo * using a more portable argument list mechanism than printf's. 445214501Srpaulo */ 446214501Srpaulo static int 447214501Srpauloless_printf(fmt, parg) 448214501Srpaulo register char *fmt; 449214501Srpaulo PARG *parg; 450214501Srpaulo{ 451214501Srpaulo register char *s; 452214501Srpaulo register int col; 453214501Srpaulo 454214501Srpaulo col = 0; 455214501Srpaulo while (*fmt != '\0') 456214501Srpaulo { 457214501Srpaulo if (*fmt != '%') 458214501Srpaulo { 459214501Srpaulo putchr(*fmt++); 460214501Srpaulo col++; 461214501Srpaulo } else 462214501Srpaulo { 463214501Srpaulo ++fmt; 464214501Srpaulo switch (*fmt++) 465214501Srpaulo { 466214501Srpaulo case 's': 467214501Srpaulo s = parg->p_string; 468214501Srpaulo parg++; 469214501Srpaulo while (*s != '\0') 470214501Srpaulo { 471214501Srpaulo putchr(*s++); 472214501Srpaulo col++; 473214501Srpaulo } 474214501Srpaulo break; 475214501Srpaulo case 'd': 476214501Srpaulo col += iprint_int(parg->p_int); 477214501Srpaulo parg++; 478214501Srpaulo break; 479214501Srpaulo case 'n': 480214501Srpaulo col += iprint_linenum(parg->p_linenum); 481214501Srpaulo parg++; 482214501Srpaulo break; 483214501Srpaulo } 484214501Srpaulo } 485214501Srpaulo } 486214501Srpaulo return (col); 487214501Srpaulo} 488214501Srpaulo 489214501Srpaulo/* 490214501Srpaulo * Get a RETURN. 491214501Srpaulo * If some other non-trivial char is pressed, unget it, so it will 492214501Srpaulo * become the next command. 493214501Srpaulo */ 494214501Srpaulo public void 495214501Srpauloget_return() 496214501Srpaulo{ 497214501Srpaulo int c; 498214501Srpaulo 499214501Srpaulo#if ONLY_RETURN 500214501Srpaulo while ((c = getchr()) != '\n' && c != '\r') 501214501Srpaulo bell(); 502214501Srpaulo#else 503214501Srpaulo c = getchr(); 504214501Srpaulo if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR) 505214501Srpaulo ungetcc(c); 506214501Srpaulo#endif 507214501Srpaulo} 508214501Srpaulo 509214501Srpaulo/* 510214501Srpaulo * Output a message in the lower left corner of the screen 511214501Srpaulo * and wait for carriage return. 512214501Srpaulo */ 513214501Srpaulo public void 514214501Srpauloerror(fmt, parg) 515214501Srpaulo char *fmt; 516214501Srpaulo PARG *parg; 517214501Srpaulo{ 518214501Srpaulo int col = 0; 519214501Srpaulo static char return_to_continue[] = " (press RETURN)"; 520214501Srpaulo 521214501Srpaulo errmsgs++; 522214501Srpaulo 523214501Srpaulo if (any_display && is_tty) 524214501Srpaulo { 525214501Srpaulo at_exit(); 526214501Srpaulo clear_bot(); 527214501Srpaulo at_enter(AT_STANDOUT); 528214501Srpaulo col += so_s_width; 529214501Srpaulo } 530214501Srpaulo 531214501Srpaulo col += less_printf(fmt, parg); 532214501Srpaulo 533214501Srpaulo if (!(any_display && is_tty)) 534214501Srpaulo { 535214501Srpaulo putchr('\n'); 536214501Srpaulo return; 537214501Srpaulo } 538214501Srpaulo 539214501Srpaulo putstr(return_to_continue); 540214501Srpaulo at_exit(); 541214501Srpaulo col += sizeof(return_to_continue) + so_e_width; 542214501Srpaulo 543214501Srpaulo get_return(); 544214501Srpaulo lower_left(); 545214501Srpaulo 546214501Srpaulo if (col >= sc_width) 547214501Srpaulo /* 548214501Srpaulo * Printing the message has probably scrolled the screen. 549214501Srpaulo * {{ Unless the terminal doesn't have auto margins, 550214501Srpaulo * in which case we just hammered on the right margin. }} 551214501Srpaulo */ 552214501Srpaulo screen_trashed = 1; 553214501Srpaulo 554214501Srpaulo flush(); 555214501Srpaulo} 556214501Srpaulo 557214501Srpaulostatic char intr_to_abort[] = "... (interrupt to abort)"; 558214501Srpaulo 559214501Srpaulo/* 560214501Srpaulo * Output a message in the lower left corner of the screen 561214501Srpaulo * and don't wait for carriage return. 562214501Srpaulo * Usually used to warn that we are beginning a potentially 563214501Srpaulo * time-consuming operation. 564214501Srpaulo */ 565214501Srpaulo public void 566214501Srpauloierror(fmt, parg) 567214501Srpaulo char *fmt; 568214501Srpaulo PARG *parg; 569214501Srpaulo{ 570214501Srpaulo at_exit(); 571214501Srpaulo clear_bot(); 572214501Srpaulo at_enter(AT_STANDOUT); 573 (void) less_printf(fmt, parg); 574 putstr(intr_to_abort); 575 at_exit(); 576 flush(); 577 need_clr = 1; 578} 579 580/* 581 * Output a message in the lower left corner of the screen 582 * and return a single-character response. 583 */ 584 public int 585query(fmt, parg) 586 char *fmt; 587 PARG *parg; 588{ 589 register int c; 590 int col = 0; 591 592 if (any_display && is_tty) 593 clear_bot(); 594 595 (void) less_printf(fmt, parg); 596 c = getchr(); 597 598 if (!(any_display && is_tty)) 599 { 600 putchr('\n'); 601 return (c); 602 } 603 604 lower_left(); 605 if (col >= sc_width) 606 screen_trashed = 1; 607 flush(); 608 609 return (c); 610} 611