Annotation of src/usr.bin/less/output.c, Revision 1.2
1.1 etheisen 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
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
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
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
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
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
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
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();
1.2 ! etheisen 295: if (c == 'q')
! 296: quit(QUIT_OK);
1.1 etheisen 297: if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
298: ungetcc(c);
299: #endif
300: lower_left();
301:
302: if (col >= sc_width)
303: /*
304: * Printing the message has probably scrolled the screen.
305: * {{ Unless the terminal doesn't have auto margins,
306: * in which case we just hammered on the right margin. }}
307: */
308: screen_trashed = 1;
309:
310: flush();
311: }
312:
313: static char intr_to_abort[] = "... (interrupt to abort)";
314:
315: /*
316: * Output a message in the lower left corner of the screen
317: * and don't wait for carriage return.
318: * Usually used to warn that we are beginning a potentially
319: * time-consuming operation.
320: */
321: public void
322: ierror(fmt, parg)
323: char *fmt;
324: PARG *parg;
325: {
326: clear_bot();
327: so_enter();
328: (void) iprintf(fmt, parg);
329: putstr(intr_to_abort);
330: so_exit();
331: flush();
332: need_clr = 1;
333: }
334:
335: /*
336: * Output a message in the lower left corner of the screen
337: * and return a single-character response.
338: */
339: public int
340: query(fmt, parg)
341: char *fmt;
342: PARG *parg;
343: {
344: register int c;
345: int col = 0;
346:
347: if (any_display)
348: clear_bot();
349:
350: (void) iprintf(fmt, parg);
351: c = getchr();
352:
353: if (!any_display)
354: {
355: putchr('\n');
356: return (c);
357: }
358:
359: lower_left();
360: if (col >= sc_width)
361: screen_trashed = 1;
362: flush();
363:
364: return (c);
365: }