2 * Copyright (C) 1984-2021 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, see the README file.
12 * High level routines dealing with the output to the screen.
16 #if MSDOS_COMPILER==WIN32C
18 #ifndef COMMON_LVB_UNDERSCORE
19 #define COMMON_LVB_UNDERSCORE 0x8000
23 public int errmsgs; /* Count of messages displayed by error() */
25 public int final_attr;
30 extern int so_s_width, so_e_width;
31 extern int screen_trashed;
35 #if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
37 extern int nm_fg_color, nm_bg_color;
38 extern int bo_fg_color, bo_bg_color;
39 extern int ul_fg_color, ul_bg_color;
40 extern int so_fg_color, so_bg_color;
41 extern int bl_fg_color, bl_bg_color;
43 #if MSDOS_COMPILER==WIN32C
44 extern int vt_enabled;
49 * Display the line which is in the line buffer.
61 * Don't output if a signal is pending.
67 final_attr = AT_NORMAL;
69 for (i = 0; (c = gline(i, &a)) != '\0'; i++)
82 static char obuf[OUTBUF_SIZE];
83 static char *ob = obuf;
84 static int outfd = 2; /* stderr */
86 #if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
90 if (ctldisp != OPT_ONPLUS || (vt_enabled && sgr_mode))
91 WIN32textout(obuf, ob - obuf);
95 * Look for SGR escape sequences, and convert them
96 * to color commands. Replace bold, underline,
97 * and italic escapes into colors specified via
98 * the -D command-line option.
100 char *anchor, *p, *p_next;
101 static int fg, fgi, bg, bgi;
104 #if MSDOS_COMPILER==WIN32C
105 /* Screen colors used by 3x and 4x SGR commands. */
106 static unsigned char screen_color[] = {
110 FOREGROUND_RED|FOREGROUND_GREEN,
112 FOREGROUND_BLUE|FOREGROUND_RED,
113 FOREGROUND_BLUE|FOREGROUND_GREEN,
114 FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED
117 static enum COLORS screen_color[] = {
118 BLACK, RED, GREEN, BROWN,
119 BLUE, MAGENTA, CYAN, LIGHTGRAY
123 if (fg == 0 && bg == 0)
125 fg = nm_fg_color & 7;
126 fgi = nm_fg_color & 8;
127 bg = nm_bg_color & 7;
128 bgi = nm_bg_color & 8;
130 for (anchor = p_next = obuf;
131 (p_next = memchr(p_next, ESC, ob - p_next)) != NULL; )
134 if (p[1] == '[') /* "ESC-[" sequence */
139 * If some chars seen since
140 * the last escape sequence,
141 * write them out to the screen.
143 WIN32textout(anchor, p-anchor);
146 p += 2; /* Skip the "ESC-[" */
150 * Handle null escape sequence
151 * "ESC[m", which restores
156 fg = nm_fg_color & 7;
157 fgi = nm_fg_color & 8;
158 bg = nm_bg_color & 7;
159 bgi = nm_bg_color & 8;
161 WIN32setcolors(nm_fg_color, nm_bg_color);
168 * Select foreground/background colors
169 * based on the escape sequence.
171 while (!is_ansi_end(*p))
174 long code = strtol(p, &q, 10);
179 * Incomplete sequence.
180 * Leave it unprocessed
183 int slop = (int) (q - anchor);
184 /* {{ strcpy args overlap! }} */
185 strcpy(obuf, anchor);
191 code > 49 || code < 0 ||
192 (!is_ansi_end(*q) && *q != ';'))
206 /* case 0: all attrs off */
207 fg = nm_fg_color & 7;
208 bg = nm_bg_color & 7;
213 * \e[0;...m resets them
221 fgi = nm_fg_color & 8;
222 bgi = nm_bg_color & 8;
225 case 1: /* bold on */
229 case 3: /* italic on */
230 case 7: /* inverse on */
233 case 4: /* underline on */
237 case 5: /* slow blink on */
238 case 6: /* fast blink on */
242 case 8: /* concealed on */
245 case 22: /* bold off */
249 case 23: /* italic off */
250 case 27: /* inverse off */
253 case 24: /* underline off */
257 case 28: /* concealed off */
260 case 30: case 31: case 32:
261 case 33: case 34: case 35:
263 fg = screen_color[code - 30];
266 case 39: /* default fg */
267 fg = nm_fg_color & 7;
270 case 40: case 41: case 42:
271 case 43: case 44: case 45:
273 bg = screen_color[code - 40];
276 case 49: /* default bg */
277 bg = nm_bg_color & 7;
283 if (!is_ansi_end(*p) || p == p_next)
286 * In SGR mode, the ANSI sequence is
287 * always honored; otherwise if an attr
288 * is used by itself ("\e[1m" versus
289 * "\e[1;33m", for example), set the
290 * color assigned to that attribute.
292 if (sgr_mode || (at & 32))
329 #if MSDOS_COMPILER==WIN32C
330 f &= 0xf | COMMON_LVB_UNDERSCORE;
335 WIN32setcolors(f, b);
336 p_next = anchor = p + 1;
341 /* Output what's left in the buffer. */
342 WIN32textout(anchor, ob - anchor);
349 * Flush buffered output.
351 * If we haven't displayed any file data yet,
352 * output messages on error output (file descriptor 2),
353 * otherwise output on standard output (file descriptor 1).
355 * This has the desirable effect of producing all
356 * error messages on error output if standard output
357 * is directed to a file. It also does the same if
358 * we never produce any real output; for example, if
359 * the input file(s) cannot be opened. If we do
360 * eventually produce output, code in edit() makes
361 * sure these messages can be seen before they are
362 * overwritten or scrolled away.
369 n = (int) (ob - obuf);
374 #if MSDOS_COMPILER==MSOFTC
382 #if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
393 if (write(outfd, obuf, n) != n)
398 * Set the output file descriptor (1=stdout or 2=stderr).
409 * Output a character.
415 #if 0 /* fake UTF-8 output for testing */
419 static char ubuf[MAX_UTF_CHAR_LEN];
420 static int ubuf_len = 0;
421 static int ubuf_index = 0;
424 ubuf_len = utf_len(c);
427 ubuf[ubuf_index++] = c;
428 if (ubuf_index < ubuf_len)
430 c = get_wchar(ubuf) & 0xFF;
440 if (c == '\n' && is_tty)
447 if (c == '\n' && is_tty) /* In OS-9, '\n' == 0x0D */
452 * Some versions of flush() write to *ob, so we must flush
453 * when we are still one char from the end of obuf.
455 if (ob >= &obuf[sizeof(obuf)-1])
475 * Convert an integral type to a string.
477 #define TYPE_TO_A_FUNC(funcname, type) \
478 void funcname(num, buf) \
482 int neg = (num < 0); \
483 char tbuf[INT_STRLEN_BOUND(num)+2]; \
484 char *s = tbuf + sizeof(tbuf); \
485 if (neg) num = -num; \
488 *--s = (num % 10) + '0'; \
489 } while ((num /= 10) != 0); \
490 if (neg) *--s = '-'; \
494 TYPE_TO_A_FUNC(postoa, POSITION)
495 TYPE_TO_A_FUNC(linenumtoa, LINENUM)
496 TYPE_TO_A_FUNC(inttoa, int)
499 * Convert an string to an integral type.
501 #define STR_TO_TYPE_FUNC(funcname, type) \
502 type funcname(buf, ebuf) \
509 if (c < '0' || c > '9') break; \
510 val = 10 * val + c - '0'; \
512 if (ebuf != NULL) *ebuf = buf; \
516 STR_TO_TYPE_FUNC(lstrtopos, POSITION)
517 STR_TO_TYPE_FUNC(lstrtoi, int)
520 * Output an integer in a given radix.
526 char buf[INT_STRLEN_BOUND(num)];
530 return ((int) strlen(buf));
534 * Output a line number in a given radix.
540 char buf[INT_STRLEN_BOUND(num)];
542 linenumtoa(num, buf);
544 return ((int) strlen(buf));
548 * This function implements printf-like functionality
549 * using a more portable argument list mechanism than printf's.
551 * {{ This paranoia about the portability of printf dates from experiences
552 * with systems in the 1980s and is of course no longer necessary. }}
555 less_printf(fmt, parg)
584 col += iprint_int(parg->p_int);
588 col += iprint_linenum(parg->p_linenum);
592 putchr(parg->p_char);
606 * If some other non-trivial char is pressed, unget it, so it will
607 * become the next command.
610 get_return(VOID_PARAM)
615 while ((c = getchr()) != '\n' && c != '\r')
619 if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
625 * Output a message in the lower left corner of the screen
626 * and wait for carriage return.
634 static char return_to_continue[] = " (press RETURN)";
640 less_printf(fmt, parg);
649 at_enter(AT_STANDOUT|AT_COLOR_ERROR);
651 col += less_printf(fmt, parg);
652 putstr(return_to_continue);
654 col += sizeof(return_to_continue) + so_e_width;
662 * Printing the message has probably scrolled the screen.
663 * {{ Unless the terminal doesn't have auto margins,
664 * in which case we just hammered on the right margin. }}
671 static char intr_to_abort[] = "... (interrupt to abort)";
674 * Output a message in the lower left corner of the screen
675 * and don't wait for carriage return.
676 * Usually used to warn that we are beginning a potentially
677 * time-consuming operation.
686 at_enter(AT_STANDOUT|AT_COLOR_ERROR);
687 (void) less_printf(fmt, parg);
688 putstr(intr_to_abort);
695 * Output a message in the lower left corner of the screen
696 * and return a single-character response.
709 (void) less_printf(fmt, parg);