1 /* $OpenBSD: output.c,v 1.3 2001/01/29 01:58:03 niklas Exp $ */ 2 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(); 297 if (c == 'q') 298 quit(QUIT_OK); 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 } 368