Unleashed v1.4
[unleashed.git] / bin / less / output.c
blobbafe48b8146884ac0cf2860a1b51a46bdc94656b
1 /*
2 * Copyright (C) 1984-2012 Mark Nudelman
3 * Modified for use with illumos by Garrett D'Amore.
4 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
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.
9 * For more information, see the README file.
13 * High level routines dealing with the output to the screen.
16 #include "less.h"
18 int errmsgs; /* Count of messages displayed by error() */
20 extern volatile sig_atomic_t sigs;
21 extern int sc_width;
22 extern int so_s_width, so_e_width;
23 extern int screen_trashed;
24 extern int any_display;
25 extern int is_tty;
26 extern int oldbot;
28 static int need_clr;
31 * Display the line which is in the line buffer.
33 void
34 put_line(void)
36 int c;
37 int i;
38 int a;
40 if (ABORT_SIGS()) {
42 * Don't output if a signal is pending.
44 screen_trashed = 1;
45 return;
48 for (i = 0; (c = gline(i, &a)) != '\0'; i++) {
49 at_switch(a);
50 if (c == '\b')
51 putbs();
52 else
53 (void) putchr(c);
56 at_exit();
59 static char obuf[OUTBUF_SIZE];
60 static char *ob = obuf;
63 * Flush buffered output.
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).
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.
78 void
79 flush(int ignore_errors)
81 int n;
82 int fd;
83 ssize_t nwritten;
85 n = (intptr_t)ob - (intptr_t)obuf;
86 if (n == 0)
87 return;
89 fd = (any_display) ? STDOUT_FILENO : STDERR_FILENO;
90 nwritten = write(fd, obuf, n);
91 if (nwritten != n) {
92 if (nwritten == -1 && !ignore_errors)
93 quit(QUIT_ERROR);
94 screen_trashed = 1;
96 ob = obuf;
100 * Output a character.
103 putchr(int c)
105 if (need_clr) {
106 need_clr = 0;
107 clear_bot();
110 * Some versions of flush() write to *ob, so we must flush
111 * when we are still one char from the end of obuf.
113 if (ob >= &obuf[sizeof (obuf)-1])
114 flush(0);
115 *ob++ = (char)c;
116 return (c);
120 * Output a string.
122 void
123 putstr(const char *s)
125 while (*s != '\0')
126 (void) putchr(*s++);
131 * Convert an integral type to a string.
133 #define TYPE_TO_A_FUNC(funcname, type) \
134 void \
135 funcname(type num, char *buf, size_t len) \
137 int neg = (num < 0); \
138 char tbuf[23]; \
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); \
151 TYPE_TO_A_FUNC(postoa, off_t)
152 TYPE_TO_A_FUNC(inttoa, int)
155 * Output an integer in a given radix.
157 static int
158 iprint_int(int num)
160 char buf[11];
162 inttoa(num, buf, sizeof (buf));
163 putstr(buf);
164 return (strlen(buf));
168 * Output a line number in a given radix.
170 static int
171 iprint_linenum(off_t num)
173 char buf[21];
175 postoa(num, buf, sizeof(buf));
176 putstr(buf);
177 return (strlen(buf));
181 * This function implements printf-like functionality
182 * using a more portable argument list mechanism than printf's.
184 static int
185 less_printf(const char *fmt, PARG *parg)
187 char *s;
188 int col;
190 col = 0;
191 while (*fmt != '\0') {
192 if (*fmt != '%') {
193 (void) putchr(*fmt++);
194 col++;
195 } else {
196 ++fmt;
197 switch (*fmt++) {
198 case 's':
199 s = parg->p_string;
200 parg++;
201 while (*s != '\0') {
202 (void) putchr(*s++);
203 col++;
205 break;
206 case 'd':
207 col += iprint_int(parg->p_int);
208 parg++;
209 break;
210 case 'n':
211 col += iprint_linenum(parg->p_linenum);
212 parg++;
213 break;
217 return (col);
221 * Get a RETURN.
222 * If some other non-trivial char is pressed, unget it, so it will
223 * become the next command.
225 void
226 get_return(void)
228 int c;
230 c = getchr();
231 if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
232 ungetcc(c);
236 * Output a message in the lower left corner of the screen
237 * and wait for carriage return.
239 void
240 error(const char *fmt, PARG *parg)
242 int col = 0;
243 static char return_to_continue[] = " (press RETURN)";
245 errmsgs++;
247 if (any_display && is_tty) {
248 if (!oldbot)
249 squish_check();
250 at_exit();
251 clear_bot();
252 at_enter(AT_STANDOUT);
253 col += so_s_width;
256 col += less_printf(fmt, parg);
258 if (!(any_display && is_tty)) {
259 (void) putchr('\n');
260 return;
263 putstr(return_to_continue);
264 at_exit();
265 col += sizeof (return_to_continue) + so_e_width;
267 get_return();
268 lower_left();
269 clear_eol();
271 if (col >= sc_width)
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. }}
277 screen_trashed = 1;
279 flush(0);
282 static char intr_to_abort[] = "... (interrupt to abort)";
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.
290 void
291 ierror(const char *fmt, PARG *parg)
293 at_exit();
294 clear_bot();
295 at_enter(AT_STANDOUT);
296 (void) less_printf(fmt, parg);
297 putstr(intr_to_abort);
298 at_exit();
299 flush(0);
300 need_clr = 1;
304 * Output a message in the lower left corner of the screen
305 * and return a single-character response.
308 query(const char *fmt, PARG *parg)
310 int c;
311 int col = 0;
313 if (any_display && is_tty)
314 clear_bot();
316 (void) less_printf(fmt, parg);
317 c = getchr();
319 if (!(any_display && is_tty)) {
320 (void) putchr('\n');
321 return (c);
324 lower_left();
325 if (col >= sc_width)
326 screen_trashed = 1;
327 flush(0);
329 return (c);