Annotation of src/usr.bin/less/output.c, Revision 1.17
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.17 ! deraadt 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); \
1.16 mmcc 138: char tbuf[23]; \
1.10 nicm 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(inttoa, int)
153:
154: /*
1.1 etheisen 155: * Output an integer in a given radix.
156: */
1.10 nicm 157: static int
158: iprint_int(int num)
1.1 etheisen 159: {
1.16 mmcc 160: char buf[11];
1.1 etheisen 161:
1.10 nicm 162: inttoa(num, buf, sizeof (buf));
1.5 millert 163: putstr(buf);
164: return (strlen(buf));
165: }
1.1 etheisen 166:
1.5 millert 167: /*
168: * Output a line number in a given radix.
169: */
1.10 nicm 170: static int
1.14 mmcc 171: iprint_linenum(off_t num)
1.5 millert 172: {
1.16 mmcc 173: char buf[21];
1.1 etheisen 174:
1.15 mmcc 175: postoa(num, buf, sizeof(buf));
1.5 millert 176: putstr(buf);
177: return (strlen(buf));
1.1 etheisen 178: }
179:
180: /*
181: * This function implements printf-like functionality
182: * using a more portable argument list mechanism than printf's.
183: */
1.10 nicm 184: static int
185: less_printf(const char *fmt, PARG *parg)
1.1 etheisen 186: {
1.11 tedu 187: char *s;
188: int col;
1.1 etheisen 189:
190: col = 0;
1.10 nicm 191: while (*fmt != '\0') {
192: if (*fmt != '%') {
193: (void) putchr(*fmt++);
1.1 etheisen 194: col++;
1.10 nicm 195: } else {
1.1 etheisen 196: ++fmt;
1.10 nicm 197: switch (*fmt++) {
1.1 etheisen 198: case 's':
199: s = parg->p_string;
200: parg++;
1.10 nicm 201: while (*s != '\0') {
202: (void) putchr(*s++);
1.1 etheisen 203: col++;
204: }
205: break;
206: case 'd':
1.5 millert 207: col += iprint_int(parg->p_int);
208: parg++;
209: break;
210: case 'n':
211: col += iprint_linenum(parg->p_linenum);
1.1 etheisen 212: parg++;
213: break;
214: }
215: }
216: }
217: return (col);
218: }
219:
220: /*
1.5 millert 221: * Get a RETURN.
222: * If some other non-trivial char is pressed, unget it, so it will
223: * become the next command.
224: */
1.10 nicm 225: void
226: get_return(void)
1.5 millert 227: {
228: int c;
229:
230: c = getchr();
231: if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
232: ungetcc(c);
233: }
234:
235: /*
1.1 etheisen 236: * Output a message in the lower left corner of the screen
237: * and wait for carriage return.
238: */
1.10 nicm 239: void
240: error(const char *fmt, PARG *parg)
1.1 etheisen 241: {
242: int col = 0;
243: static char return_to_continue[] = " (press RETURN)";
244:
245: errmsgs++;
246:
1.10 nicm 247: if (any_display && is_tty) {
1.6 shadchin 248: if (!oldbot)
249: squish_check();
250: at_exit();
1.1 etheisen 251: clear_bot();
1.6 shadchin 252: at_enter(AT_STANDOUT);
1.1 etheisen 253: col += so_s_width;
254: }
255:
1.5 millert 256: col += less_printf(fmt, parg);
1.1 etheisen 257:
1.10 nicm 258: if (!(any_display && is_tty)) {
259: (void) putchr('\n');
1.1 etheisen 260: return;
261: }
262:
263: putstr(return_to_continue);
1.6 shadchin 264: at_exit();
1.10 nicm 265: col += sizeof (return_to_continue) + so_e_width;
1.1 etheisen 266:
1.5 millert 267: get_return();
1.1 etheisen 268: lower_left();
1.10 nicm 269: clear_eol();
1.1 etheisen 270:
271: if (col >= sc_width)
272: /*
273: * Printing the message has probably scrolled the screen.
274: * {{ Unless the terminal doesn't have auto margins,
275: * in which case we just hammered on the right margin. }}
276: */
277: screen_trashed = 1;
278:
1.13 nicm 279: flush(0);
1.1 etheisen 280: }
281:
282: static char intr_to_abort[] = "... (interrupt to abort)";
283:
284: /*
285: * Output a message in the lower left corner of the screen
286: * and don't wait for carriage return.
287: * Usually used to warn that we are beginning a potentially
288: * time-consuming operation.
289: */
1.10 nicm 290: void
291: ierror(const char *fmt, PARG *parg)
1.1 etheisen 292: {
1.6 shadchin 293: at_exit();
1.1 etheisen 294: clear_bot();
1.6 shadchin 295: at_enter(AT_STANDOUT);
1.5 millert 296: (void) less_printf(fmt, parg);
1.1 etheisen 297: putstr(intr_to_abort);
1.6 shadchin 298: at_exit();
1.13 nicm 299: flush(0);
1.1 etheisen 300: need_clr = 1;
301: }
302:
303: /*
304: * Output a message in the lower left corner of the screen
305: * and return a single-character response.
306: */
1.10 nicm 307: int
308: query(const char *fmt, PARG *parg)
1.1 etheisen 309: {
1.11 tedu 310: int c;
1.1 etheisen 311: int col = 0;
312:
1.5 millert 313: if (any_display && is_tty)
1.1 etheisen 314: clear_bot();
315:
1.5 millert 316: (void) less_printf(fmt, parg);
1.1 etheisen 317: c = getchr();
318:
1.10 nicm 319: if (!(any_display && is_tty)) {
320: (void) putchr('\n');
1.1 etheisen 321: return (c);
322: }
323:
324: lower_left();
325: if (col >= sc_width)
326: screen_trashed = 1;
1.13 nicm 327: flush(0);
1.1 etheisen 328:
329: return (c);
330: }