1 /*
2 * Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice in the documentation and/or other materials provided with
12 * the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
20 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
21 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
23 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27
28 /*
29 * High level routines dealing with the output to the screen.
30 */
31
32 #include "less.h"
33
34 public int errmsgs; /* Count of messages displayed by error() */
35 public int need_clr;
36
37 extern int sigs;
38 extern int sc_width;
39 extern int so_s_width, so_e_width;
40 extern int screen_trashed;
41 extern int any_display;
42
43 /*
44 * Display the line which is in the line buffer.
45 */
46 public void
put_line()47 put_line()
48 {
49 register int c;
50 register int i;
51 int a;
52 int curr_attr;
53
54 if (ABORT_SIGS())
55 {
56 /*
57 * Don't output if a signal is pending.
58 */
59 screen_trashed = 1;
60 return;
61 }
62
63 curr_attr = AT_NORMAL;
64
65 for (i = 0; (c = gline(i, &a)) != '\0'; i++)
66 {
67 if (a != curr_attr)
68 {
69 /*
70 * Changing attributes.
71 * Display the exit sequence for the old attribute
72 * and the enter sequence for the new one.
73 */
74 switch (curr_attr)
75 {
76 case AT_UNDERLINE: ul_exit(); break;
77 case AT_BOLD: bo_exit(); break;
78 case AT_BLINK: bl_exit(); break;
79 case AT_STANDOUT: so_exit(); break;
80 }
81 switch (a)
82 {
83 case AT_UNDERLINE: ul_enter(); break;
84 case AT_BOLD: bo_enter(); break;
85 case AT_BLINK: bl_enter(); break;
86 case AT_STANDOUT: so_enter(); break;
87 }
88 curr_attr = a;
89 }
90 if (curr_attr == AT_INVIS)
91 continue;
92 if (c == '\b')
93 putbs();
94 else
95 putchr(c);
96 }
97
98 switch (curr_attr)
99 {
100 case AT_UNDERLINE: ul_exit(); break;
101 case AT_BOLD: bo_exit(); break;
102 case AT_BLINK: bl_exit(); break;
103 case AT_STANDOUT: so_exit(); break;
104 }
105 }
106
107 static char obuf[1024];
108 static char *ob = obuf;
109
110 /*
111 * Flush buffered output.
112 *
113 * If we haven't displayed any file data yet,
114 * output messages on error output (file descriptor 2),
115 * otherwise output on standard output (file descriptor 1).
116 *
117 * This has the desirable effect of producing all
118 * error messages on error output if standard output
119 * is directed to a file. It also does the same if
120 * we never produce any real output; for example, if
121 * the input file(s) cannot be opened. If we do
122 * eventually produce output, code in edit() makes
123 * sure these messages can be seen before they are
124 * overwritten or scrolled away.
125 */
126 public void
flush()127 flush()
128 {
129 register int n;
130 register int fd;
131
132 #if MSOFTC
133 *ob = '\0';
134 _outtext(obuf);
135 ob = obuf;
136 #else
137 n = ob - obuf;
138 if (n == 0)
139 return;
140 fd = (any_display) ? 1 : 2;
141 if (write(fd, obuf, n) != n)
142 screen_trashed = 1;
143 ob = obuf;
144 #endif
145 }
146
147 /*
148 * Output a character.
149 */
150 public int
putchr(c)151 putchr(c)
152 int c;
153 {
154 if (ob >= &obuf[sizeof(obuf)])
155 flush();
156 if (need_clr)
157 {
158 need_clr = 0;
159 clear_bot();
160 }
161 #if MSOFTC
162 if (c == '\n')
163 putchr('\r');
164 #endif
165 *ob++ = c;
166 return (c);
167 }
168
169 /*
170 * Output a string.
171 */
172 public void
putstr(s)173 putstr(s)
174 register char *s;
175 {
176 while (*s != '\0')
177 putchr(*s++);
178 }
179
180
181 /*
182 * Output an integer in a given radix.
183 */
184 static int
iprintnum(num,radix)185 iprintnum(num, radix)
186 int num;
187 int radix;
188 {
189 register char *s;
190 int r;
191 int neg;
192 char buf[10];
193
194 if (neg = (num < 0))
195 num = -num;
196
197 s = buf;
198 do
199 {
200 *s++ = (num % radix) + '0';
201 } while ((num /= radix) != 0);
202
203 if (neg)
204 *s++ = '-';
205 r = s - buf;
206
207 while (s > buf)
208 putchr(*--s);
209 return (r);
210 }
211
212 /*
213 * This function implements printf-like functionality
214 * using a more portable argument list mechanism than printf's.
215 */
216 static int
iprintf(fmt,parg)217 iprintf(fmt, parg)
218 register char *fmt;
219 PARG *parg;
220 {
221 register char *s;
222 register int n;
223 register int col;
224
225 col = 0;
226 while (*fmt != '\0')
227 {
228 if (*fmt != '%')
229 {
230 putchr(*fmt++);
231 col++;
232 } else
233 {
234 ++fmt;
235 switch (*fmt++) {
236 case 's':
237 s = parg->p_string;
238 parg++;
239 while (*s != '\0')
240 {
241 putchr(*s++);
242 col++;
243 }
244 break;
245 case 'd':
246 n = parg->p_int;
247 parg++;
248 col += iprintnum(n, 10);
249 break;
250 }
251 }
252 }
253 return (col);
254 }
255
256 /*
257 * Output a message in the lower left corner of the screen
258 * and wait for carriage return.
259 */
260 public void
error(fmt,parg)261 error(fmt, parg)
262 char *fmt;
263 PARG *parg;
264 {
265 int c;
266 int col = 0;
267 static char return_to_continue[] = " (press RETURN)";
268
269 errmsgs++;
270
271 if (any_display)
272 {
273 clear_bot();
274 so_enter();
275 col += so_s_width;
276 }
277
278 col += iprintf(fmt, parg);
279
280 if (!any_display)
281 {
282 putchr('\n');
283 return;
284 }
285
286 putstr(return_to_continue);
287 so_exit();
288 col += sizeof(return_to_continue) + so_e_width;
289
290 #if ONLY_RETURN
291 while ((c = getchr()) != '\n' && c != '\r')
292 bell();
293 #else
294 c = getchr();
295 if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
296 ungetcc(c);
297 #endif
298 lower_left();
299
300 if (col >= sc_width)
301 /*
302 * Printing the message has probably scrolled the screen.
303 * {{ Unless the terminal doesn't have auto margins,
304 * in which case we just hammered on the right margin. }}
305 */
306 screen_trashed = 1;
307
308 flush();
309 }
310
311 static char intr_to_abort[] = "... (interrupt to abort)";
312
313 /*
314 * Output a message in the lower left corner of the screen
315 * and don't wait for carriage return.
316 * Usually used to warn that we are beginning a potentially
317 * time-consuming operation.
318 */
319 public void
ierror(fmt,parg)320 ierror(fmt, parg)
321 char *fmt;
322 PARG *parg;
323 {
324 clear_bot();
325 so_enter();
326 (void) iprintf(fmt, parg);
327 putstr(intr_to_abort);
328 so_exit();
329 flush();
330 need_clr = 1;
331 }
332
333 /*
334 * Output a message in the lower left corner of the screen
335 * and return a single-character response.
336 */
337 public int
query(fmt,parg)338 query(fmt, parg)
339 char *fmt;
340 PARG *parg;
341 {
342 register int c;
343 int col = 0;
344
345 if (any_display)
346 clear_bot();
347
348 (void) iprintf(fmt, parg);
349 c = getchr();
350
351 if (!any_display)
352 {
353 putchr('\n');
354 return (c);
355 }
356
357 lower_left();
358 if (col >= sc_width)
359 screen_trashed = 1;
360 flush();
361
362 return (c);
363 }
364