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