2 * Copyright (C) 1984-2005 Mark Nudelman
4 * You may distribute under the terms of either the GNU General Public
5 * License or the Less License, as specified in the README file.
7 * For more information about less, or for information on how to
8 * contact the author, see the README file.
13 * High level routines dealing with the output to the screen.
17 #if MSDOS_COMPILER==WIN32C
21 public int errmsgs; /* Count of messages displayed by error() */
23 public int final_attr;
27 extern int so_s_width, so_e_width;
28 extern int screen_trashed;
29 extern int any_display;
32 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
34 extern int nm_fg_color, nm_bg_color;
35 extern int bo_fg_color, bo_bg_color;
36 extern int ul_fg_color, ul_bg_color;
37 extern int so_fg_color, so_bg_color;
38 extern int bl_fg_color, bl_bg_color;
42 * Display the line which is in the line buffer.
54 * Don't output if a signal is pending.
60 final_attr = AT_NORMAL;
62 for (i = 0; (c = gline(i, &a)) != '\0'; i++)
75 static char obuf[OUTBUF_SIZE];
76 static char *ob = obuf;
79 * Flush buffered output.
81 * If we haven't displayed any file data yet,
82 * output messages on error output (file descriptor 2),
83 * otherwise output on standard output (file descriptor 1).
85 * This has the desirable effect of producing all
86 * error messages on error output if standard output
87 * is directed to a file. It also does the same if
88 * we never produce any real output; for example, if
89 * the input file(s) cannot be opened. If we do
90 * eventually produce output, code in edit() makes
91 * sure these messages can be seen before they are
92 * overwritten or scrolled away.
103 #if MSDOS_COMPILER==WIN32C
104 if (is_tty && any_display)
108 CONSOLE_SCREEN_BUFFER_INFO scr;
112 extern HANDLE con_out;
116 * There is a bug in Win32 WriteConsole() if we're
117 * writing in the last cell with a different color.
118 * To avoid color problems in the bottom line,
119 * we scroll the screen manually, before writing.
121 GetConsoleScreenBufferInfo(con_out, &scr);
122 col = scr.dwCursorPosition.X;
123 row = scr.dwCursorPosition.Y;
124 for (op = obuf; op < obuf + olen; op++)
130 } else if (*op == '\r')
143 if (row > scr.srWindow.Bottom)
144 win32_scroll_up(row - scr.srWindow.Bottom);
145 WriteConsole(con_out, obuf, olen, &nwritten, NULL);
150 #if MSDOS_COMPILER==MSOFTC
151 if (is_tty && any_display)
159 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
160 if (is_tty && any_display)
163 if (ctldisp != OPT_ONPLUS)
168 * Look for SGR escape sequences, and convert them
169 * to color commands. Replace bold, underline,
170 * and italic escapes into colors specified via
171 * the -D command-line option.
173 char *anchor, *p, *p_next;
174 int buflen = ob - obuf;
175 unsigned char fg, bg, norm_attr;
177 * Only dark colors mentioned here, so that
178 * bold has visible effect.
180 static enum COLORS screen_color[] = {
181 BLACK, RED, GREEN, BROWN,
182 BLUE, MAGENTA, CYAN, LIGHTGRAY
185 /* Normal text colors are used as baseline. */
186 bg = nm_bg_color & 0xf;
187 fg = nm_fg_color & 0xf;
188 norm_attr = (bg << 4) | fg;
189 for (anchor = p_next = obuf;
190 (p_next = memchr (p_next, ESC,
191 buflen - (p_next - obuf)))
197 * Handle the null escape sequence
198 * (ESC-[m), which is used to restore
199 * the original color.
201 if (p[1] == '[' && is_ansi_end(p[2]))
209 if (p[1] == '[') /* "Esc-[" sequence */
212 * If some chars seen since
213 * the last escape sequence,
214 * write it out to the screen
215 * using current text attributes.
226 while (!is_ansi_end(*p))
229 long code = strtol(p, &q, 10);
234 * Incomplete sequence.
235 * Leave it unprocessed
238 int slop = q - anchor;
239 strcpy(obuf, anchor);
245 || code > 49 || code < 0
257 case 1: /* bold on */
261 case 3: /* italic on */
265 case 4: /* underline on */
269 case 8: /* concealed on */
272 case 0: /* all attrs off */
273 case 22:/* bold off */
274 case 23:/* italic off */
275 case 24:/* underline off */
279 case 30: case 31: case 32:
280 case 33: case 34: case 35:
282 fg = (fg & 8) | (screen_color[code - 30]);
284 case 39: /* default fg */
287 case 40: case 41: case 42:
288 case 43: case 44: case 45:
290 bg = (bg & 8) | (screen_color[code - 40]);
292 case 49: /* default fg */
298 if (is_ansi_end(*p) && p > p_next)
302 textattr ((bg << 4)| fg);
303 p_next = anchor = p + 1;
310 /* Output what's left in the buffer. */
319 fd = (any_display) ? 1 : 2;
320 if (write(fd, obuf, n) != n)
326 * Output a character.
332 #if 0 /* fake UTF-8 output for testing */
336 static char ubuf[MAX_UTF_CHAR_LEN];
337 static int ubuf_len = 0;
338 static int ubuf_index = 0;
341 ubuf_len = utf_len(c);
344 ubuf[ubuf_index++] = c;
345 if (ubuf_index < ubuf_len)
347 c = get_wchar(ubuf) & 0xFF;
357 if (c == '\n' && is_tty)
364 if (c == '\n' && is_tty) /* In OS-9, '\n' == 0x0D */
369 * Some versions of flush() write to *ob, so we must flush
370 * when we are still one char from the end of obuf.
372 if (ob >= &obuf[sizeof(obuf)-1])
391 * Convert an integral type to a string.
393 #define TYPE_TO_A_FUNC(funcname, type) \
394 void funcname(num, buf) \
398 int neg = (num < 0); \
399 char tbuf[INT_STRLEN_BOUND(num)+2]; \
400 register char *s = tbuf + sizeof(tbuf); \
401 if (neg) num = -num; \
404 *--s = (num % 10) + '0'; \
405 } while ((num /= 10) != 0); \
406 if (neg) *--s = '-'; \
410 TYPE_TO_A_FUNC(postoa, POSITION)
411 TYPE_TO_A_FUNC(linenumtoa, LINENUM)
412 TYPE_TO_A_FUNC(inttoa, int)
415 * Output an integer in a given radix.
421 char buf[INT_STRLEN_BOUND(num)];
425 return (strlen(buf));
429 * Output a line number in a given radix.
435 char buf[INT_STRLEN_BOUND(num)];
437 linenumtoa(num, buf);
439 return (strlen(buf));
443 * This function implements printf-like functionality
444 * using a more portable argument list mechanism than printf's.
447 less_printf(fmt, parg)
476 col += iprint_int(parg->p_int);
480 col += iprint_linenum(parg->p_linenum);
491 * If some other non-trivial char is pressed, unget it, so it will
492 * become the next command.
500 while ((c = getchr()) != '\n' && c != '\r')
504 if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
510 * Output a message in the lower left corner of the screen
511 * and wait for carriage return.
519 static char return_to_continue[] = " (press RETURN)";
523 if (any_display && is_tty)
527 at_enter(AT_STANDOUT);
531 col += less_printf(fmt, parg);
533 if (!(any_display && is_tty))
539 putstr(return_to_continue);
541 col += sizeof(return_to_continue) + so_e_width;
548 * Printing the message has probably scrolled the screen.
549 * {{ Unless the terminal doesn't have auto margins,
550 * in which case we just hammered on the right margin. }}
557 static char intr_to_abort[] = "... (interrupt to abort)";
560 * Output a message in the lower left corner of the screen
561 * and don't wait for carriage return.
562 * Usually used to warn that we are beginning a potentially
563 * time-consuming operation.
572 at_enter(AT_STANDOUT);
573 (void) less_printf(fmt, parg);
574 putstr(intr_to_abort);
581 * Output a message in the lower left corner of the screen
582 * and return a single-character response.
592 if (any_display && is_tty)
595 (void) less_printf(fmt, parg);
598 if (!(any_display && is_tty))