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