Remove old versions of less.
[dragonfly.git] / contrib / less-4 / output.c
blobe3300459c87fc47e1653fb69ed833aebad311b19
1 /*
2 * Copyright (C) 1984-2007 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.
9 */
13 * High level routines dealing with the output to the screen.
16 #include "less.h"
17 #if MSDOS_COMPILER==WIN32C
18 #include "windows.h"
19 #endif
21 public int errmsgs; /* Count of messages displayed by error() */
22 public int need_clr;
23 public int final_attr;
24 public int at_prompt;
26 extern int sigs;
27 extern int sc_width;
28 extern int so_s_width, so_e_width;
29 extern int screen_trashed;
30 extern int any_display;
31 extern int is_tty;
32 extern int oldbot;
34 #if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
35 extern int ctldisp;
36 extern int nm_fg_color, nm_bg_color;
37 extern int bo_fg_color, bo_bg_color;
38 extern int ul_fg_color, ul_bg_color;
39 extern int so_fg_color, so_bg_color;
40 extern int bl_fg_color, bl_bg_color;
41 #endif
44 * Display the line which is in the line buffer.
46 public void
47 put_line()
49 register int c;
50 register int i;
51 int a;
53 if (ABORT_SIGS())
56 * Don't output if a signal is pending.
58 screen_trashed = 1;
59 return;
62 final_attr = AT_NORMAL;
64 for (i = 0; (c = gline(i, &a)) != '\0'; i++)
66 at_switch(a);
67 final_attr = a;
68 if (c == '\b')
69 putbs();
70 else
71 putchr(c);
74 at_exit();
77 static char obuf[OUTBUF_SIZE];
78 static char *ob = obuf;
81 * Flush buffered output.
83 * If we haven't displayed any file data yet,
84 * output messages on error output (file descriptor 2),
85 * otherwise output on standard output (file descriptor 1).
87 * This has the desirable effect of producing all
88 * error messages on error output if standard output
89 * is directed to a file. It also does the same if
90 * we never produce any real output; for example, if
91 * the input file(s) cannot be opened. If we do
92 * eventually produce output, code in edit() makes
93 * sure these messages can be seen before they are
94 * overwritten or scrolled away.
96 public void
97 flush()
99 register int n;
100 register int fd;
102 n = ob - obuf;
103 if (n == 0)
104 return;
106 #if MSDOS_COMPILER==MSOFTC
107 if (is_tty && any_display)
109 *ob = '\0';
110 _outtext(obuf);
111 ob = obuf;
112 return;
114 #else
115 #if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
116 if (is_tty && any_display)
118 *ob = '\0';
119 if (ctldisp != OPT_ONPLUS)
120 WIN32textout(obuf, ob - obuf);
121 else
124 * Look for SGR escape sequences, and convert them
125 * to color commands. Replace bold, underline,
126 * and italic escapes into colors specified via
127 * the -D command-line option.
129 char *anchor, *p, *p_next;
130 unsigned char fg, bg;
131 #if MSDOS_COMPILER==WIN32C
132 /* Screen colors used by 3x and 4x SGR commands. */
133 static unsigned char screen_color[] = {
134 0, /* BLACK */
135 FOREGROUND_RED,
136 FOREGROUND_GREEN,
137 FOREGROUND_RED|FOREGROUND_GREEN,
138 FOREGROUND_BLUE,
139 FOREGROUND_BLUE|FOREGROUND_RED,
140 FOREGROUND_BLUE|FOREGROUND_GREEN,
141 FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED
143 #else
144 static enum COLORS screen_color[] = {
145 BLACK, RED, GREEN, BROWN,
146 BLUE, MAGENTA, CYAN, LIGHTGRAY
148 #endif
150 for (anchor = p_next = obuf;
151 (p_next = memchr(p_next, ESC, ob - p_next)) != NULL; )
153 p = p_next;
154 if (p[1] == '[') /* "ESC-[" sequence */
156 if (p > anchor)
159 * If some chars seen since
160 * the last escape sequence,
161 * write them out to the screen.
163 WIN32textout(anchor, p-anchor);
164 anchor = p;
166 p += 2; /* Skip the "ESC-[" */
167 if (is_ansi_end(*p))
170 * Handle null escape sequence
171 * "ESC[m", which restores
172 * the normal color.
174 p++;
175 anchor = p_next = p;
176 WIN32setcolors(nm_fg_color, nm_bg_color);
177 continue;
179 p_next = p;
182 * Select foreground/background colors
183 * based on the escape sequence.
185 fg = nm_fg_color;
186 bg = nm_bg_color;
187 while (!is_ansi_end(*p))
189 char *q;
190 long code = strtol(p, &q, 10);
192 if (*q == '\0')
195 * Incomplete sequence.
196 * Leave it unprocessed
197 * in the buffer.
199 int slop = q - anchor;
200 /* {{ strcpy args overlap! }} */
201 strcpy(obuf, anchor);
202 ob = &obuf[slop];
203 return;
206 if (q == p ||
207 code > 49 || code < 0 ||
208 (!is_ansi_end(*q) && *q != ';'))
210 p_next = q;
211 break;
213 if (*q == ';')
214 q++;
216 switch (code)
218 default:
219 /* case 0: all attrs off */
220 /* case 22: bold off */
221 /* case 23: italic off */
222 /* case 24: underline off */
223 /* case 27: inverse off */
224 fg = nm_fg_color;
225 bg = nm_bg_color;
226 break;
227 case 1: /* bold on */
228 fg = bo_fg_color;
229 bg = bo_bg_color;
230 break;
231 case 3: /* italic on */
232 case 7: /* inverse on */
233 fg = so_fg_color;
234 bg = so_bg_color;
235 break;
236 case 4: /* underline on */
237 fg = ul_fg_color;
238 bg = ul_bg_color;
239 break;
240 case 5: /* slow blink on */
241 case 6: /* fast blink on */
242 fg = bl_fg_color;
243 bg = bl_bg_color;
244 break;
245 case 8: /* concealed on */
246 fg = (bg & 7) | 8;
247 break;
248 case 30: case 31: case 32:
249 case 33: case 34: case 35:
250 case 36: case 37:
251 fg = (fg & 8) | (screen_color[code - 30]);
252 break;
253 case 39: /* default fg */
254 fg = nm_fg_color;
255 break;
256 case 40: case 41: case 42:
257 case 43: case 44: case 45:
258 case 46: case 47:
259 bg = (bg & 8) | (screen_color[code - 40]);
260 break;
261 case 49: /* default fg */
262 bg = nm_bg_color;
263 break;
265 p = q;
267 if (!is_ansi_end(*p) || p == p_next)
268 break;
269 fg &= 0xf;
270 bg &= 0xf;
271 WIN32setcolors(fg, bg);
272 p_next = anchor = p + 1;
273 } else
274 p_next++;
277 /* Output what's left in the buffer. */
278 WIN32textout(anchor, ob - anchor);
280 ob = obuf;
281 return;
283 #endif
284 #endif
285 fd = (any_display) ? 1 : 2;
286 if (write(fd, obuf, n) != n)
287 screen_trashed = 1;
288 ob = obuf;
292 * Output a character.
294 public int
295 putchr(c)
296 int c;
298 #if 0 /* fake UTF-8 output for testing */
299 extern int utf_mode;
300 if (utf_mode)
302 static char ubuf[MAX_UTF_CHAR_LEN];
303 static int ubuf_len = 0;
304 static int ubuf_index = 0;
305 if (ubuf_len == 0)
307 ubuf_len = utf_len(c);
308 ubuf_index = 0;
310 ubuf[ubuf_index++] = c;
311 if (ubuf_index < ubuf_len)
312 return c;
313 c = get_wchar(ubuf) & 0xFF;
314 ubuf_len = 0;
316 #endif
317 if (need_clr)
319 need_clr = 0;
320 clear_bot();
322 #if MSDOS_COMPILER
323 if (c == '\n' && is_tty)
325 /* remove_top(1); */
326 putchr('\r');
328 #else
329 #ifdef _OSK
330 if (c == '\n' && is_tty) /* In OS-9, '\n' == 0x0D */
331 putchr(0x0A);
332 #endif
333 #endif
335 * Some versions of flush() write to *ob, so we must flush
336 * when we are still one char from the end of obuf.
338 if (ob >= &obuf[sizeof(obuf)-1])
339 flush();
340 *ob++ = c;
341 at_prompt = 0;
342 return (c);
346 * Output a string.
348 public void
349 putstr(s)
350 register char *s;
352 while (*s != '\0')
353 putchr(*s++);
358 * Convert an integral type to a string.
360 #define TYPE_TO_A_FUNC(funcname, type) \
361 void funcname(num, buf) \
362 type num; \
363 char *buf; \
365 int neg = (num < 0); \
366 char tbuf[INT_STRLEN_BOUND(num)+2]; \
367 register char *s = tbuf + sizeof(tbuf); \
368 if (neg) num = -num; \
369 *--s = '\0'; \
370 do { \
371 *--s = (num % 10) + '0'; \
372 } while ((num /= 10) != 0); \
373 if (neg) *--s = '-'; \
374 strcpy(buf, s); \
377 TYPE_TO_A_FUNC(postoa, POSITION)
378 TYPE_TO_A_FUNC(linenumtoa, LINENUM)
379 TYPE_TO_A_FUNC(inttoa, int)
382 * Output an integer in a given radix.
384 static int
385 iprint_int(num)
386 int num;
388 char buf[INT_STRLEN_BOUND(num)];
390 inttoa(num, buf);
391 putstr(buf);
392 return (strlen(buf));
396 * Output a line number in a given radix.
398 static int
399 iprint_linenum(num)
400 LINENUM num;
402 char buf[INT_STRLEN_BOUND(num)];
404 linenumtoa(num, buf);
405 putstr(buf);
406 return (strlen(buf));
410 * This function implements printf-like functionality
411 * using a more portable argument list mechanism than printf's.
413 static int
414 less_printf(fmt, parg)
415 register char *fmt;
416 PARG *parg;
418 register char *s;
419 register int col;
421 col = 0;
422 while (*fmt != '\0')
424 if (*fmt != '%')
426 putchr(*fmt++);
427 col++;
428 } else
430 ++fmt;
431 switch (*fmt++)
433 case 's':
434 s = parg->p_string;
435 parg++;
436 while (*s != '\0')
438 putchr(*s++);
439 col++;
441 break;
442 case 'd':
443 col += iprint_int(parg->p_int);
444 parg++;
445 break;
446 case 'n':
447 col += iprint_linenum(parg->p_linenum);
448 parg++;
449 break;
453 return (col);
457 * Get a RETURN.
458 * If some other non-trivial char is pressed, unget it, so it will
459 * become the next command.
461 public void
462 get_return()
464 int c;
466 #if ONLY_RETURN
467 while ((c = getchr()) != '\n' && c != '\r')
468 bell();
469 #else
470 c = getchr();
471 if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
472 ungetcc(c);
473 #endif
477 * Output a message in the lower left corner of the screen
478 * and wait for carriage return.
480 public void
481 error(fmt, parg)
482 char *fmt;
483 PARG *parg;
485 int col = 0;
486 static char return_to_continue[] = " (press RETURN)";
488 errmsgs++;
490 if (any_display && is_tty)
492 if (!oldbot)
493 squish_check();
494 at_exit();
495 clear_bot();
496 at_enter(AT_STANDOUT);
497 col += so_s_width;
500 col += less_printf(fmt, parg);
502 if (!(any_display && is_tty))
504 putchr('\n');
505 return;
508 putstr(return_to_continue);
509 at_exit();
510 col += sizeof(return_to_continue) + so_e_width;
512 get_return();
513 lower_left();
515 if (col >= sc_width)
517 * Printing the message has probably scrolled the screen.
518 * {{ Unless the terminal doesn't have auto margins,
519 * in which case we just hammered on the right margin. }}
521 screen_trashed = 1;
523 flush();
526 static char intr_to_abort[] = "... (interrupt to abort)";
529 * Output a message in the lower left corner of the screen
530 * and don't wait for carriage return.
531 * Usually used to warn that we are beginning a potentially
532 * time-consuming operation.
534 public void
535 ierror(fmt, parg)
536 char *fmt;
537 PARG *parg;
539 at_exit();
540 clear_bot();
541 at_enter(AT_STANDOUT);
542 (void) less_printf(fmt, parg);
543 putstr(intr_to_abort);
544 at_exit();
545 flush();
546 need_clr = 1;
550 * Output a message in the lower left corner of the screen
551 * and return a single-character response.
553 public int
554 query(fmt, parg)
555 char *fmt;
556 PARG *parg;
558 register int c;
559 int col = 0;
561 if (any_display && is_tty)
562 clear_bot();
564 (void) less_printf(fmt, parg);
565 c = getchr();
567 if (!(any_display && is_tty))
569 putchr('\n');
570 return (c);
573 lower_left();
574 if (col >= sc_width)
575 screen_trashed = 1;
576 flush();
578 return (c);