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