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