1 1.5 simonb /* $NetBSD: output.c,v 1.5 2023/10/06 05:49:49 simonb Exp $ */ 2 1.1 tron 3 1.1 tron /* 4 1.5 simonb * Copyright (C) 1984-2023 Mark Nudelman 5 1.1 tron * 6 1.1 tron * You may distribute under the terms of either the GNU General Public 7 1.1 tron * License or the Less License, as specified in the README file. 8 1.1 tron * 9 1.4 tron * For more information, see the README file. 10 1.1 tron */ 11 1.1 tron 12 1.1 tron 13 1.1 tron /* 14 1.1 tron * High level routines dealing with the output to the screen. 15 1.1 tron */ 16 1.1 tron 17 1.1 tron #include "less.h" 18 1.1 tron #if MSDOS_COMPILER==WIN32C 19 1.1 tron #include "windows.h" 20 1.5 simonb #ifndef COMMON_LVB_UNDERSCORE 21 1.5 simonb #define COMMON_LVB_UNDERSCORE 0x8000 22 1.5 simonb #endif 23 1.1 tron #endif 24 1.1 tron 25 1.5 simonb public int errmsgs; /* Count of messages displayed by error() */ 26 1.1 tron public int need_clr; 27 1.1 tron public int final_attr; 28 1.1 tron public int at_prompt; 29 1.1 tron 30 1.1 tron extern int sigs; 31 1.1 tron extern int sc_width; 32 1.1 tron extern int so_s_width, so_e_width; 33 1.1 tron extern int screen_trashed; 34 1.1 tron extern int is_tty; 35 1.1 tron extern int oldbot; 36 1.5 simonb extern char intr_char; 37 1.1 tron 38 1.1 tron #if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 39 1.1 tron extern int ctldisp; 40 1.1 tron extern int nm_fg_color, nm_bg_color; 41 1.1 tron extern int bo_fg_color, bo_bg_color; 42 1.1 tron extern int ul_fg_color, ul_bg_color; 43 1.1 tron extern int so_fg_color, so_bg_color; 44 1.1 tron extern int bl_fg_color, bl_bg_color; 45 1.5 simonb extern int sgr_mode; 46 1.5 simonb #if MSDOS_COMPILER==WIN32C 47 1.5 simonb extern int vt_enabled; 48 1.5 simonb #endif 49 1.1 tron #endif 50 1.1 tron 51 1.1 tron /* 52 1.1 tron * Display the line which is in the line buffer. 53 1.1 tron */ 54 1.5 simonb public void put_line(void) 55 1.1 tron { 56 1.5 simonb int c; 57 1.5 simonb int i; 58 1.1 tron int a; 59 1.1 tron 60 1.1 tron if (ABORT_SIGS()) 61 1.1 tron { 62 1.1 tron /* 63 1.1 tron * Don't output if a signal is pending. 64 1.1 tron */ 65 1.1 tron screen_trashed = 1; 66 1.1 tron return; 67 1.1 tron } 68 1.1 tron 69 1.1 tron final_attr = AT_NORMAL; 70 1.1 tron 71 1.1 tron for (i = 0; (c = gline(i, &a)) != '\0'; i++) 72 1.1 tron { 73 1.1 tron at_switch(a); 74 1.1 tron final_attr = a; 75 1.1 tron if (c == '\b') 76 1.1 tron putbs(); 77 1.1 tron else 78 1.1 tron putchr(c); 79 1.1 tron } 80 1.1 tron 81 1.1 tron at_exit(); 82 1.1 tron } 83 1.1 tron 84 1.1 tron static char obuf[OUTBUF_SIZE]; 85 1.1 tron static char *ob = obuf; 86 1.5 simonb static int outfd = 2; /* stderr */ 87 1.5 simonb 88 1.5 simonb #if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 89 1.5 simonb static void win_flush(void) 90 1.5 simonb { 91 1.5 simonb if (ctldisp != OPT_ONPLUS || (vt_enabled && sgr_mode)) 92 1.5 simonb WIN32textout(obuf, ob - obuf); 93 1.5 simonb else 94 1.5 simonb { 95 1.5 simonb /* 96 1.5 simonb * Look for SGR escape sequences, and convert them 97 1.5 simonb * to color commands. Replace bold, underline, 98 1.5 simonb * and italic escapes into colors specified via 99 1.5 simonb * the -D command-line option. 100 1.5 simonb */ 101 1.5 simonb char *anchor, *p, *p_next; 102 1.5 simonb static int fg, fgi, bg, bgi; 103 1.5 simonb static int at; 104 1.5 simonb int f, b; 105 1.5 simonb #if MSDOS_COMPILER==WIN32C 106 1.5 simonb /* Screen colors used by 3x and 4x SGR commands. */ 107 1.5 simonb static unsigned char screen_color[] = { 108 1.5 simonb 0, /* BLACK */ 109 1.5 simonb FOREGROUND_RED, 110 1.5 simonb FOREGROUND_GREEN, 111 1.5 simonb FOREGROUND_RED|FOREGROUND_GREEN, 112 1.5 simonb FOREGROUND_BLUE, 113 1.5 simonb FOREGROUND_BLUE|FOREGROUND_RED, 114 1.5 simonb FOREGROUND_BLUE|FOREGROUND_GREEN, 115 1.5 simonb FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED 116 1.5 simonb }; 117 1.5 simonb #else 118 1.5 simonb static enum COLORS screen_color[] = { 119 1.5 simonb BLACK, RED, GREEN, BROWN, 120 1.5 simonb BLUE, MAGENTA, CYAN, LIGHTGRAY 121 1.5 simonb }; 122 1.5 simonb #endif 123 1.5 simonb 124 1.5 simonb if (fg == 0 && bg == 0) 125 1.5 simonb { 126 1.5 simonb fg = nm_fg_color & 7; 127 1.5 simonb fgi = nm_fg_color & 8; 128 1.5 simonb bg = nm_bg_color & 7; 129 1.5 simonb bgi = nm_bg_color & 8; 130 1.5 simonb } 131 1.5 simonb for (anchor = p_next = obuf; 132 1.5 simonb (p_next = memchr(p_next, ESC, ob - p_next)) != NULL; ) 133 1.5 simonb { 134 1.5 simonb p = p_next; 135 1.5 simonb if (p[1] == '[') /* "ESC-[" sequence */ 136 1.5 simonb { 137 1.5 simonb if (p > anchor) 138 1.5 simonb { 139 1.5 simonb /* 140 1.5 simonb * If some chars seen since 141 1.5 simonb * the last escape sequence, 142 1.5 simonb * write them out to the screen. 143 1.5 simonb */ 144 1.5 simonb WIN32textout(anchor, p-anchor); 145 1.5 simonb anchor = p; 146 1.5 simonb } 147 1.5 simonb p += 2; /* Skip the "ESC-[" */ 148 1.5 simonb if (is_ansi_end(*p)) 149 1.5 simonb { 150 1.5 simonb /* 151 1.5 simonb * Handle null escape sequence 152 1.5 simonb * "ESC[m", which restores 153 1.5 simonb * the normal color. 154 1.5 simonb */ 155 1.5 simonb p++; 156 1.5 simonb anchor = p_next = p; 157 1.5 simonb fg = nm_fg_color & 7; 158 1.5 simonb fgi = nm_fg_color & 8; 159 1.5 simonb bg = nm_bg_color & 7; 160 1.5 simonb bgi = nm_bg_color & 8; 161 1.5 simonb at = 0; 162 1.5 simonb WIN32setcolors(nm_fg_color, nm_bg_color); 163 1.5 simonb continue; 164 1.5 simonb } 165 1.5 simonb p_next = p; 166 1.5 simonb at &= ~32; 167 1.5 simonb 168 1.5 simonb /* 169 1.5 simonb * Select foreground/background colors 170 1.5 simonb * based on the escape sequence. 171 1.5 simonb */ 172 1.5 simonb while (!is_ansi_end(*p)) 173 1.5 simonb { 174 1.5 simonb char *q; 175 1.5 simonb long code = strtol(p, &q, 10); 176 1.5 simonb 177 1.5 simonb if (*q == '\0') 178 1.5 simonb { 179 1.5 simonb /* 180 1.5 simonb * Incomplete sequence. 181 1.5 simonb * Leave it unprocessed 182 1.5 simonb * in the buffer. 183 1.5 simonb */ 184 1.5 simonb int slop = (int) (q - anchor); 185 1.5 simonb /* {{ strcpy args overlap! }} */ 186 1.5 simonb strcpy(obuf, anchor); 187 1.5 simonb ob = &obuf[slop]; 188 1.5 simonb return; 189 1.5 simonb } 190 1.5 simonb 191 1.5 simonb if (q == p || 192 1.5 simonb code > 49 || code < 0 || 193 1.5 simonb (!is_ansi_end(*q) && *q != ';')) 194 1.5 simonb { 195 1.5 simonb p_next = q; 196 1.5 simonb break; 197 1.5 simonb } 198 1.5 simonb if (*q == ';') 199 1.5 simonb { 200 1.5 simonb q++; 201 1.5 simonb at |= 32; 202 1.5 simonb } 203 1.5 simonb 204 1.5 simonb switch (code) 205 1.5 simonb { 206 1.5 simonb default: 207 1.5 simonb /* case 0: all attrs off */ 208 1.5 simonb fg = nm_fg_color & 7; 209 1.5 simonb bg = nm_bg_color & 7; 210 1.5 simonb at &= 32; 211 1.5 simonb /* 212 1.5 simonb * \e[0m use normal 213 1.5 simonb * intensities, but 214 1.5 simonb * \e[0;...m resets them 215 1.5 simonb */ 216 1.5 simonb if (at & 32) 217 1.5 simonb { 218 1.5 simonb fgi = 0; 219 1.5 simonb bgi = 0; 220 1.5 simonb } else 221 1.5 simonb { 222 1.5 simonb fgi = nm_fg_color & 8; 223 1.5 simonb bgi = nm_bg_color & 8; 224 1.5 simonb } 225 1.5 simonb break; 226 1.5 simonb case 1: /* bold on */ 227 1.5 simonb fgi = 8; 228 1.5 simonb at |= 1; 229 1.5 simonb break; 230 1.5 simonb case 3: /* italic on */ 231 1.5 simonb case 7: /* inverse on */ 232 1.5 simonb at |= 2; 233 1.5 simonb break; 234 1.5 simonb case 4: /* underline on */ 235 1.5 simonb bgi = 8; 236 1.5 simonb at |= 4; 237 1.5 simonb break; 238 1.5 simonb case 5: /* slow blink on */ 239 1.5 simonb case 6: /* fast blink on */ 240 1.5 simonb bgi = 8; 241 1.5 simonb at |= 8; 242 1.5 simonb break; 243 1.5 simonb case 8: /* concealed on */ 244 1.5 simonb at |= 16; 245 1.5 simonb break; 246 1.5 simonb case 22: /* bold off */ 247 1.5 simonb fgi = 0; 248 1.5 simonb at &= ~1; 249 1.5 simonb break; 250 1.5 simonb case 23: /* italic off */ 251 1.5 simonb case 27: /* inverse off */ 252 1.5 simonb at &= ~2; 253 1.5 simonb break; 254 1.5 simonb case 24: /* underline off */ 255 1.5 simonb bgi = 0; 256 1.5 simonb at &= ~4; 257 1.5 simonb break; 258 1.5 simonb case 28: /* concealed off */ 259 1.5 simonb at &= ~16; 260 1.5 simonb break; 261 1.5 simonb case 30: case 31: case 32: 262 1.5 simonb case 33: case 34: case 35: 263 1.5 simonb case 36: case 37: 264 1.5 simonb fg = screen_color[code - 30]; 265 1.5 simonb at |= 32; 266 1.5 simonb break; 267 1.5 simonb case 39: /* default fg */ 268 1.5 simonb fg = nm_fg_color & 7; 269 1.5 simonb at |= 32; 270 1.5 simonb break; 271 1.5 simonb case 40: case 41: case 42: 272 1.5 simonb case 43: case 44: case 45: 273 1.5 simonb case 46: case 47: 274 1.5 simonb bg = screen_color[code - 40]; 275 1.5 simonb at |= 32; 276 1.5 simonb break; 277 1.5 simonb case 49: /* default bg */ 278 1.5 simonb bg = nm_bg_color & 7; 279 1.5 simonb at |= 32; 280 1.5 simonb break; 281 1.5 simonb } 282 1.5 simonb p = q; 283 1.5 simonb } 284 1.5 simonb if (!is_ansi_end(*p) || p == p_next) 285 1.5 simonb break; 286 1.5 simonb /* 287 1.5 simonb * In SGR mode, the ANSI sequence is 288 1.5 simonb * always honored; otherwise if an attr 289 1.5 simonb * is used by itself ("\e[1m" versus 290 1.5 simonb * "\e[1;33m", for example), set the 291 1.5 simonb * color assigned to that attribute. 292 1.5 simonb */ 293 1.5 simonb if (sgr_mode || (at & 32)) 294 1.5 simonb { 295 1.5 simonb if (at & 2) 296 1.5 simonb { 297 1.5 simonb f = bg | bgi; 298 1.5 simonb b = fg | fgi; 299 1.5 simonb } else 300 1.5 simonb { 301 1.5 simonb f = fg | fgi; 302 1.5 simonb b = bg | bgi; 303 1.5 simonb } 304 1.5 simonb } else 305 1.5 simonb { 306 1.5 simonb if (at & 1) 307 1.5 simonb { 308 1.5 simonb f = bo_fg_color; 309 1.5 simonb b = bo_bg_color; 310 1.5 simonb } else if (at & 2) 311 1.5 simonb { 312 1.5 simonb f = so_fg_color; 313 1.5 simonb b = so_bg_color; 314 1.5 simonb } else if (at & 4) 315 1.5 simonb { 316 1.5 simonb f = ul_fg_color; 317 1.5 simonb b = ul_bg_color; 318 1.5 simonb } else if (at & 8) 319 1.5 simonb { 320 1.5 simonb f = bl_fg_color; 321 1.5 simonb b = bl_bg_color; 322 1.5 simonb } else 323 1.5 simonb { 324 1.5 simonb f = nm_fg_color; 325 1.5 simonb b = nm_bg_color; 326 1.5 simonb } 327 1.5 simonb } 328 1.5 simonb if (at & 16) 329 1.5 simonb f = b ^ 8; 330 1.5 simonb #if MSDOS_COMPILER==WIN32C 331 1.5 simonb f &= 0xf | COMMON_LVB_UNDERSCORE; 332 1.5 simonb #else 333 1.5 simonb f &= 0xf; 334 1.5 simonb #endif 335 1.5 simonb b &= 0xf; 336 1.5 simonb WIN32setcolors(f, b); 337 1.5 simonb p_next = anchor = p + 1; 338 1.5 simonb } else 339 1.5 simonb p_next++; 340 1.5 simonb } 341 1.5 simonb 342 1.5 simonb /* Output what's left in the buffer. */ 343 1.5 simonb WIN32textout(anchor, ob - anchor); 344 1.5 simonb } 345 1.5 simonb ob = obuf; 346 1.5 simonb } 347 1.5 simonb #endif 348 1.1 tron 349 1.1 tron /* 350 1.1 tron * Flush buffered output. 351 1.1 tron * 352 1.1 tron * If we haven't displayed any file data yet, 353 1.1 tron * output messages on error output (file descriptor 2), 354 1.1 tron * otherwise output on standard output (file descriptor 1). 355 1.1 tron * 356 1.1 tron * This has the desirable effect of producing all 357 1.1 tron * error messages on error output if standard output 358 1.1 tron * is directed to a file. It also does the same if 359 1.1 tron * we never produce any real output; for example, if 360 1.1 tron * the input file(s) cannot be opened. If we do 361 1.1 tron * eventually produce output, code in edit() makes 362 1.1 tron * sure these messages can be seen before they are 363 1.1 tron * overwritten or scrolled away. 364 1.1 tron */ 365 1.5 simonb public void flush(void) 366 1.1 tron { 367 1.5 simonb int n; 368 1.1 tron 369 1.5 simonb n = (int) (ob - obuf); 370 1.1 tron if (n == 0) 371 1.1 tron return; 372 1.5 simonb ob = obuf; 373 1.1 tron 374 1.1 tron #if MSDOS_COMPILER==MSOFTC 375 1.5 simonb if (interactive()) 376 1.1 tron { 377 1.5 simonb obuf[n] = '\0'; 378 1.1 tron _outtext(obuf); 379 1.1 tron return; 380 1.1 tron } 381 1.1 tron #else 382 1.1 tron #if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 383 1.5 simonb if (interactive()) 384 1.1 tron { 385 1.5 simonb ob = obuf + n; 386 1.1 tron *ob = '\0'; 387 1.5 simonb win_flush(); 388 1.1 tron return; 389 1.1 tron } 390 1.1 tron #endif 391 1.1 tron #endif 392 1.5 simonb 393 1.5 simonb if (write(outfd, obuf, n) != n) 394 1.1 tron screen_trashed = 1; 395 1.5 simonb } 396 1.5 simonb 397 1.5 simonb /* 398 1.5 simonb * Set the output file descriptor (1=stdout or 2=stderr). 399 1.5 simonb */ 400 1.5 simonb public void set_output(int fd) 401 1.5 simonb { 402 1.5 simonb flush(); 403 1.5 simonb outfd = fd; 404 1.1 tron } 405 1.1 tron 406 1.1 tron /* 407 1.1 tron * Output a character. 408 1.1 tron */ 409 1.5 simonb public int putchr(int c) 410 1.1 tron { 411 1.1 tron #if 0 /* fake UTF-8 output for testing */ 412 1.1 tron extern int utf_mode; 413 1.1 tron if (utf_mode) 414 1.1 tron { 415 1.1 tron static char ubuf[MAX_UTF_CHAR_LEN]; 416 1.1 tron static int ubuf_len = 0; 417 1.1 tron static int ubuf_index = 0; 418 1.1 tron if (ubuf_len == 0) 419 1.1 tron { 420 1.1 tron ubuf_len = utf_len(c); 421 1.1 tron ubuf_index = 0; 422 1.1 tron } 423 1.1 tron ubuf[ubuf_index++] = c; 424 1.1 tron if (ubuf_index < ubuf_len) 425 1.1 tron return c; 426 1.1 tron c = get_wchar(ubuf) & 0xFF; 427 1.1 tron ubuf_len = 0; 428 1.1 tron } 429 1.1 tron #endif 430 1.5 simonb clear_bot_if_needed(); 431 1.1 tron #if MSDOS_COMPILER 432 1.1 tron if (c == '\n' && is_tty) 433 1.1 tron { 434 1.1 tron /* remove_top(1); */ 435 1.1 tron putchr('\r'); 436 1.1 tron } 437 1.1 tron #else 438 1.1 tron #ifdef _OSK 439 1.1 tron if (c == '\n' && is_tty) /* In OS-9, '\n' == 0x0D */ 440 1.1 tron putchr(0x0A); 441 1.1 tron #endif 442 1.1 tron #endif 443 1.1 tron /* 444 1.1 tron * Some versions of flush() write to *ob, so we must flush 445 1.1 tron * when we are still one char from the end of obuf. 446 1.1 tron */ 447 1.1 tron if (ob >= &obuf[sizeof(obuf)-1]) 448 1.1 tron flush(); 449 1.1 tron *ob++ = c; 450 1.1 tron at_prompt = 0; 451 1.1 tron return (c); 452 1.1 tron } 453 1.1 tron 454 1.5 simonb public void clear_bot_if_needed(void) 455 1.5 simonb { 456 1.5 simonb if (!need_clr) 457 1.5 simonb return; 458 1.5 simonb need_clr = 0; 459 1.5 simonb clear_bot(); 460 1.5 simonb } 461 1.5 simonb 462 1.1 tron /* 463 1.1 tron * Output a string. 464 1.1 tron */ 465 1.5 simonb public void putstr(constant char *s) 466 1.1 tron { 467 1.1 tron while (*s != '\0') 468 1.1 tron putchr(*s++); 469 1.1 tron } 470 1.1 tron 471 1.1 tron 472 1.1 tron /* 473 1.1 tron * Convert an integral type to a string. 474 1.1 tron */ 475 1.1 tron #define TYPE_TO_A_FUNC(funcname, type) \ 476 1.5 simonb void funcname(type num, char *buf, int radix) \ 477 1.1 tron { \ 478 1.1 tron int neg = (num < 0); \ 479 1.1 tron char tbuf[INT_STRLEN_BOUND(num)+2]; \ 480 1.5 simonb char *s = tbuf + sizeof(tbuf); \ 481 1.1 tron if (neg) num = -num; \ 482 1.1 tron *--s = '\0'; \ 483 1.1 tron do { \ 484 1.5 simonb *--s = "0123456789ABCDEF"[num % radix]; \ 485 1.5 simonb } while ((num /= radix) != 0); \ 486 1.1 tron if (neg) *--s = '-'; \ 487 1.1 tron strcpy(buf, s); \ 488 1.1 tron } 489 1.1 tron 490 1.1 tron TYPE_TO_A_FUNC(postoa, POSITION) 491 1.1 tron TYPE_TO_A_FUNC(linenumtoa, LINENUM) 492 1.1 tron TYPE_TO_A_FUNC(inttoa, int) 493 1.1 tron 494 1.1 tron /* 495 1.5 simonb * Convert a string to an integral type. Return ((type) -1) on overflow. 496 1.1 tron */ 497 1.5 simonb #define STR_TO_TYPE_FUNC(funcname, type) \ 498 1.5 simonb type funcname(char *buf, char **ebuf, int radix) \ 499 1.5 simonb { \ 500 1.5 simonb type val = 0; \ 501 1.5 simonb int v = 0; \ 502 1.5 simonb for (;; buf++) { \ 503 1.5 simonb char c = *buf; \ 504 1.5 simonb int digit = (c >= '0' && c <= '9') ? c - '0' : (c >= 'a' && c <= 'f') ? c - 'a' + 10 : (c >= 'A' && c <= 'F') ? c - 'A' + 10 : -1; \ 505 1.5 simonb if (digit < 0 || digit >= radix) break; \ 506 1.5 simonb v |= ckd_mul(&val, val, radix); \ 507 1.5 simonb v |= ckd_add(&val, val, digit); \ 508 1.5 simonb } \ 509 1.5 simonb if (ebuf != NULL) *ebuf = buf; \ 510 1.5 simonb return v ? -1 : val; \ 511 1.5 simonb } 512 1.5 simonb 513 1.5 simonb STR_TO_TYPE_FUNC(lstrtopos, POSITION) 514 1.5 simonb STR_TO_TYPE_FUNC(lstrtoi, int) 515 1.5 simonb STR_TO_TYPE_FUNC(lstrtoul, unsigned long) 516 1.1 tron 517 1.1 tron /* 518 1.5 simonb * Print an integral type. 519 1.1 tron */ 520 1.5 simonb #define IPRINT_FUNC(funcname, type, typetoa) \ 521 1.5 simonb static int funcname(type num, int radix) \ 522 1.5 simonb { \ 523 1.5 simonb char buf[INT_STRLEN_BOUND(num)]; \ 524 1.5 simonb typetoa(num, buf, radix); \ 525 1.5 simonb putstr(buf); \ 526 1.5 simonb return (int) strlen(buf); \ 527 1.5 simonb } 528 1.1 tron 529 1.5 simonb IPRINT_FUNC(iprint_int, int, inttoa) 530 1.5 simonb IPRINT_FUNC(iprint_linenum, LINENUM, linenumtoa) 531 1.1 tron 532 1.1 tron /* 533 1.1 tron * This function implements printf-like functionality 534 1.1 tron * using a more portable argument list mechanism than printf's. 535 1.5 simonb * 536 1.5 simonb * {{ This paranoia about the portability of printf dates from experiences 537 1.5 simonb * with systems in the 1980s and is of course no longer necessary. }} 538 1.1 tron */ 539 1.5 simonb public int less_printf(char *fmt, PARG *parg) 540 1.1 tron { 541 1.5 simonb char *s; 542 1.5 simonb int col; 543 1.1 tron 544 1.1 tron col = 0; 545 1.1 tron while (*fmt != '\0') 546 1.1 tron { 547 1.1 tron if (*fmt != '%') 548 1.1 tron { 549 1.1 tron putchr(*fmt++); 550 1.1 tron col++; 551 1.1 tron } else 552 1.1 tron { 553 1.1 tron ++fmt; 554 1.1 tron switch (*fmt++) 555 1.1 tron { 556 1.1 tron case 's': 557 1.1 tron s = parg->p_string; 558 1.1 tron parg++; 559 1.1 tron while (*s != '\0') 560 1.1 tron { 561 1.1 tron putchr(*s++); 562 1.1 tron col++; 563 1.1 tron } 564 1.1 tron break; 565 1.1 tron case 'd': 566 1.5 simonb col += iprint_int(parg->p_int, 10); 567 1.5 simonb parg++; 568 1.5 simonb break; 569 1.5 simonb case 'x': 570 1.5 simonb col += iprint_int(parg->p_int, 16); 571 1.1 tron parg++; 572 1.1 tron break; 573 1.1 tron case 'n': 574 1.5 simonb col += iprint_linenum(parg->p_linenum, 10); 575 1.5 simonb parg++; 576 1.5 simonb break; 577 1.5 simonb case 'c': 578 1.5 simonb s = prchar(parg->p_char); 579 1.1 tron parg++; 580 1.5 simonb while (*s != '\0') 581 1.5 simonb { 582 1.5 simonb putchr(*s++); 583 1.5 simonb col++; 584 1.5 simonb } 585 1.5 simonb break; 586 1.5 simonb case '%': 587 1.5 simonb putchr('%'); 588 1.1 tron break; 589 1.1 tron } 590 1.1 tron } 591 1.1 tron } 592 1.1 tron return (col); 593 1.1 tron } 594 1.1 tron 595 1.1 tron /* 596 1.1 tron * Get a RETURN. 597 1.1 tron * If some other non-trivial char is pressed, unget it, so it will 598 1.1 tron * become the next command. 599 1.1 tron */ 600 1.5 simonb public void get_return(void) 601 1.1 tron { 602 1.1 tron int c; 603 1.1 tron 604 1.1 tron #if ONLY_RETURN 605 1.1 tron while ((c = getchr()) != '\n' && c != '\r') 606 1.1 tron bell(); 607 1.1 tron #else 608 1.1 tron c = getchr(); 609 1.1 tron if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR) 610 1.1 tron ungetcc(c); 611 1.1 tron #endif 612 1.1 tron } 613 1.1 tron 614 1.1 tron /* 615 1.1 tron * Output a message in the lower left corner of the screen 616 1.1 tron * and wait for carriage return. 617 1.1 tron */ 618 1.5 simonb public void error(char *fmt, PARG *parg) 619 1.1 tron { 620 1.1 tron int col = 0; 621 1.1 tron static char return_to_continue[] = " (press RETURN)"; 622 1.1 tron 623 1.1 tron errmsgs++; 624 1.1 tron 625 1.5 simonb if (!interactive()) 626 1.1 tron { 627 1.5 simonb less_printf(fmt, parg); 628 1.1 tron putchr('\n'); 629 1.1 tron return; 630 1.1 tron } 631 1.1 tron 632 1.5 simonb if (!oldbot) 633 1.5 simonb squish_check(); 634 1.5 simonb at_exit(); 635 1.5 simonb clear_bot(); 636 1.5 simonb at_enter(AT_STANDOUT|AT_COLOR_ERROR); 637 1.5 simonb col += so_s_width; 638 1.5 simonb col += less_printf(fmt, parg); 639 1.1 tron putstr(return_to_continue); 640 1.1 tron at_exit(); 641 1.1 tron col += sizeof(return_to_continue) + so_e_width; 642 1.1 tron 643 1.1 tron get_return(); 644 1.1 tron lower_left(); 645 1.5 simonb clear_eol(); 646 1.1 tron 647 1.1 tron if (col >= sc_width) 648 1.1 tron /* 649 1.1 tron * Printing the message has probably scrolled the screen. 650 1.1 tron * {{ Unless the terminal doesn't have auto margins, 651 1.1 tron * in which case we just hammered on the right margin. }} 652 1.1 tron */ 653 1.1 tron screen_trashed = 1; 654 1.1 tron 655 1.1 tron flush(); 656 1.1 tron } 657 1.1 tron 658 1.1 tron /* 659 1.1 tron * Output a message in the lower left corner of the screen 660 1.1 tron * and don't wait for carriage return. 661 1.1 tron * Usually used to warn that we are beginning a potentially 662 1.1 tron * time-consuming operation. 663 1.1 tron */ 664 1.5 simonb static void ierror_suffix(char *fmt, PARG *parg, char *suffix1, char *suffix2, char *suffix3) 665 1.1 tron { 666 1.1 tron at_exit(); 667 1.1 tron clear_bot(); 668 1.5 simonb at_enter(AT_STANDOUT|AT_COLOR_ERROR); 669 1.1 tron (void) less_printf(fmt, parg); 670 1.5 simonb putstr(suffix1); 671 1.5 simonb putstr(suffix2); 672 1.5 simonb putstr(suffix3); 673 1.1 tron at_exit(); 674 1.1 tron flush(); 675 1.1 tron need_clr = 1; 676 1.1 tron } 677 1.1 tron 678 1.5 simonb public void ierror(char *fmt, PARG *parg) 679 1.5 simonb { 680 1.5 simonb ierror_suffix(fmt, parg, "... (interrupt to abort)", "", ""); 681 1.5 simonb } 682 1.5 simonb 683 1.5 simonb public void ixerror(char *fmt, PARG *parg) 684 1.5 simonb { 685 1.5 simonb if (!supports_ctrl_x()) 686 1.5 simonb ierror(fmt, parg); 687 1.5 simonb else 688 1.5 simonb ierror_suffix(fmt, parg, 689 1.5 simonb "... (", prchar(intr_char), " or interrupt to abort)"); 690 1.5 simonb } 691 1.5 simonb 692 1.1 tron /* 693 1.1 tron * Output a message in the lower left corner of the screen 694 1.1 tron * and return a single-character response. 695 1.1 tron */ 696 1.5 simonb public int query(char *fmt, PARG *parg) 697 1.1 tron { 698 1.5 simonb int c; 699 1.1 tron int col = 0; 700 1.1 tron 701 1.5 simonb if (interactive()) 702 1.1 tron clear_bot(); 703 1.1 tron 704 1.1 tron (void) less_printf(fmt, parg); 705 1.1 tron c = getchr(); 706 1.1 tron 707 1.5 simonb if (interactive()) 708 1.5 simonb { 709 1.5 simonb lower_left(); 710 1.5 simonb if (col >= sc_width) 711 1.5 simonb screen_trashed = 1; 712 1.5 simonb flush(); 713 1.5 simonb } else 714 1.1 tron { 715 1.1 tron putchr('\n'); 716 1.1 tron } 717 1.1 tron 718 1.5 simonb if (c == 'Q') 719 1.5 simonb quit(QUIT_OK); 720 1.1 tron return (c); 721 1.1 tron } 722