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