Updated docs/README-ATTACHMENTS, mainly to reflect that no setup is
[mmh] / docs / historical / mh-6.8.5 / miscellany / less-177 / output.c
1 /*
2  * High level routines dealing with the output to the screen.
3  */
4
5 #include "less.h"
6
7 public int errmsgs;     /* Count of messages displayed by error() */
8 public int need_clr;
9
10 extern int sigs;
11 extern int sc_width;
12 extern int so_s_width, so_e_width;
13 extern int screen_trashed;
14 extern int any_display;
15 #if __MSDOS__
16 extern int output_mode;
17 #endif
18
19 /*
20  * Display the line which is in the line buffer.
21  */
22         public void
23 put_line()
24 {
25         register int c;
26         register int i;
27         int a;
28         int curr_attr;
29
30         if (sigs)
31         {
32                 /*
33                  * Don't output if a signal is pending.
34                  */
35                 screen_trashed = 1;
36                 return;
37         }
38
39         curr_attr = NORMAL;
40
41         for (i = 0;  (c = gline(i, &a)) != '\0';  i++)
42         {
43                 if (a != curr_attr)
44                 {
45                         /*
46                          * Changing attributes.
47                          * Display the exit sequence for the old attribute
48                          * and the enter sequence for the new one.
49                          */
50                         switch (curr_attr)
51                         {
52                         case UNDERLINE: ul_exit();      break;
53                         case BOLD:      bo_exit();      break;
54                         case BLINK:     bl_exit();      break;
55                         }
56                         switch (a)
57                         {
58                         case UNDERLINE: ul_enter();     break;
59                         case BOLD:      bo_enter();     break;
60                         case BLINK:     bl_enter();     break;
61                         }
62                         curr_attr = a;
63                 }
64                 if (curr_attr == INVIS)
65                         continue;
66                 if (c == '\b')
67                         putbs();
68                 else
69                         putchr(c);
70         }
71 }
72
73 static char obuf[1024];
74 static char *ob = obuf;
75
76 /*
77  * Flush buffered output.
78  *
79  * If we haven't displayed any file data yet,
80  * output messages on error output (file descriptor 2),
81  * otherwise output on standard output (file descriptor 1).
82  *
83  * This has the desirable effect of producing all
84  * error messages on error output if standard output
85  * is directed to a file.  It also does the same if
86  * we never produce any real output; for example, if
87  * the input file(s) cannot be opened.  If we do
88  * eventually produce output, code in edit() makes
89  * sure these messages can be seen before they are
90  * overwritten or scrolled away.
91  */
92         public void
93 flush()
94 {
95         register int n;
96         register int fd;
97
98 #if __MSDOS__
99         if (output_mode == 0)
100         {
101                 *ob = '\0';
102                 cputs(obuf);
103                 ob = obuf;
104                 return;
105         }
106 #endif
107         n = ob - obuf;
108         if (n == 0)
109                 return;
110         fd = (any_display) ? 1 : 2;
111         if (write(fd, obuf, n) != n)
112                 screen_trashed = 1;
113         ob = obuf;
114 }
115
116 /*
117  * Output a character.
118  */
119         public void
120 putchr(c)
121         int c;
122 {
123         if (ob >= &obuf[sizeof(obuf)])
124                 flush();
125         if (need_clr)
126         {
127                 need_clr = 0;
128                 lower_left();
129                 clear_eol();
130         }
131 #if __MSDOS__
132         if (c == '\n')
133                 *ob++ = '\r';
134 #endif
135         *ob++ = c;
136 }
137
138 /*
139  * Output a string.
140  */
141         public void
142 putstr(s)
143         register char *s;
144 {
145         while (*s != '\0')
146                 putchr(*s++);
147 }
148
149
150 /*
151  * Output an integer in a given radix.
152  */
153         static int
154 iprintnum(num, radix)
155         int num;
156         int radix;
157 {
158         register char *s;
159         int r;
160         int neg;
161         char buf[10];
162
163         if (neg = (num < 0))
164                 num = -num;
165
166         s = buf;
167         do
168         {
169                 *s++ = (num % radix) + '0';
170         } while ((num /= radix) != 0);
171
172         if (neg)
173                 *s++ = '-';
174         r = s - buf;
175
176         while (s > buf)
177                 putchr(*--s);
178         return (r);
179 }
180
181 /*
182  * This function implements printf-like functionality
183  * using a more portable argument list mechanism than printf's.
184  */
185         static int
186 iprintf(fmt, parg)
187         register char *fmt;
188         PARG *parg;
189 {
190         register char *s;
191         register int n;
192         register int col;
193
194         col = 0;
195         while (*fmt != '\0')
196         {
197                 if (*fmt != '%')
198                 {
199                         putchr(*fmt++);
200                         col++;
201                 } else
202                 {
203                         ++fmt;
204                         switch (*fmt++) {
205                         case 's':
206                                 s = parg->p_string;
207                                 parg++;
208                                 while (*s != '\0')
209                                 {
210                                         putchr(*s++);
211                                         col++;
212                                 }
213                                 break;
214                         case 'd':
215                                 n = parg->p_int;
216                                 parg++;
217                                 col += iprintnum(n, 10);
218                                 break;
219                         }
220                 }
221         }
222         return (col);
223 }
224
225 /*
226  * Output a message in the lower left corner of the screen
227  * and wait for carriage return.
228  */
229         public void
230 error(fmt, parg)
231         char *fmt;
232         PARG *parg;
233 {
234         int c;
235         int col = 0;
236         static char return_to_continue[] = "  (press RETURN)";
237
238         errmsgs++;
239
240         if (any_display)
241         {
242                 lower_left();
243                 clear_eol();
244                 so_enter();
245                 col += so_s_width;
246         }
247
248         col += iprintf(fmt, parg);
249
250         if (!any_display)
251         {
252                 putchr('\n');
253                 return;
254         }
255
256         putstr(return_to_continue);
257         so_exit();
258         col += sizeof(return_to_continue) + so_e_width;
259
260 #if ONLY_RETURN
261         while ((c = getchr()) != '\n' && c != '\r')
262                 bell();
263 #else
264         c = getchr();
265         if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
266                 ungetcc(c);
267 #endif
268         lower_left();
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
278         flush();
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  */
289         public void
290 ierror(fmt, parg)
291         char *fmt;
292         PARG *parg;
293 {
294         lower_left();
295         clear_eol();
296         so_enter();
297         (void) iprintf(fmt, parg);
298         putstr(intr_to_abort);
299         so_exit();
300         flush();
301         need_clr = 1;
302 }
303
304 /*
305  * Output a message in the lower left corner of the screen
306  * and return a single-character response.
307  */
308         public int
309 query(fmt, parg)
310         char *fmt;
311         PARG *parg;
312 {
313         register int c;
314         int col = 0;
315
316         if (any_display)
317         {
318                 lower_left();
319                 clear_eol();
320         }
321
322         (void) iprintf(fmt, parg);
323         c = getchr();
324
325         if (!any_display)
326         {
327                 putchr('\n');
328                 return (c);
329         }
330
331         lower_left();
332         if (col >= sc_width)
333                 screen_trashed = 1;
334         flush();
335
336         return (c);
337 }