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