"SfR Fresh" - the SfR Freeware/Shareware Archive 
Member "less-424/output.c" of archive less-424.tar.gz:
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 /*
2 * Copyright (C) 1984-2008 Mark Nudelman
3 *
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.
6 *
7 * For more information about less, or for information on how to
8 * contact the author, see the README file.
9 */
10
11
12 /*
13 * High level routines dealing with the output to the screen.
14 */
15
16 #include "less.h"
17 #if MSDOS_COMPILER==WIN32C
18 #include "windows.h"
19 #endif
20
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;
25
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;
33
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
42
43 /*
44 * Display the line which is in the line buffer.
45 */
46 public void
47 put_line()
48 {
49 register int c;
50 register int i;
51 int a;
52
53 if (ABORT_SIGS())
54 {
55 /*
56 * Don't output if a signal is pending.
57 */
58 screen_trashed = 1;
59 return;
60 }
61
62 final_attr = AT_NORMAL;
63
64 for (i = 0; (c = gline(i, &a)) != '\0'; i++)
65 {
66 at_switch(a);
67 final_attr = a;
68 if (c == '\b')
69 putbs();
70 else
71 putchr(c);
72 }
73
74 at_exit();
75 }
76
77 static char obuf[OUTBUF_SIZE];
78 static char *ob = obuf;
79
80 /*
81 * Flush buffered output.
82 *
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).
86 *
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.
95 */
96 public void
97 flush()
98 {
99 register int n;
100 register int fd;
101
102 n = ob - obuf;
103 if (n == 0)
104 return;
105
106 #if MSDOS_COMPILER==MSOFTC
107 if (is_tty && any_display)
108 {
109 *ob = '\0';
110 _outtext(obuf);
111 ob = obuf;
112 return;
113 }
114 #else
115 #if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
116 if (is_tty && any_display)
117 {
118 *ob = '\0';
119 if (ctldisp != OPT_ONPLUS)
120 WIN32textout(obuf, ob - obuf);
121 else
122 {
123 /*
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.
128 */
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
142 };
143 #else
144 static enum COLORS screen_color[] = {
145 BLACK, RED, GREEN, BROWN,
146 BLUE, MAGENTA, CYAN, LIGHTGRAY
147 };
148 #endif
149
150 for (anchor = p_next = obuf;
151 (p_next = memchr(p_next, ESC, ob - p_next)) != NULL; )
152 {
153 p = p_next;
154 if (p[1] == '[') /* "ESC-[" sequence */
155 {
156 if (p > anchor)
157 {
158 /*
159 * If some chars seen since
160 * the last escape sequence,
161 * write them out to the screen.
162 */
163 WIN32textout(anchor, p-anchor);
164 anchor = p;
165 }
166 p += 2; /* Skip the "ESC-[" */
167 if (is_ansi_end(*p))
168 {
169 /*
170 * Handle null escape sequence
171 * "ESC[m", which restores
172 * the normal color.
173 */
174 p++;
175 anchor = p_next = p;
176 WIN32setcolors(nm_fg_color, nm_bg_color);
177 continue;
178 }
179 p_next = p;
180
181 /*
182 * Select foreground/background colors
183 * based on the escape sequence.
184 */
185 fg = nm_fg_color;
186 bg = nm_bg_color;
187 while (!is_ansi_end(*p))
188 {
189 char *q;
190 long code = strtol(p, &q, 10);
191
192 if (*q == '\0')
193 {
194 /*
195 * Incomplete sequence.
196 * Leave it unprocessed
197 * in the buffer.
198 */
199 int slop = q - anchor;
200 /* {{ strcpy args overlap! }} */
201 strcpy(obuf, anchor);
202 ob = &obuf[slop];
203 return;
204 }
205
206 if (q == p ||
207 code > 49 || code < 0 ||
208 (!is_ansi_end(*q) && *q != ';'))
209 {
210 p_next = q;
211 break;
212 }
213 if (*q == ';')
214 q++;
215
216 switch (code)
217 {
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;
264 }
265 p = q;
266 }
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++;
275 }
276
277 /* Output what's left in the buffer. */
278 WIN32textout(anchor, ob - anchor);
279 }
280 ob = obuf;
281 return;
282 }
283 #endif
284 #endif
285 fd = (any_display) ? 1 : 2;
286 if (write(fd, obuf, n) != n)
287 screen_trashed = 1;
288 ob = obuf;
289 }
290
291 /*
292 * Output a character.
293 */
294 public int
295 putchr(c)
296 int c;
297 {
298 #if 0 /* fake UTF-8 output for testing */
299 extern int utf_mode;
300 if (utf_mode)
301 {
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)
306 {
307 ubuf_len = utf_len(c);
308 ubuf_index = 0;
309 }
310 ubuf[ubuf_index++] = c;
311 if (ubuf_index < ubuf_len)
312 return c;
313 c = get_wchar(ubuf) & 0xFF;
314 ubuf_len = 0;
315 }
316 #endif
317 if (need_clr)
318 {
319 need_clr = 0;
320 clear_bot();
321 }
322 #if MSDOS_COMPILER
323 if (c == '\n' && is_tty)
324 {
325 /* remove_top(1); */
326 putchr('\r');
327 }
328 #else
329 #ifdef _OSK
330 if (c == '\n' && is_tty) /* In OS-9, '\n' == 0x0D */
331 putchr(0x0A);
332 #endif
333 #endif
334 /*
335 * Some versions of flush() write to *ob, so we must flush
336 * when we are still one char from the end of obuf.
337 */
338 if (ob >= &obuf[sizeof(obuf)-1])
339 flush();
340 *ob++ = c;
341 at_prompt = 0;
342 return (c);
343 }
344
345 /*
346 * Output a string.
347 */
348 public void
349 putstr(s)
350 register char *s;
351 {
352 while (*s != '\0')
353 putchr(*s++);
354 }
355
356
357 /*
358 * Convert an integral type to a string.
359 */
360 #define TYPE_TO_A_FUNC(funcname, type) \
361 void funcname(num, buf) \
362 type num; \
363 char *buf; \
364 { \
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); \
375 }
376
377 TYPE_TO_A_FUNC(postoa, POSITION)
378 TYPE_TO_A_FUNC(linenumtoa, LINENUM)
379 TYPE_TO_A_FUNC(inttoa, int)
380
381 /*
382 * Output an integer in a given radix.
383 */
384 static int
385 iprint_int(num)
386 int num;
387 {
388 char buf[INT_STRLEN_BOUND(num)];
389
390 inttoa(num, buf);
391 putstr(buf);
392 return (strlen(buf));
393 }
394
395 /*
396 * Output a line number in a given radix.
397 */
398 static int
399 iprint_linenum(num)
400 LINENUM num;
401 {
402 char buf[INT_STRLEN_BOUND(num)];
403
404 linenumtoa(num, buf);
405 putstr(buf);
406 return (strlen(buf));
407 }
408
409 /*
410 * This function implements printf-like functionality
411 * using a more portable argument list mechanism than printf's.
412 */
413 static int
414 less_printf(fmt, parg)
415 register char *fmt;
416 PARG *parg;
417 {
418 register char *s;
419 register int col;
420
421 col = 0;
422 while (*fmt != '\0')
423 {
424 if (*fmt != '%')
425 {
426 putchr(*fmt++);
427 col++;
428 } else
429 {
430 ++fmt;
431 switch (*fmt++)
432 {
433 case 's':
434 s = parg->p_string;
435 parg++;
436 while (*s != '\0')
437 {
438 putchr(*s++);
439 col++;
440 }
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;
450 }
451 }
452 }
453 return (col);
454 }
455
456 /*
457 * Get a RETURN.
458 * If some other non-trivial char is pressed, unget it, so it will
459 * become the next command.
460 */
461 public void
462 get_return()
463 {
464 int c;
465
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
474 }
475
476 /*
477 * Output a message in the lower left corner of the screen
478 * and wait for carriage return.
479 */
480 public void
481 error(fmt, parg)
482 char *fmt;
483 PARG *parg;
484 {
485 int col = 0;
486 static char return_to_continue[] = " (press RETURN)";
487
488 errmsgs++;
489
490 if (any_display && is_tty)
491 {
492 if (!oldbot)
493 squish_check();
494 at_exit();
495 clear_bot();
496 at_enter(AT_STANDOUT);
497 col += so_s_width;
498 }
499
500 col += less_printf(fmt, parg);
501
502 if (!(any_display && is_tty))
503 {
504 putchr('\n');
505 return;
506 }
507
508 putstr(return_to_continue);
509 at_exit();
510 col += sizeof(return_to_continue) + so_e_width;
511
512 get_return();
513 lower_left();
514
515 if (col >= sc_width)
516 /*
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. }}
520 */
521 screen_trashed = 1;
522
523 flush();
524 }
525
526 static char intr_to_abort[] = "... (interrupt to abort)";
527
528 /*
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.
533 */
534 public void
535 ierror(fmt, parg)
536 char *fmt;
537 PARG *parg;
538 {
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;
547 }
548
549 /*
550 * Output a message in the lower left corner of the screen
551 * and return a single-character response.
552 */
553 public int
554 query(fmt, parg)
555 char *fmt;
556 PARG *parg;
557 {
558 register int c;
559 int col = 0;
560
561 if (any_display && is_tty)
562 clear_bot();
563
564 (void) less_printf(fmt, parg);
565 c = getchr();
566
567 if (!(any_display && is_tty))
568 {
569 putchr('\n');
570 return (c);
571 }
572
573 lower_left();
574 if (col >= sc_width)
575 screen_trashed = 1;
576 flush();
577
578 return (c);
579 }