Oops, add missing space.
[dragonfly/port-amd64.git] / contrib / less-406 / output.c
blob9c9d4acf4d8c6dc9c3e92a81d93fdfea5f06bf43
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==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;
105 #if MSDOS_COMPILER==WIN32C
106 if (is_tty && any_display)
108 char *op;
109 DWORD nwritten = 0;
110 CONSOLE_SCREEN_BUFFER_INFO scr;
111 int row;
112 int col;
113 int olen;
114 extern HANDLE con_out;
116 olen = ob - obuf;
118 * There is a bug in Win32 WriteConsole() if we're
119 * writing in the last cell with a different color.
120 * To avoid color problems in the bottom line,
121 * we scroll the screen manually, before writing.
123 GetConsoleScreenBufferInfo(con_out, &scr);
124 col = scr.dwCursorPosition.X;
125 row = scr.dwCursorPosition.Y;
126 for (op = obuf; op < obuf + olen; op++)
128 if (*op == '\n')
130 col = 0;
131 row++;
132 } else if (*op == '\r')
134 col = 0;
135 } else
137 col++;
138 if (col >= sc_width)
140 col = 0;
141 row++;
145 if (row > scr.srWindow.Bottom)
146 win32_scroll_up(row - scr.srWindow.Bottom);
147 WriteConsole(con_out, obuf, olen, &nwritten, NULL);
148 ob = obuf;
149 return;
151 #else
152 #if MSDOS_COMPILER==MSOFTC
153 if (is_tty && any_display)
155 *ob = '\0';
156 _outtext(obuf);
157 ob = obuf;
158 return;
160 #else
161 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
162 if (is_tty && any_display)
164 *ob = '\0';
165 if (ctldisp != OPT_ONPLUS)
166 cputs(obuf);
167 else
170 * Look for SGR escape sequences, and convert them
171 * to color commands. Replace bold, underline,
172 * and italic escapes into colors specified via
173 * the -D command-line option.
175 char *anchor, *p, *p_next;
176 int buflen = ob - obuf;
177 unsigned char fg, bg, norm_attr;
179 * Only dark colors mentioned here, so that
180 * bold has visible effect.
182 static enum COLORS screen_color[] = {
183 BLACK, RED, GREEN, BROWN,
184 BLUE, MAGENTA, CYAN, LIGHTGRAY
187 /* Normal text colors are used as baseline. */
188 bg = nm_bg_color & 0xf;
189 fg = nm_fg_color & 0xf;
190 norm_attr = (bg << 4) | fg;
191 for (anchor = p_next = obuf;
192 (p_next = memchr (p_next, ESC,
193 buflen - (p_next - obuf)))
194 != NULL; )
196 p = p_next;
199 * Handle the null escape sequence
200 * (ESC-[m), which is used to restore
201 * the original color.
203 if (p[1] == '[' && is_ansi_end(p[2]))
205 textattr(norm_attr);
206 p += 3;
207 anchor = p_next = p;
208 continue;
211 if (p[1] == '[') /* "Esc-[" sequence */
214 * If some chars seen since
215 * the last escape sequence,
216 * write it out to the screen
217 * using current text attributes.
219 if (p > anchor)
221 *p = '\0';
222 cputs (anchor);
223 *p = ESC;
224 anchor = p;
226 p += 2;
227 p_next = p;
228 while (!is_ansi_end(*p))
230 char *q;
231 long code = strtol(p, &q, 10);
233 if (!*q)
236 * Incomplete sequence.
237 * Leave it unprocessed
238 * in the buffer.
240 int slop = q - anchor;
241 strcpy(obuf, anchor);
242 ob = &obuf[slop];
243 return;
246 if (q == p
247 || code > 49 || code < 0
248 || (!is_ansi_end(*q)
249 && *q != ';'))
251 p_next = q;
252 break;
254 if (*q == ';')
255 q++;
257 switch (code)
259 case 1: /* bold on */
260 fg = bo_fg_color;
261 bg = bo_bg_color;
262 break;
263 case 3: /* italic on */
264 fg = so_fg_color;
265 bg = so_bg_color;
266 break;
267 case 4: /* underline on */
268 fg = ul_fg_color;
269 bg = ul_bg_color;
270 break;
271 case 8: /* concealed on */
272 fg = (bg & 7) | 8;
273 break;
274 case 0: /* all attrs off */
275 case 22:/* bold off */
276 case 23:/* italic off */
277 case 24:/* underline off */
278 fg = nm_fg_color;
279 bg = nm_bg_color;
280 break;
281 case 30: case 31: case 32:
282 case 33: case 34: case 35:
283 case 36: case 37:
284 fg = (fg & 8) | (screen_color[code - 30]);
285 break;
286 case 39: /* default fg */
287 fg = nm_fg_color;
288 break;
289 case 40: case 41: case 42:
290 case 43: case 44: case 45:
291 case 46: case 47:
292 bg = (bg & 8) | (screen_color[code - 40]);
293 break;
294 case 49: /* default fg */
295 bg = nm_bg_color;
296 break;
298 p = q;
300 if (is_ansi_end(*p) && p > p_next)
302 bg &= 15;
303 fg &= 15;
304 textattr ((bg << 4)| fg);
305 p_next = anchor = p + 1;
306 } else
307 break;
308 } else
309 p_next++;
312 /* Output what's left in the buffer. */
313 cputs (anchor);
315 ob = obuf;
316 return;
318 #endif
319 #endif
320 #endif
321 fd = (any_display) ? 1 : 2;
322 if (write(fd, obuf, n) != n)
323 screen_trashed = 1;
324 ob = obuf;
328 * Output a character.
330 public int
331 putchr(c)
332 int c;
334 #if 0 /* fake UTF-8 output for testing */
335 extern int utf_mode;
336 if (utf_mode)
338 static char ubuf[MAX_UTF_CHAR_LEN];
339 static int ubuf_len = 0;
340 static int ubuf_index = 0;
341 if (ubuf_len == 0)
343 ubuf_len = utf_len(c);
344 ubuf_index = 0;
346 ubuf[ubuf_index++] = c;
347 if (ubuf_index < ubuf_len)
348 return c;
349 c = get_wchar(ubuf) & 0xFF;
350 ubuf_len = 0;
352 #endif
353 if (need_clr)
355 need_clr = 0;
356 clear_bot();
358 #if MSDOS_COMPILER
359 if (c == '\n' && is_tty)
361 /* remove_top(1); */
362 putchr('\r');
364 #else
365 #ifdef _OSK
366 if (c == '\n' && is_tty) /* In OS-9, '\n' == 0x0D */
367 putchr(0x0A);
368 #endif
369 #endif
371 * Some versions of flush() write to *ob, so we must flush
372 * when we are still one char from the end of obuf.
374 if (ob >= &obuf[sizeof(obuf)-1])
375 flush();
376 *ob++ = c;
377 at_prompt = 0;
378 return (c);
382 * Output a string.
384 public void
385 putstr(s)
386 register char *s;
388 while (*s != '\0')
389 putchr(*s++);
394 * Convert an integral type to a string.
396 #define TYPE_TO_A_FUNC(funcname, type) \
397 void funcname(num, buf) \
398 type num; \
399 char *buf; \
401 int neg = (num < 0); \
402 char tbuf[INT_STRLEN_BOUND(num)+2]; \
403 register char *s = tbuf + sizeof(tbuf); \
404 if (neg) num = -num; \
405 *--s = '\0'; \
406 do { \
407 *--s = (num % 10) + '0'; \
408 } while ((num /= 10) != 0); \
409 if (neg) *--s = '-'; \
410 strcpy(buf, s); \
413 TYPE_TO_A_FUNC(postoa, POSITION)
414 TYPE_TO_A_FUNC(linenumtoa, LINENUM)
415 TYPE_TO_A_FUNC(inttoa, int)
418 * Output an integer in a given radix.
420 static int
421 iprint_int(num)
422 int num;
424 char buf[INT_STRLEN_BOUND(num)];
426 inttoa(num, buf);
427 putstr(buf);
428 return (strlen(buf));
432 * Output a line number in a given radix.
434 static int
435 iprint_linenum(num)
436 LINENUM num;
438 char buf[INT_STRLEN_BOUND(num)];
440 linenumtoa(num, buf);
441 putstr(buf);
442 return (strlen(buf));
446 * This function implements printf-like functionality
447 * using a more portable argument list mechanism than printf's.
449 static int
450 less_printf(fmt, parg)
451 register char *fmt;
452 PARG *parg;
454 register char *s;
455 register int col;
457 col = 0;
458 while (*fmt != '\0')
460 if (*fmt != '%')
462 putchr(*fmt++);
463 col++;
464 } else
466 ++fmt;
467 switch (*fmt++)
469 case 's':
470 s = parg->p_string;
471 parg++;
472 while (*s != '\0')
474 putchr(*s++);
475 col++;
477 break;
478 case 'd':
479 col += iprint_int(parg->p_int);
480 parg++;
481 break;
482 case 'n':
483 col += iprint_linenum(parg->p_linenum);
484 parg++;
485 break;
489 return (col);
493 * Get a RETURN.
494 * If some other non-trivial char is pressed, unget it, so it will
495 * become the next command.
497 public void
498 get_return()
500 int c;
502 #if ONLY_RETURN
503 while ((c = getchr()) != '\n' && c != '\r')
504 bell();
505 #else
506 c = getchr();
507 if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
508 ungetcc(c);
509 #endif
513 * Output a message in the lower left corner of the screen
514 * and wait for carriage return.
516 public void
517 error(fmt, parg)
518 char *fmt;
519 PARG *parg;
521 int col = 0;
522 static char return_to_continue[] = " (press RETURN)";
524 errmsgs++;
526 if (any_display && is_tty)
528 if (!oldbot)
529 squish_check();
530 at_exit();
531 clear_bot();
532 at_enter(AT_STANDOUT);
533 col += so_s_width;
536 col += less_printf(fmt, parg);
538 if (!(any_display && is_tty))
540 putchr('\n');
541 return;
544 putstr(return_to_continue);
545 at_exit();
546 col += sizeof(return_to_continue) + so_e_width;
548 get_return();
549 lower_left();
551 if (col >= sc_width)
553 * Printing the message has probably scrolled the screen.
554 * {{ Unless the terminal doesn't have auto margins,
555 * in which case we just hammered on the right margin. }}
557 screen_trashed = 1;
559 flush();
562 static char intr_to_abort[] = "... (interrupt to abort)";
565 * Output a message in the lower left corner of the screen
566 * and don't wait for carriage return.
567 * Usually used to warn that we are beginning a potentially
568 * time-consuming operation.
570 public void
571 ierror(fmt, parg)
572 char *fmt;
573 PARG *parg;
575 at_exit();
576 clear_bot();
577 at_enter(AT_STANDOUT);
578 (void) less_printf(fmt, parg);
579 putstr(intr_to_abort);
580 at_exit();
581 flush();
582 need_clr = 1;
586 * Output a message in the lower left corner of the screen
587 * and return a single-character response.
589 public int
590 query(fmt, parg)
591 char *fmt;
592 PARG *parg;
594 register int c;
595 int col = 0;
597 if (any_display && is_tty)
598 clear_bot();
600 (void) less_printf(fmt, parg);
601 c = getchr();
603 if (!(any_display && is_tty))
605 putchr('\n');
606 return (c);
609 lower_left();
610 if (col >= sc_width)
611 screen_trashed = 1;
612 flush();
614 return (c);