Annotation of src/usr.bin/less/output.c, Revision 1.13
1.1 etheisen 1: /*
1.9 shadchin 2: * Copyright (C) 1984-2012 Mark Nudelman
1.12 nicm 3: * Modified for use with illumos by Garrett D'Amore.
4: * Copyright 2014 Garrett D'Amore <garrett@damore.org>
1.1 etheisen 5: *
1.5 millert 6: * You may distribute under the terms of either the GNU General Public
7: * License or the Less License, as specified in the README file.
1.1 etheisen 8: *
1.9 shadchin 9: * For more information, see the README file.
1.10 nicm 10: */
1.1 etheisen 11:
12: /*
13: * High level routines dealing with the output to the screen.
14: */
15:
16: #include "less.h"
1.10 nicm 17:
18: int errmsgs; /* Count of messages displayed by error() */
1.1 etheisen 19:
1.7 millert 20: extern volatile sig_atomic_t sigs;
1.1 etheisen 21: extern int sc_width;
22: extern int so_s_width, so_e_width;
23: extern int screen_trashed;
24: extern int any_display;
1.5 millert 25: extern int is_tty;
1.6 shadchin 26: extern int oldbot;
1.5 millert 27:
1.10 nicm 28: static int need_clr;
1.1 etheisen 29:
30: /*
31: * Display the line which is in the line buffer.
32: */
1.10 nicm 33: void
34: put_line(void)
1.1 etheisen 35: {
1.10 nicm 36: int c;
37: int i;
1.1 etheisen 38: int a;
39:
1.10 nicm 40: if (ABORT_SIGS()) {
1.1 etheisen 41: /*
42: * Don't output if a signal is pending.
43: */
44: screen_trashed = 1;
45: return;
46: }
47:
1.10 nicm 48: for (i = 0; (c = gline(i, &a)) != '\0'; i++) {
1.6 shadchin 49: at_switch(a);
1.1 etheisen 50: if (c == '\b')
51: putbs();
52: else
1.10 nicm 53: (void) putchr(c);
1.1 etheisen 54: }
55:
1.6 shadchin 56: at_exit();
1.1 etheisen 57: }
58:
1.5 millert 59: static char obuf[OUTBUF_SIZE];
1.1 etheisen 60: static char *ob = obuf;
61:
62: /*
63: * Flush buffered output.
64: *
65: * If we haven't displayed any file data yet,
66: * output messages on error output (file descriptor 2),
67: * otherwise output on standard output (file descriptor 1).
68: *
69: * This has the desirable effect of producing all
70: * error messages on error output if standard output
71: * is directed to a file. It also does the same if
72: * we never produce any real output; for example, if
73: * the input file(s) cannot be opened. If we do
74: * eventually produce output, code in edit() makes
75: * sure these messages can be seen before they are
76: * overwritten or scrolled away.
77: */
1.10 nicm 78: void
1.13 ! nicm 79: flush(int ignore_errors)
1.1 etheisen 80: {
1.10 nicm 81: int n;
82: int fd;
1.8 millert 83: ssize_t nwritten;
1.1 etheisen 84:
1.10 nicm 85: n = (intptr_t)ob - (intptr_t)obuf;
1.1 etheisen 86: if (n == 0)
87: return;
1.5 millert 88:
1.6 shadchin 89: fd = (any_display) ? STDOUT_FILENO : STDERR_FILENO;
1.8 millert 90: nwritten = write(fd, obuf, n);
91: if (nwritten != n) {
1.13 ! nicm 92: if (nwritten == -1 && !ignore_errors)
1.8 millert 93: quit(QUIT_ERROR);
1.1 etheisen 94: screen_trashed = 1;
1.8 millert 95: }
1.1 etheisen 96: ob = obuf;
97: }
98:
99: /*
100: * Output a character.
101: */
1.10 nicm 102: int
103: putchr(int c)
1.1 etheisen 104: {
1.10 nicm 105: if (need_clr) {
1.1 etheisen 106: need_clr = 0;
107: clear_bot();
108: }
1.5 millert 109: /*
110: * Some versions of flush() write to *ob, so we must flush
111: * when we are still one char from the end of obuf.
112: */
1.10 nicm 113: if (ob >= &obuf[sizeof (obuf)-1])
1.13 ! nicm 114: flush(0);
1.10 nicm 115: *ob++ = (char)c;
1.1 etheisen 116: return (c);
117: }
118:
119: /*
120: * Output a string.
121: */
1.10 nicm 122: void
123: putstr(const char *s)
1.1 etheisen 124: {
125: while (*s != '\0')
1.10 nicm 126: (void) putchr(*s++);
1.1 etheisen 127: }
128:
129:
130: /*
1.5 millert 131: * Convert an integral type to a string.
132: */
1.10 nicm 133: #define TYPE_TO_A_FUNC(funcname, type) \
134: void \
135: funcname(type num, char *buf, size_t len) \
136: { \
137: int neg = (num < 0); \
138: char tbuf[INT_STRLEN_BOUND(num)+2]; \
139: char *s = tbuf + sizeof (tbuf); \
140: if (neg) \
141: num = -num; \
142: *--s = '\0'; \
143: do { \
144: *--s = (num % 10) + '0'; \
145: } while ((num /= 10) != 0); \
146: if (neg) \
147: *--s = '-'; \
148: (void) strlcpy(buf, s, len); \
1.5 millert 149: }
150:
1.10 nicm 151: TYPE_TO_A_FUNC(postoa, off_t)
1.5 millert 152: TYPE_TO_A_FUNC(linenumtoa, LINENUM)
153: TYPE_TO_A_FUNC(inttoa, int)
154:
155: /*
1.1 etheisen 156: * Output an integer in a given radix.
157: */
1.10 nicm 158: static int
159: iprint_int(int num)
1.1 etheisen 160: {
1.5 millert 161: char buf[INT_STRLEN_BOUND(num)];
1.1 etheisen 162:
1.10 nicm 163: inttoa(num, buf, sizeof (buf));
1.5 millert 164: putstr(buf);
165: return (strlen(buf));
166: }
1.1 etheisen 167:
1.5 millert 168: /*
169: * Output a line number in a given radix.
170: */
1.10 nicm 171: static int
172: iprint_linenum(LINENUM num)
1.5 millert 173: {
174: char buf[INT_STRLEN_BOUND(num)];
1.1 etheisen 175:
1.10 nicm 176: linenumtoa(num, buf, sizeof (buf));
1.5 millert 177: putstr(buf);
178: return (strlen(buf));
1.1 etheisen 179: }
180:
181: /*
182: * This function implements printf-like functionality
183: * using a more portable argument list mechanism than printf's.
184: */
1.10 nicm 185: static int
186: less_printf(const char *fmt, PARG *parg)
1.1 etheisen 187: {
1.11 tedu 188: char *s;
189: int col;
1.1 etheisen 190:
191: col = 0;
1.10 nicm 192: while (*fmt != '\0') {
193: if (*fmt != '%') {
194: (void) putchr(*fmt++);
1.1 etheisen 195: col++;
1.10 nicm 196: } else {
1.1 etheisen 197: ++fmt;
1.10 nicm 198: switch (*fmt++) {
1.1 etheisen 199: case 's':
200: s = parg->p_string;
201: parg++;
1.10 nicm 202: while (*s != '\0') {
203: (void) putchr(*s++);
1.1 etheisen 204: col++;
205: }
206: break;
207: case 'd':
1.5 millert 208: col += iprint_int(parg->p_int);
209: parg++;
210: break;
211: case 'n':
212: col += iprint_linenum(parg->p_linenum);
1.1 etheisen 213: parg++;
214: break;
215: }
216: }
217: }
218: return (col);
219: }
220:
221: /*
1.5 millert 222: * Get a RETURN.
223: * If some other non-trivial char is pressed, unget it, so it will
224: * become the next command.
225: */
1.10 nicm 226: void
227: get_return(void)
1.5 millert 228: {
229: int c;
230:
231: c = getchr();
232: if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
233: ungetcc(c);
234: }
235:
236: /*
1.1 etheisen 237: * Output a message in the lower left corner of the screen
238: * and wait for carriage return.
239: */
1.10 nicm 240: void
241: error(const char *fmt, PARG *parg)
1.1 etheisen 242: {
243: int col = 0;
244: static char return_to_continue[] = " (press RETURN)";
245:
246: errmsgs++;
247:
1.10 nicm 248: if (any_display && is_tty) {
1.6 shadchin 249: if (!oldbot)
250: squish_check();
251: at_exit();
1.1 etheisen 252: clear_bot();
1.6 shadchin 253: at_enter(AT_STANDOUT);
1.1 etheisen 254: col += so_s_width;
255: }
256:
1.5 millert 257: col += less_printf(fmt, parg);
1.1 etheisen 258:
1.10 nicm 259: if (!(any_display && is_tty)) {
260: (void) putchr('\n');
1.1 etheisen 261: return;
262: }
263:
264: putstr(return_to_continue);
1.6 shadchin 265: at_exit();
1.10 nicm 266: col += sizeof (return_to_continue) + so_e_width;
1.1 etheisen 267:
1.5 millert 268: get_return();
1.1 etheisen 269: lower_left();
1.10 nicm 270: clear_eol();
1.1 etheisen 271:
272: if (col >= sc_width)
273: /*
274: * Printing the message has probably scrolled the screen.
275: * {{ Unless the terminal doesn't have auto margins,
276: * in which case we just hammered on the right margin. }}
277: */
278: screen_trashed = 1;
279:
1.13 ! nicm 280: flush(0);
1.1 etheisen 281: }
282:
283: static char intr_to_abort[] = "... (interrupt to abort)";
284:
285: /*
286: * Output a message in the lower left corner of the screen
287: * and don't wait for carriage return.
288: * Usually used to warn that we are beginning a potentially
289: * time-consuming operation.
290: */
1.10 nicm 291: void
292: ierror(const char *fmt, PARG *parg)
1.1 etheisen 293: {
1.6 shadchin 294: at_exit();
1.1 etheisen 295: clear_bot();
1.6 shadchin 296: at_enter(AT_STANDOUT);
1.5 millert 297: (void) less_printf(fmt, parg);
1.1 etheisen 298: putstr(intr_to_abort);
1.6 shadchin 299: at_exit();
1.13 ! nicm 300: flush(0);
1.1 etheisen 301: need_clr = 1;
302: }
303:
304: /*
305: * Output a message in the lower left corner of the screen
306: * and return a single-character response.
307: */
1.10 nicm 308: int
309: query(const char *fmt, PARG *parg)
1.1 etheisen 310: {
1.11 tedu 311: int c;
1.1 etheisen 312: int col = 0;
313:
1.5 millert 314: if (any_display && is_tty)
1.1 etheisen 315: clear_bot();
316:
1.5 millert 317: (void) less_printf(fmt, parg);
1.1 etheisen 318: c = getchr();
319:
1.10 nicm 320: if (!(any_display && is_tty)) {
321: (void) putchr('\n');
1.1 etheisen 322: return (c);
323: }
324:
325: lower_left();
326: if (col >= sc_width)
327: screen_trashed = 1;
1.13 ! nicm 328: flush(0);
1.1 etheisen 329:
330: return (c);
331: }