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