kernel - Fix races created by a comedy of circumstansces (3)
[dragonfly.git] / contrib / less / output.c
blobd6cfc382672022b6eec0c90b47f54b66545791d8
1 /*
2 * Copyright (C) 1984-2015 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.
8 */
12 * High level routines dealing with the output to the screen.
15 #include "less.h"
16 #if MSDOS_COMPILER==WIN32C
17 #include "windows.h"
18 #endif
20 public int errmsgs; /* Count of messages displayed by error() */
21 public int need_clr;
22 public int final_attr;
23 public int at_prompt;
25 extern int sigs;
26 extern int sc_width;
27 extern int so_s_width, so_e_width;
28 extern int screen_trashed;
29 extern int any_display;
30 extern int is_tty;
31 extern int oldbot;
33 #if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
34 extern int ctldisp;
35 extern int nm_fg_color, nm_bg_color;
36 extern int bo_fg_color, bo_bg_color;
37 extern int ul_fg_color, ul_bg_color;
38 extern int so_fg_color, so_bg_color;
39 extern int bl_fg_color, bl_bg_color;
40 #endif
43 * Display the line which is in the line buffer.
45 public void
46 put_line()
48 register int c;
49 register int i;
50 int a;
52 if (ABORT_SIGS())
55 * Don't output if a signal is pending.
57 screen_trashed = 1;
58 return;
61 final_attr = AT_NORMAL;
63 for (i = 0; (c = gline(i, &a)) != '\0'; i++)
65 at_switch(a);
66 final_attr = a;
67 if (c == '\b')
68 putbs();
69 else
70 putchr(c);
73 at_exit();
76 static char obuf[OUTBUF_SIZE];
77 static char *ob = obuf;
80 * Flush buffered output.
82 * If we haven't displayed any file data yet,
83 * output messages on error output (file descriptor 2),
84 * otherwise output on standard output (file descriptor 1).
86 * This has the desirable effect of producing all
87 * error messages on error output if standard output
88 * is directed to a file. It also does the same if
89 * we never produce any real output; for example, if
90 * the input file(s) cannot be opened. If we do
91 * eventually produce output, code in edit() makes
92 * sure these messages can be seen before they are
93 * overwritten or scrolled away.
95 public void
96 flush()
98 register int n;
99 register int fd;
101 n = (int) (ob - obuf);
102 if (n == 0)
103 return;
105 #if MSDOS_COMPILER==MSOFTC
106 if (is_tty && any_display)
108 *ob = '\0';
109 _outtext(obuf);
110 ob = obuf;
111 return;
113 #else
114 #if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
115 if (is_tty && any_display)
117 *ob = '\0';
118 if (ctldisp != OPT_ONPLUS)
119 WIN32textout(obuf, ob - obuf);
120 else
123 * Look for SGR escape sequences, and convert them
124 * to color commands. Replace bold, underline,
125 * and italic escapes into colors specified via
126 * the -D command-line option.
128 char *anchor, *p, *p_next;
129 unsigned char fg, bg;
130 static unsigned char at;
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 at = 0;
177 WIN32setcolors(nm_fg_color, nm_bg_color);
178 continue;
180 p_next = p;
183 * Select foreground/background colors
184 * based on the escape sequence.
186 fg = nm_fg_color;
187 bg = nm_bg_color;
188 while (!is_ansi_end(*p))
190 char *q;
191 long code = strtol(p, &q, 10);
193 if (*q == '\0')
196 * Incomplete sequence.
197 * Leave it unprocessed
198 * in the buffer.
200 int slop = (int) (q - anchor);
201 /* {{ strcpy args overlap! }} */
202 strcpy(obuf, anchor);
203 ob = &obuf[slop];
204 return;
207 if (q == p ||
208 code > 49 || code < 0 ||
209 (!is_ansi_end(*q) && *q != ';'))
211 p_next = q;
212 break;
214 if (*q == ';')
215 q++;
217 switch (code)
219 default:
220 /* case 0: all attrs off */
221 fg = nm_fg_color;
222 bg = nm_bg_color;
223 at = 0;
224 break;
225 case 1: /* bold on */
226 at |= 1;
227 break;
228 case 3: /* italic on */
229 case 7: /* inverse on */
230 at |= 2;
231 break;
232 case 4: /* underline on */
233 at |= 4;
234 break;
235 case 5: /* slow blink on */
236 case 6: /* fast blink on */
237 at |= 8;
238 break;
239 case 8: /* concealed on */
240 fg = (bg & 7) | 8;
241 break;
242 case 22: /* bold off */
243 at &= ~1;
244 break;
245 case 23: /* italic off */
246 case 27: /* inverse off */
247 at &= ~2;
248 break;
249 case 24: /* underline off */
250 at &= ~4;
251 break;
252 case 30: case 31: case 32:
253 case 33: case 34: case 35:
254 case 36: case 37:
255 fg = (fg & 8) | (screen_color[code - 30]);
256 break;
257 case 39: /* default fg */
258 fg = nm_fg_color;
259 break;
260 case 40: case 41: case 42:
261 case 43: case 44: case 45:
262 case 46: case 47:
263 bg = (bg & 8) | (screen_color[code - 40]);
264 break;
265 case 49: /* default fg */
266 bg = nm_bg_color;
267 break;
269 p = q;
271 if (!is_ansi_end(*p) || p == p_next)
272 break;
273 if (at & 1)
276 * If \e[1m use defined bold
277 * color, else set intensity.
279 if (p[-2] == '[')
281 #if MSDOS_COMPILER==WIN32C
282 fg |= FOREGROUND_INTENSITY;
283 bg |= BACKGROUND_INTENSITY;
284 #else
285 fg = bo_fg_color;
286 bg = bo_bg_color;
287 #endif
288 } else
289 fg |= 8;
290 } else if (at & 2)
292 fg = so_fg_color;
293 bg = so_bg_color;
294 } else if (at & 4)
296 fg = ul_fg_color;
297 bg = ul_bg_color;
298 } else if (at & 8)
300 fg = bl_fg_color;
301 bg = bl_bg_color;
303 fg &= 0xf;
304 bg &= 0xf;
305 WIN32setcolors(fg, bg);
306 p_next = anchor = p + 1;
307 } else
308 p_next++;
311 /* Output what's left in the buffer. */
312 WIN32textout(anchor, ob - anchor);
314 ob = obuf;
315 return;
317 #endif
318 #endif
319 fd = (any_display) ? 1 : 2;
320 if (write(fd, obuf, n) != n)
321 screen_trashed = 1;
322 ob = obuf;
326 * Output a character.
328 public int
329 putchr(c)
330 int c;
332 #if 0 /* fake UTF-8 output for testing */
333 extern int utf_mode;
334 if (utf_mode)
336 static char ubuf[MAX_UTF_CHAR_LEN];
337 static int ubuf_len = 0;
338 static int ubuf_index = 0;
339 if (ubuf_len == 0)
341 ubuf_len = utf_len(c);
342 ubuf_index = 0;
344 ubuf[ubuf_index++] = c;
345 if (ubuf_index < ubuf_len)
346 return c;
347 c = get_wchar(ubuf) & 0xFF;
348 ubuf_len = 0;
350 #endif
351 if (need_clr)
353 need_clr = 0;
354 clear_bot();
356 #if MSDOS_COMPILER
357 if (c == '\n' && is_tty)
359 /* remove_top(1); */
360 putchr('\r');
362 #else
363 #ifdef _OSK
364 if (c == '\n' && is_tty) /* In OS-9, '\n' == 0x0D */
365 putchr(0x0A);
366 #endif
367 #endif
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])
373 flush();
374 *ob++ = c;
375 at_prompt = 0;
376 return (c);
380 * Output a string.
382 public void
383 putstr(s)
384 register char *s;
386 while (*s != '\0')
387 putchr(*s++);
392 * Convert an integral type to a string.
394 #define TYPE_TO_A_FUNC(funcname, type) \
395 void funcname(num, buf) \
396 type num; \
397 char *buf; \
399 int neg = (num < 0); \
400 char tbuf[INT_STRLEN_BOUND(num)+2]; \
401 register char *s = tbuf + sizeof(tbuf); \
402 if (neg) num = -num; \
403 *--s = '\0'; \
404 do { \
405 *--s = (num % 10) + '0'; \
406 } while ((num /= 10) != 0); \
407 if (neg) *--s = '-'; \
408 strcpy(buf, s); \
411 TYPE_TO_A_FUNC(postoa, POSITION)
412 TYPE_TO_A_FUNC(linenumtoa, LINENUM)
413 TYPE_TO_A_FUNC(inttoa, int)
416 * Output an integer in a given radix.
418 static int
419 iprint_int(num)
420 int num;
422 char buf[INT_STRLEN_BOUND(num)];
424 inttoa(num, buf);
425 putstr(buf);
426 return ((int) strlen(buf));
430 * Output a line number in a given radix.
432 static int
433 iprint_linenum(num)
434 LINENUM num;
436 char buf[INT_STRLEN_BOUND(num)];
438 linenumtoa(num, buf);
439 putstr(buf);
440 return ((int) strlen(buf));
444 * This function implements printf-like functionality
445 * using a more portable argument list mechanism than printf's.
447 static int
448 less_printf(fmt, parg)
449 register char *fmt;
450 PARG *parg;
452 register char *s;
453 register int col;
455 col = 0;
456 while (*fmt != '\0')
458 if (*fmt != '%')
460 putchr(*fmt++);
461 col++;
462 } else
464 ++fmt;
465 switch (*fmt++)
467 case 's':
468 s = parg->p_string;
469 parg++;
470 while (*s != '\0')
472 putchr(*s++);
473 col++;
475 break;
476 case 'd':
477 col += iprint_int(parg->p_int);
478 parg++;
479 break;
480 case 'n':
481 col += iprint_linenum(parg->p_linenum);
482 parg++;
483 break;
487 return (col);
491 * Get a RETURN.
492 * If some other non-trivial char is pressed, unget it, so it will
493 * become the next command.
495 public void
496 get_return()
498 int c;
500 #if ONLY_RETURN
501 while ((c = getchr()) != '\n' && c != '\r')
502 bell();
503 #else
504 c = getchr();
505 if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
506 ungetcc(c);
507 #endif
511 * Output a message in the lower left corner of the screen
512 * and wait for carriage return.
514 public void
515 error(fmt, parg)
516 char *fmt;
517 PARG *parg;
519 int col = 0;
520 static char return_to_continue[] = " (press RETURN)";
522 errmsgs++;
524 if (any_display && is_tty)
526 if (!oldbot)
527 squish_check();
528 at_exit();
529 clear_bot();
530 at_enter(AT_STANDOUT);
531 col += so_s_width;
534 col += less_printf(fmt, parg);
536 if (!(any_display && is_tty))
538 putchr('\n');
539 return;
542 putstr(return_to_continue);
543 at_exit();
544 col += sizeof(return_to_continue) + so_e_width;
546 get_return();
547 lower_left();
548 clear_eol();
550 if (col >= sc_width)
552 * Printing the message has probably scrolled the screen.
553 * {{ Unless the terminal doesn't have auto margins,
554 * in which case we just hammered on the right margin. }}
556 screen_trashed = 1;
558 flush();
561 static char intr_to_abort[] = "... (interrupt to abort)";
564 * Output a message in the lower left corner of the screen
565 * and don't wait for carriage return.
566 * Usually used to warn that we are beginning a potentially
567 * time-consuming operation.
569 public void
570 ierror(fmt, parg)
571 char *fmt;
572 PARG *parg;
574 at_exit();
575 clear_bot();
576 at_enter(AT_STANDOUT);
577 (void) less_printf(fmt, parg);
578 putstr(intr_to_abort);
579 at_exit();
580 flush();
581 need_clr = 1;
585 * Output a message in the lower left corner of the screen
586 * and return a single-character response.
588 public int
589 query(fmt, parg)
590 char *fmt;
591 PARG *parg;
593 register int c;
594 int col = 0;
596 if (any_display && is_tty)
597 clear_bot();
599 (void) less_printf(fmt, parg);
600 c = getchr();
602 if (!(any_display && is_tty))
604 putchr('\n');
605 return (c);
608 lower_left();
609 if (col >= sc_width)
610 screen_trashed = 1;
611 flush();
613 return (c);