1 /* $NetBSD: io.c,v 1.31 2024/03/26 20:50:29 andvar Exp $ */ 2 3 /* 4 * io.c Larn is copyrighted 1986 by Noah Morgan. 5 * 6 * Below are the functions in this file: 7 * 8 * setupvt100() Subroutine to set up terminal in correct mode for game 9 * clearvt100() Subroutine to clean up terminal when the game is over 10 * ttgetch() Routine to read in one character from the terminal 11 * scbr() Function to set cbreak -echo for the terminal 12 * sncbr() Function to set -cbreak echo for the terminal 13 * newgame() Subroutine to save the initial time and seed rnd() 14 * 15 * FILE OUTPUT ROUTINES 16 * 17 * lprintf(format,args . . .) printf to the output buffer 18 * lprint(integer) send binary integer to output buffer 19 * lwrite(buf,len) write a buffer to the output buffer 20 * lprcat(str) append a string to the output buffer 21 * 22 * FILE OUTPUT MACROS (in header.h) 23 * 24 * lprc(character) put the character into the output buffer 25 * 26 * FILE INPUT ROUTINES 27 * 28 * long lgetc() read one character from input buffer 29 * long larn_lrint() read one integer from input buffer 30 * lrfill(address,number) put input bytes into a buffer char 31 * *lgetw() get a whitespace ended word from 32 * input char *lgetl() get a \n or EOF ended line from input 33 * 34 * FILE OPEN / CLOSE ROUTINES 35 * 36 * lcreat(filename) create a new file for write 37 * lopen(filename) open a file for read 38 * lappend(filename) open for append to an existing file 39 * lrclose() close the input file 40 * lwclose() close output file 41 * lflush() flush the output buffer 42 * 43 * Other Routines 44 * 45 * cursor(x,y) position cursor at [x,y] 46 * cursors() position cursor at [1,24] (saves memory) 47 * cl_line(x,y) clear line at [1,y] and leave cursor at [x,y] 48 * cl_up(x,y) clear screen from [x,1] to current line 49 * cl_dn(x,y) clear screen from [1,y] to end of display 50 * standout(str) print the string in standout mode 51 * set_score_output() called when output should be literally printed 52 * ttputch(ch) print one character in decoded output buffer 53 * flush_buf() flush buffer with decoded output 54 * init_term() terminal initialization -- setup termcap info 55 * char *tmcapcnv(sd,ss) routine to convert VT100 \33's to termcap format 56 * beep() routine to emit a beep if enabled 57 * (see no-beep in .larnopts) 58 * 59 * Note: ** entries are available only in termcap mode. 60 */ 61 #include <sys/cdefs.h> 62 #ifndef lint 63 __RCSID("$NetBSD: io.c,v 1.31 2024/03/26 20:50:29 andvar Exp $"); 64 #endif /* not lint */ 65 66 #include "header.h" 67 #include "extern.h" 68 #include <string.h> 69 #include <unistd.h> 70 #include <stdio.h> 71 #include <stdlib.h> 72 #include <time.h> 73 #include <term.h> 74 #include <fcntl.h> 75 #include <errno.h> 76 #include <ctype.h> 77 78 #ifdef TERMIO 79 #include <termio.h> 80 #define sgttyb termio 81 #define stty(_a,_b) ioctl(_a,TCSETA,_b) 82 #define gtty(_a,_b) ioctl(_a,TCGETA,_b) 83 #endif 84 #ifdef TERMIOS 85 #include <termios.h> 86 #define sgttyb termios 87 #define stty(_a,_b) tcsetattr(_a,TCSADRAIN,_b) 88 #define gtty(_a,_b) tcgetattr(_a,_b) 89 #endif 90 91 #if defined(TERMIO) || defined(TERMIOS) 92 static int rawflg = 0; 93 static char saveeof, saveeol; 94 #define doraw(_a) \ 95 if(!rawflg) { \ 96 ++rawflg; \ 97 saveeof = _a.c_cc[VMIN]; \ 98 saveeol = _a.c_cc[VTIME]; \ 99 } \ 100 _a.c_cc[VMIN] = 1; \ 101 _a.c_cc[VTIME] = 1; \ 102 _a.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL) 103 #define unraw(_a) \ 104 _a.c_cc[VMIN] = saveeof; \ 105 _a.c_cc[VTIME] = saveeol; \ 106 _a.c_lflag |= ICANON|ECHO|ECHOE|ECHOK|ECHONL 107 108 #else /* not TERMIO or TERMIOS */ 109 110 #ifndef BSD 111 #define CBREAK RAW /* V7 has no CBREAK */ 112 #endif 113 114 #define doraw(_a) (_a.sg_flags |= CBREAK,_a.sg_flags &= ~ECHO) 115 #define unraw(_a) (_a.sg_flags &= ~CBREAK,_a.sg_flags |= ECHO) 116 #include <sgtty.h> 117 #endif /* not TERMIO or TERMIOS */ 118 119 #ifndef NOVARARGS /* if we have varargs */ 120 #include <stdarg.h> 121 #else /* NOVARARGS */ /* if we don't have varargs */ 122 typedef char *va_list; 123 #define va_dcl int va_alist; 124 #define va_start(plist) plist = (char *) &va_alist 125 #define va_end(plist) 126 #define va_arg(plist,mode) ((mode *)(plist += sizeof(mode)))[-1] 127 #endif /* NOVARARGS */ 128 129 static int ttputch(int ch); 130 static void flush_buf(void); 131 132 #define LINBUFSIZE 128 /* size of the lgetw() and lgetl() buffer */ 133 int io_outfd; /* output file numbers */ 134 int io_infd; /* input file numbers */ 135 static struct sgttyb ttx;/* storage for the tty modes */ 136 static int ipoint = MAXIBUF, iepoint = MAXIBUF; /* input buffering 137 * pointers */ 138 static char lgetwbuf[LINBUFSIZE]; /* get line (word) buffer */ 139 140 /* 141 * setupvt100() Subroutine to set up terminal in correct mode for game 142 * 143 * Attributes off, clear screen, set scrolling region, set tty mode 144 */ 145 void 146 setupvt100(void) 147 { 148 clear(); 149 setscroll(); 150 scbr(); /* system("stty cbreak -echo"); */ 151 } 152 153 /* 154 * clearvt100() Subroutine to clean up terminal when the game is over 155 * 156 * Attributes off, clear screen, unset scrolling region, restore tty mode 157 */ 158 void 159 clearvt100(void) 160 { 161 resetscroll(); 162 clear(); 163 sncbr(); /* system("stty -cbreak echo"); */ 164 } 165 166 /* 167 * ttgetch() Routine to read in one character from the terminal 168 */ 169 int 170 ttgetch(void) 171 { 172 char byt; 173 #ifdef EXTRA 174 c[BYTESIN]++; 175 #endif 176 lflush(); /* be sure output buffer is flushed */ 177 read(0, &byt, 1); /* get byte from terminal */ 178 return (byt); 179 } 180 181 /* 182 * scbr() Function to set cbreak -echo for the terminal 183 * 184 * like: system("stty cbreak -echo") 185 */ 186 void 187 scbr(void) 188 { 189 gtty(0, &ttx); 190 doraw(ttx); 191 stty(0, &ttx); 192 } 193 194 /* 195 * sncbr() Function to set -cbreak echo for the terminal 196 * 197 * like: system("stty -cbreak echo") 198 */ 199 void 200 sncbr(void) 201 { 202 gtty(0, &ttx); 203 unraw(ttx); 204 stty(0, &ttx); 205 } 206 207 /* 208 * newgame() Subroutine to save the initial time and seed rnd() 209 */ 210 void 211 newgame(void) 212 { 213 long *p, *pe; 214 for (p = c, pe = c + 100; p < pe; *p++ = 0); 215 time(&initialtime); 216 seedrand(initialtime); 217 srandom(initialtime); 218 lcreat((char *) 0); /* open buffering for output to terminal */ 219 } 220 221 /* 222 * lprintf(format,args . . .) printf to the output buffer 223 * char *format; 224 * ??? args . . . 225 * 226 * Enter with the format string in "format", as per printf() usage 227 * and any needed arguments following it 228 * Note: lprintf() only supports %s, %c and %d, with width modifier and left 229 * or right justification. 230 * No correct checking for output buffer overflow is done, but flushes 231 * are done beforehand if needed. 232 * Returns nothing of value. 233 */ 234 void 235 lprintf(const char *fmt, ...) 236 { 237 va_list ap; 238 char buf[BUFBIG/2]; 239 240 va_start(ap, fmt); 241 vsnprintf(buf, sizeof(buf), fmt, ap); 242 va_end(ap); 243 244 if (lpnt >= lpend) 245 lflush(); 246 247 lprcat(buf); 248 } 249 250 /* 251 * lprint(long-integer) send binary integer to output buffer 252 * long integer; 253 * 254 * +---------+---------+---------+---------+ 255 * | high | | | low | 256 * | order | | | order | 257 * | byte | | | byte | 258 * +---------+---------+---------+---------+ 259 * 31 --- 24 23 --- 16 15 --- 8 7 --- 0 260 * 261 * The save order is low order first, to high order (4 bytes total) 262 * and is written to be system independent. 263 * No checking for output buffer overflow is done, but flushes if needed! 264 * Returns nothing of value. 265 */ 266 void 267 lprint(long x) 268 { 269 if (lpnt >= lpend) 270 lflush(); 271 *lpnt++ = 255 & x; 272 *lpnt++ = 255 & (x >> 8); 273 *lpnt++ = 255 & (x >> 16); 274 *lpnt++ = 255 & (x >> 24); 275 } 276 277 /* 278 * lwrite(buf,len) write a buffer to the output buffer 279 * char *buf; 280 * int len; 281 * 282 * Enter with the address and number of bytes to write out 283 * Returns nothing of value 284 */ 285 void 286 lwrite(char *buf, int len) 287 { 288 char *s; 289 u_char *t; 290 int num2; 291 292 if (len > 399) { /* don't copy data if can just write it */ 293 #ifdef EXTRA 294 c[BYTESOUT] += len; 295 #endif 296 297 #ifndef VT100 298 for (s = buf; len > 0; --len) 299 lprc(*s++); 300 #else /* VT100 */ 301 lflush(); 302 write(io_outfd, buf, len); 303 #endif /* VT100 */ 304 } else 305 while (len) { 306 if (lpnt >= lpend) 307 lflush(); /* if buffer is full flush it */ 308 num2 = lpbuf + BUFBIG - lpnt; /* # bytes left in 309 * output buffer */ 310 if (num2 > len) 311 num2 = len; 312 t = lpnt; 313 len -= num2; 314 while (num2--) 315 *t++ = *buf++; /* copy in the bytes */ 316 lpnt = t; 317 } 318 } 319 320 /* 321 * long lgetc() Read one character from input buffer 322 * 323 * Returns 0 if EOF, otherwise the character 324 */ 325 long 326 lgetc(void) 327 { 328 int i; 329 if (ipoint != iepoint) 330 return (inbuffer[ipoint++]); 331 if (iepoint != MAXIBUF) 332 return (0); 333 if ((i = read(io_infd, inbuffer, MAXIBUF)) <= 0) { 334 if (i != 0) 335 write(1, "error reading from input file\n", 30); 336 iepoint = ipoint = 0; 337 return (0); 338 } 339 ipoint = 1; 340 iepoint = i; 341 return (*inbuffer); 342 } 343 344 /* 345 * long lrint() Read one integer from input buffer 346 * 347 * +---------+---------+---------+---------+ 348 * | high | | | low | 349 * | order | | | order | 350 * | byte | | | byte | 351 * +---------+---------+---------+---------+ 352 * 31 --- 24 23 --- 16 15 --- 8 7 --- 0 353 * 354 * The save order is low order first, to high order (4 bytes total) 355 * Returns the int read 356 */ 357 long 358 larn_lrint(void) 359 { 360 unsigned long i; 361 i = 255 & lgetc(); 362 i |= (255 & lgetc()) << 8; 363 i |= (255 & lgetc()) << 16; 364 i |= (255 & lgetc()) << 24; 365 return (i); 366 } 367 368 /* 369 * lrfill(address,number) put input bytes into a buffer 370 * char *address; 371 * int number; 372 * 373 * Reads "number" bytes into the buffer pointed to by "address". 374 * Returns nothing of value 375 */ 376 void 377 lrfill(char *adr, int num) 378 { 379 u_char *pnt; 380 int num2; 381 382 while (num) { 383 if (iepoint == ipoint) { 384 if (num > 5) { /* fast way */ 385 if (read(io_infd, adr, num) != num) 386 write(2, "error reading from input file\n", 30); 387 num = 0; 388 } else { 389 *adr++ = lgetc(); 390 --num; 391 } 392 } else { 393 num2 = iepoint - ipoint; /* # of bytes left in 394 * the buffer */ 395 if (num2 > num) 396 num2 = num; 397 pnt = inbuffer + ipoint; 398 num -= num2; 399 ipoint += num2; 400 while (num2--) 401 *adr++ = *pnt++; 402 } 403 } 404 } 405 406 /* 407 * char *lgetw() Get a whitespace ended word from input 408 * 409 * Returns pointer to a buffer that contains word. If EOF, returns a NULL 410 */ 411 char * 412 lgetw(void) 413 { 414 char *lgp, cc; 415 int n = LINBUFSIZE, quote = 0; 416 lgp = lgetwbuf; 417 do 418 cc = lgetc(); 419 while ((cc <= 32) && (cc > '\0')); /* eat whitespace */ 420 for (;; --n, cc = lgetc()) { 421 if ((cc == '\0') && (lgp == lgetwbuf)) 422 return (NULL); /* EOF */ 423 if ((n <= 1) || ((cc <= 32) && (quote == 0))) { 424 *lgp = '\0'; 425 return (lgetwbuf); 426 } 427 if (cc != '"') 428 *lgp++ = cc; 429 else 430 quote ^= 1; 431 } 432 } 433 434 /* 435 * char *lgetl() Function to read in a line ended by newline or EOF 436 * 437 * Returns pointer to a buffer that contains the line. If EOF, returns NULL 438 */ 439 char * 440 lgetl(void) 441 { 442 int i = LINBUFSIZE, ch; 443 char *str = lgetwbuf; 444 for (;; --i) { 445 if ((*str++ = ch = lgetc()) == '\0') { 446 if (str == lgetwbuf + 1) 447 return (NULL); /* EOF */ 448 ot: *str = '\0'; 449 return (lgetwbuf); /* line ended by EOF */ 450 } 451 if ((ch == '\n') || (i <= 1)) 452 goto ot;/* line ended by \n */ 453 } 454 } 455 456 /* 457 * lcreat(filename) Create a new file for write 458 * char *filename; 459 * 460 * lcreat((char*)0); means to the terminal 461 * Returns -1 if error, otherwise the file descriptor opened. 462 */ 463 int 464 lcreat(char *str) 465 { 466 lflush(); 467 lpnt = lpbuf; 468 lpend = lpbuf + BUFBIG; 469 if (str == NULL) 470 return (io_outfd = 1); 471 if ((io_outfd = creat(str, 0644)) < 0) { 472 io_outfd = 1; 473 lprintf("error creating file <%s>: %s\n", str, 474 strerror(errno)); 475 lflush(); 476 return (-1); 477 } 478 return (io_outfd); 479 } 480 481 /* 482 * lopen(filename) Open a file for read 483 * char *filename; 484 * 485 * lopen(0) means from the terminal 486 * Returns -1 if error, otherwise the file descriptor opened. 487 */ 488 int 489 lopen(char *str) 490 { 491 ipoint = iepoint = MAXIBUF; 492 if (str == NULL) 493 return (io_infd = 0); 494 if ((io_infd = open(str, O_RDONLY)) < 0) { 495 lwclose(); 496 io_outfd = 1; 497 lpnt = lpbuf; 498 return (-1); 499 } 500 return (io_infd); 501 } 502 503 /* 504 * lappend(filename) Open for append to an existing file 505 * char *filename; 506 * 507 * lappend(0) means to the terminal 508 * Returns -1 if error, otherwise the file descriptor opened. 509 */ 510 int 511 lappend(char *str) 512 { 513 lpnt = lpbuf; 514 lpend = lpbuf + BUFBIG; 515 if (str == NULL) 516 return (io_outfd = 1); 517 if ((io_outfd = open(str, 2)) < 0) { 518 io_outfd = 1; 519 return (-1); 520 } 521 lseek(io_outfd, 0, SEEK_END); /* seek to end of file */ 522 return (io_outfd); 523 } 524 525 /* 526 * lrclose() close the input file 527 * 528 * Returns nothing of value. 529 */ 530 void 531 lrclose(void) 532 { 533 if (io_infd > 0) { 534 close(io_infd); 535 io_infd = 0; 536 } 537 } 538 539 /* 540 * lwclose() close output file flushing if needed 541 * 542 * Returns nothing of value. 543 */ 544 void 545 lwclose(void) 546 { 547 lflush(); 548 if (io_outfd > 2) { 549 close(io_outfd); 550 io_outfd = 1; 551 } 552 } 553 554 /* 555 * lprcat(string) append a string to the output buffer 556 * avoids calls to lprintf (time consuming) 557 */ 558 void 559 lprcat(const char *str) 560 { 561 u_char *str2; 562 if (lpnt >= lpend) 563 lflush(); 564 str2 = lpnt; 565 while ((*str2++ = *str++) != '\0') 566 continue; 567 lpnt = str2 - 1; 568 } 569 570 #ifdef VT100 571 /* 572 * cursor(x,y) Subroutine to set the cursor position 573 * 574 * x and y are the cursor coordinates, and lpbuff is the output buffer where 575 * escape sequence will be placed. 576 */ 577 static char *y_num[] = { 578 "\33[", "\33[", "\33[2", "\33[3", "\33[4", "\33[5", "\33[6", 579 "\33[7", "\33[8", "\33[9", "\33[10", "\33[11", "\33[12", "\33[13", "\33[14", 580 "\33[15", "\33[16", "\33[17", "\33[18", "\33[19", "\33[20", "\33[21", "\33[22", 581 "\33[23", "\33[24"}; 582 583 static char *x_num[] = { 584 "H", "H", ";2H", ";3H", ";4H", ";5H", ";6H", ";7H", ";8H", ";9H", 585 ";10H", ";11H", ";12H", ";13H", ";14H", ";15H", ";16H", ";17H", ";18H", ";19H", 586 ";20H", ";21H", ";22H", ";23H", ";24H", ";25H", ";26H", ";27H", ";28H", ";29H", 587 ";30H", ";31H", ";32H", ";33H", ";34H", ";35H", ";36H", ";37H", ";38H", ";39H", 588 ";40H", ";41H", ";42H", ";43H", ";44H", ";45H", ";46H", ";47H", ";48H", ";49H", 589 ";50H", ";51H", ";52H", ";53H", ";54H", ";55H", ";56H", ";57H", ";58H", ";59H", 590 ";60H", ";61H", ";62H", ";63H", ";64H", ";65H", ";66H", ";67H", ";68H", ";69H", 591 ";70H", ";71H", ";72H", ";73H", ";74H", ";75H", ";76H", ";77H", ";78H", ";79H", 592 ";80H"}; 593 594 void 595 cursor(x, y) 596 int x, y; 597 { 598 char *p; 599 if (lpnt >= lpend) 600 lflush(); 601 602 p = y_num[y]; /* get the string to print */ 603 while (*p) 604 *lpnt++ = *p++; /* print the string */ 605 606 p = x_num[x]; /* get the string to print */ 607 while (*p) 608 *lpnt++ = *p++; /* print the string */ 609 } 610 #else /* VT100 */ 611 /* 612 * cursor(x,y) Put cursor at specified coordinates staring at [1,1] (termcap) 613 */ 614 void 615 cursor(int x, int y) 616 { 617 if (lpnt >= lpend) 618 lflush(); 619 620 *lpnt++ = CURSOR; 621 *lpnt++ = x; 622 *lpnt++ = y; 623 } 624 #endif /* VT100 */ 625 626 /* 627 * Routine to position cursor at beginning of 24th line 628 */ 629 void 630 cursors(void) 631 { 632 cursor(1, 24); 633 } 634 635 #ifndef VT100 636 /* 637 * Warning: ringing the bell is control code 7. Don't use in defines. 638 * Don't change the order of these defines. 639 * Also used in helpfiles. Codes used in helpfiles should be \E[1 to \E[7 with 640 * obvious meanings. 641 */ 642 643 static char *outbuf = 0; /* translated output buffer */ 644 /* 645 * init_term() Terminal initialization -- setup termcap info 646 */ 647 void 648 init_term(void) 649 { 650 setupterm(NULL, 0, NULL); /* will exit if invalid term */ 651 if (!cursor_address) { 652 fprintf(stderr, "term does not have cursor_address.\n"); 653 exit(1); 654 } 655 if (!clr_eol) { 656 fprintf(stderr, "term does not have clr_eol.\n"); 657 exit(1); 658 } 659 if (!clear_screen) { 660 fprintf(stderr, "term does not have clear_screen.\n"); 661 exit(1); 662 } 663 if ((outbuf = malloc(BUFBIG + 16)) == 0) { /* get memory for 664 * decoded output buffer */ 665 fprintf(stderr, "Error malloc'ing memory for decoded output buffer\n"); 666 died(-285); /* malloc() failure */ 667 } 668 669 } 670 #endif /* VT100 */ 671 672 /* 673 * cl_line(x,y) Clear the whole line indicated by 'y' and leave cursor at [x,y] 674 */ 675 void 676 cl_line(int x, int y) 677 { 678 #ifdef VT100 679 cursor(x, y); 680 lprcat("\33[2K"); 681 #else /* VT100 */ 682 cursor(1, y); 683 *lpnt++ = CL_LINE; 684 cursor(x, y); 685 #endif /* VT100 */ 686 } 687 688 /* 689 * cl_up(x,y) Clear screen from [x,1] to current position. Leave cursor at [x,y] 690 */ 691 void 692 cl_up(int x, int y) 693 { 694 #ifdef VT100 695 cursor(x, y); 696 lprcat("\33[1J\33[2K"); 697 #else /* VT100 */ 698 int i; 699 cursor(1, 1); 700 for (i = 1; i <= y; i++) { 701 *lpnt++ = CL_LINE; 702 *lpnt++ = '\n'; 703 } 704 cursor(x, y); 705 #endif /* VT100 */ 706 } 707 708 /* 709 * cl_dn(x,y) Clear screen from [1,y] to end of display. Leave cursor at [x,y] 710 */ 711 void 712 cl_dn(int x, int y) 713 { 714 #ifdef VT100 715 cursor(x, y); 716 lprcat("\33[J\33[2K"); 717 #else /* VT100 */ 718 int i; 719 cursor(1, y); 720 if (!clr_eos) { 721 *lpnt++ = CL_LINE; 722 for (i = y; i <= 24; i++) { 723 *lpnt++ = CL_LINE; 724 if (i != 24) 725 *lpnt++ = '\n'; 726 } 727 cursor(x, y); 728 } else 729 *lpnt++ = CL_DOWN; 730 cursor(x, y); 731 #endif /* VT100 */ 732 } 733 734 /* 735 * standout(str) Print the argument string in inverse video (standout mode). 736 */ 737 void 738 standout(const char *str) 739 { 740 #ifdef VT100 741 setbold(); 742 while (*str) 743 *lpnt++ = *str++; 744 resetbold(); 745 #else /* VT100 */ 746 *lpnt++ = ST_START; 747 while (*str) 748 *lpnt++ = *str++; 749 *lpnt++ = ST_END; 750 #endif /* VT100 */ 751 } 752 753 /* 754 * set_score_output() Called when output should be literally printed. 755 */ 756 void 757 set_score_output(void) 758 { 759 enable_scroll = -1; 760 } 761 762 /* 763 * lflush() Flush the output buffer 764 * 765 * Returns nothing of value. 766 * for termcap version: Flush output in output buffer according to output 767 * status as indicated by `enable_scroll' 768 */ 769 #ifndef VT100 770 static int scrline = 18; /* line # for wraparound instead of scrolling 771 * if no DL */ 772 void 773 lflush(void) 774 { 775 int lpoint; 776 u_char *str; 777 static int curx = 0; 778 static int cury = 0; 779 780 if ((lpoint = lpnt - lpbuf) > 0) { 781 #ifdef EXTRA 782 c[BYTESOUT] += lpoint; 783 #endif 784 if (enable_scroll <= -1) { 785 flush_buf(); 786 if (write(io_outfd, lpbuf, lpoint) != lpoint) 787 write(2, "error writing to output file\n", 29); 788 lpnt = lpbuf; /* point back to beginning of buffer */ 789 return; 790 } 791 for (str = lpbuf; str < lpnt; str++) { 792 if (*str >= 32) { 793 ttputch(*str); 794 curx++; 795 } else 796 switch (*str) { 797 case CLEAR: 798 tputs(clear_screen, 0, ttputch); 799 curx = cury = 0; 800 break; 801 802 case CL_LINE: 803 tputs(clr_eol, 0, ttputch); 804 break; 805 806 case CL_DOWN: 807 tputs(clr_eos, 0, ttputch); 808 break; 809 810 case ST_START: 811 tputs(enter_standout_mode, 0, ttputch); 812 break; 813 814 case ST_END: 815 tputs(exit_standout_mode, 0, ttputch); 816 break; 817 818 case CURSOR: 819 curx = *++str - 1; 820 cury = *++str - 1; 821 tputs(tiparm(cursor_address, 822 cury, curx), 0, ttputch); 823 break; 824 825 case '\n': 826 if ((cury == 23) && enable_scroll) { 827 if (!delete_line || 828 !insert_line) 829 { /* wraparound or scroll? */ 830 if (++scrline > 23) 831 scrline = 19; 832 833 if (++scrline > 23) 834 scrline = 19; 835 tputs(tiparm( 836 cursor_address, 837 scrline, 0), 838 0, ttputch); 839 tputs(clr_eol, 0, 840 ttputch); 841 842 if (--scrline < 19) 843 scrline = 23; 844 tputs(tiparm( 845 cursor_address, 846 scrline, 0), 847 0, ttputch); 848 tputs(clr_eol, 0, 849 ttputch); 850 } else { 851 tputs(tiparm( 852 cursor_address, 853 19, 0), 854 0, ttputch); 855 tputs(delete_line, 0, 856 ttputch); 857 tputs(tiparm( 858 cursor_address, 859 23, 0), 860 0, ttputch); 861 /* 862 * tputs (AL, 0, 863 * ttputch); 864 */ 865 } 866 } else { 867 ttputch('\n'); 868 cury++; 869 } 870 curx = 0; 871 break; 872 873 default: 874 ttputch(*str); 875 curx++; 876 }; 877 } 878 } 879 lpnt = lpbuf; 880 flush_buf(); /* flush real output buffer now */ 881 } 882 #else /* VT100 */ 883 /* 884 * lflush() flush the output buffer 885 * 886 * Returns nothing of value. 887 */ 888 void 889 lflush() 890 { 891 int lpoint; 892 if ((lpoint = lpnt - lpbuf) > 0) { 893 #ifdef EXTRA 894 c[BYTESOUT] += lpoint; 895 #endif 896 if (write(io_outfd, lpbuf, lpoint) != lpoint) 897 write(2, "error writing to output file\n", 29); 898 } 899 lpnt = lpbuf; /* point back to beginning of buffer */ 900 } 901 #endif /* VT100 */ 902 903 #ifndef VT100 904 static int vindex = 0; 905 /* 906 * ttputch(ch) Print one character in decoded output buffer. 907 */ 908 static int 909 ttputch(int ch) 910 { 911 outbuf[vindex++] = ch; 912 if (vindex >= BUFBIG) 913 flush_buf(); 914 return (0); 915 } 916 917 /* 918 * flush_buf() Flush buffer with decoded output. 919 */ 920 static void 921 flush_buf(void) 922 { 923 if (vindex) 924 write(io_outfd, outbuf, vindex); 925 vindex = 0; 926 } 927 928 /* 929 * char *tmcapcnv(sd,ss) Routine to convert VT100 escapes to termcap 930 * format 931 * Processes only the \33[#m sequence (converts . files for termcap use 932 */ 933 char * 934 tmcapcnv(char *sd, char *ss) 935 { 936 int tmstate = 0; /* 0=normal, 1=\33 2=[ 3=# */ 937 char tmdigit = 0; /* the # in \33[#m */ 938 while (*ss) { 939 switch (tmstate) { 940 case 0: 941 if (*ss == '\33') { 942 tmstate++; 943 break; 944 } 945 ign: *sd++ = *ss; 946 ign2: tmstate = 0; 947 break; 948 case 1: 949 if (*ss != '[') 950 goto ign; 951 tmstate++; 952 break; 953 case 2: 954 if (isdigit((u_char)*ss)) { 955 tmdigit = *ss - '0'; 956 tmstate++; 957 break; 958 } 959 if (*ss == 'm') { 960 *sd++ = ST_END; 961 goto ign2; 962 } 963 goto ign; 964 case 3: 965 if (*ss == 'm') { 966 if (tmdigit) 967 *sd++ = ST_START; 968 else 969 *sd++ = ST_END; 970 goto ign2; 971 } 972 default: 973 goto ign; 974 }; 975 ss++; 976 } 977 *sd = 0; /* NULL terminator */ 978 return (sd); 979 } 980 #endif /* VT100 */ 981 982 /* 983 * beep() Routine to emit a beep if enabled (see no-beep in .larnopts) 984 */ 985 void 986 beep(void) 987 { 988 if (!nobeep) 989 *lpnt++ = '\7'; 990 } 991