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