1 /* $NetBSD: io.c,v 1.11 2001/02/05 00:57:33 christos Exp $ */ 2 3 /* 4 * io.c Larn is copyrighted 1986 by Noah Morgan. 5 * 6 * Below are the functions in this file: 7 * 8 * setupvt100() Subroutine to set up terminal in correct mode for game 9 * clearvt100() Subroutine to clean up terminal when the game is over 10 * 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.11 2001/02/05 00:57:33 christos Exp $"); 66 #endif /* not lint */ 67 68 #include "header.h" 69 #include "extern.h" 70 #include <string.h> 71 #include <unistd.h> 72 #include <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 * lgetchar() Routine to read in one character from the terminal 168 */ 169 int 170 lgetchar() 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; 767 struct tinfo *info; 768 char *CM, *CE, *CD, *CL, *SO, *SE, *AL, *DL; /* Termcap capabilities */ 769 static char *outbuf = 0; /* translated output buffer */ 770 771 /* 772 * init_term() Terminal initialization -- setup termcap info 773 */ 774 void 775 init_term() 776 { 777 char *capptr; 778 char *term; 779 780 cap = NULL; 781 switch (t_getent(&info, term = getenv("TERM"))) { 782 case -1: 783 write(2, "Cannot open termcap file.\n", 26); 784 exit(1); 785 case 0: 786 write(2, "Cannot find entry of ", 21); 787 write(2, term, strlen(term)); 788 write(2, " in termcap\n", 12); 789 exit(1); 790 }; 791 792 CM = t_agetstr(info, "cm", &cap, &capptr); /* Cursor motion */ 793 CE = t_agetstr(info, "ce", &cap, &capptr); /* Clear to eoln */ 794 CL = t_agetstr(info, "cl", &cap, &capptr); /* Clear screen */ 795 796 /* OPTIONAL */ 797 AL = t_agetstr(info, "al", &cap, &capptr); /* Insert line */ 798 DL = t_agetstr(info, "dl", &cap, &capptr); /* Delete line */ 799 SO = t_agetstr(info, "so", &cap, &capptr); /* Begin standout mode */ 800 SE = t_agetstr(info, "se", &cap, &capptr); /* End standout mode */ 801 CD = t_agetstr(info, "cd", &cap, &capptr); /* Clear to end of display */ 802 803 if (!CM) { /* can't find cursor motion entry */ 804 write(2, "Sorry, for a ", 13); 805 write(2, term, strlen(term)); 806 write(2, ", I can't find the cursor motion entry in termcap\n", 50); 807 exit(1); 808 } 809 if (!CE) { /* can't find clear to end of line entry */ 810 write(2, "Sorry, for a ", 13); 811 write(2, term, strlen(term)); 812 write(2, ", I can't find the clear to end of line entry in termcap\n", 57); 813 exit(1); 814 } 815 if (!CL) { /* can't find clear entire screen entry */ 816 write(2, "Sorry, for a ", 13); 817 write(2, term, strlen(term)); 818 write(2, ", I can't find the clear entire screen entry in termcap\n", 56); 819 exit(1); 820 } 821 if ((outbuf = malloc(BUFBIG + 16)) == 0) { /* get memory for 822 * decoded output buffer */ 823 write(2, "Error malloc'ing memory for decoded output buffer\n", 50); 824 died(-285); /* malloc() failure */ 825 } 826 } 827 #endif /* VT100 */ 828 829 /* 830 * cl_line(x,y) Clear the whole line indicated by 'y' and leave cursor at [x,y] 831 */ 832 void 833 cl_line(x, y) 834 int x, y; 835 { 836 #ifdef VT100 837 cursor(x, y); 838 lprcat("\33[2K"); 839 #else /* VT100 */ 840 cursor(1, y); 841 *lpnt++ = CL_LINE; 842 cursor(x, y); 843 #endif /* VT100 */ 844 } 845 846 /* 847 * cl_up(x,y) Clear screen from [x,1] to current position. Leave cursor at [x,y] 848 */ 849 void 850 cl_up(x, y) 851 int x, y; 852 { 853 #ifdef VT100 854 cursor(x, y); 855 lprcat("\33[1J\33[2K"); 856 #else /* VT100 */ 857 int i; 858 cursor(1, 1); 859 for (i = 1; i <= y; i++) { 860 *lpnt++ = CL_LINE; 861 *lpnt++ = '\n'; 862 } 863 cursor(x, y); 864 #endif /* VT100 */ 865 } 866 867 /* 868 * cl_dn(x,y) Clear screen from [1,y] to end of display. Leave cursor at [x,y] 869 */ 870 void 871 cl_dn(x, y) 872 int x, y; 873 { 874 #ifdef VT100 875 cursor(x, y); 876 lprcat("\33[J\33[2K"); 877 #else /* VT100 */ 878 int i; 879 cursor(1, y); 880 if (!CD) { 881 *lpnt++ = CL_LINE; 882 for (i = y; i <= 24; i++) { 883 *lpnt++ = CL_LINE; 884 if (i != 24) 885 *lpnt++ = '\n'; 886 } 887 cursor(x, y); 888 } else 889 *lpnt++ = CL_DOWN; 890 cursor(x, y); 891 #endif /* VT100 */ 892 } 893 894 /* 895 * standout(str) Print the argument string in inverse video (standout mode). 896 */ 897 void 898 standout(str) 899 char *str; 900 { 901 #ifdef VT100 902 setbold(); 903 while (*str) 904 *lpnt++ = *str++; 905 resetbold(); 906 #else /* VT100 */ 907 *lpnt++ = ST_START; 908 while (*str) 909 *lpnt++ = *str++; 910 *lpnt++ = ST_END; 911 #endif /* VT100 */ 912 } 913 914 /* 915 * set_score_output() Called when output should be literally printed. 916 */ 917 void 918 set_score_output() 919 { 920 enable_scroll = -1; 921 } 922 923 /* 924 * lflush() Flush the output buffer 925 * 926 * Returns nothing of value. 927 * for termcap version: Flush output in output buffer according to output 928 * status as indicated by `enable_scroll' 929 */ 930 #ifndef VT100 931 static int scrline = 18; /* line # for wraparound instead of scrolling 932 * if no DL */ 933 void 934 lflush() 935 { 936 int lpoint; 937 u_char *str; 938 static int curx = 0; 939 static int cury = 0; 940 char tgoto_buf[256]; 941 942 if ((lpoint = lpnt - lpbuf) > 0) { 943 #ifdef EXTRA 944 c[BYTESOUT] += lpoint; 945 #endif 946 if (enable_scroll <= -1) { 947 flush_buf(); 948 if (write(lfd, lpbuf, lpoint) != lpoint) 949 write(2, "error writing to output file\n", 29); 950 lpnt = lpbuf; /* point back to beginning of buffer */ 951 return; 952 } 953 for (str = lpbuf; str < lpnt; str++) { 954 if (*str >= 32) { 955 xputchar(*str); 956 curx++; 957 } else 958 switch (*str) { 959 case CLEAR: 960 tputs(CL, 0, xputchar); 961 curx = cury = 0; 962 break; 963 964 case CL_LINE: 965 tputs(CE, 0, xputchar); 966 break; 967 968 case CL_DOWN: 969 tputs(CD, 0, xputchar); 970 break; 971 972 case ST_START: 973 tputs(SO, 0, xputchar); 974 break; 975 976 case ST_END: 977 tputs(SE, 0, xputchar); 978 break; 979 980 case CURSOR: 981 curx = *++str - 1; 982 cury = *++str - 1; 983 if (t_goto(info, CM, curx, cury, 984 tgoto_buf, 255) == 0) 985 tputs(tgoto_buf, 0, xputchar); 986 break; 987 988 case '\n': 989 if ((cury == 23) && enable_scroll) { 990 if (!DL || !AL) { /* wraparound or scroll? */ 991 if (++scrline > 23) 992 scrline = 19; 993 994 if (++scrline > 23) 995 scrline = 19; 996 if (t_goto(info, CM, 0, 997 scrline, 998 tgoto_buf, 999 255) == 0) 1000 tputs(tgoto_buf, 1001 0, 1002 xputchar); 1003 tputs(CE, 0, xputchar); 1004 1005 if (--scrline < 19) 1006 scrline = 23; 1007 if (t_goto(info, CM, 0, 1008 scrline, 1009 tgoto_buf, 1010 255) == 0) 1011 tputs(tgoto_buf, 1012 0, 1013 xputchar); 1014 tputs(CE, 0, xputchar); 1015 } else { 1016 if (t_goto(info, CM, 0, 1017 19, 1018 tgoto_buf, 1019 255) == 0) 1020 tputs(tgoto_buf, 1021 0, 1022 xputchar); 1023 tputs(DL, 0, xputchar); 1024 if (t_goto(info, CM, 0, 1025 23, 1026 tgoto_buf, 1027 255) == 0) 1028 tputs(tgoto_buf, 1029 0, 1030 xputchar); 1031 /* 1032 * tputs (AL, 0, 1033 * xputchar); 1034 */ 1035 } 1036 } else { 1037 xputchar('\n'); 1038 cury++; 1039 } 1040 curx = 0; 1041 break; 1042 1043 default: 1044 xputchar(*str); 1045 curx++; 1046 }; 1047 } 1048 } 1049 lpnt = lpbuf; 1050 flush_buf(); /* flush real output buffer now */ 1051 } 1052 #else /* VT100 */ 1053 /* 1054 * lflush() flush the output buffer 1055 * 1056 * Returns nothing of value. 1057 */ 1058 void 1059 lflush() 1060 { 1061 int lpoint; 1062 if ((lpoint = lpnt - lpbuf) > 0) { 1063 #ifdef EXTRA 1064 c[BYTESOUT] += lpoint; 1065 #endif 1066 if (write(lfd, lpbuf, lpoint) != lpoint) 1067 write(2, "error writing to output file\n", 29); 1068 } 1069 lpnt = lpbuf; /* point back to beginning of buffer */ 1070 } 1071 #endif /* VT100 */ 1072 1073 #ifndef VT100 1074 static int vindex = 0; 1075 /* 1076 * xputchar(ch) Print one character in decoded output buffer. 1077 */ 1078 int 1079 xputchar(c) 1080 int c; 1081 { 1082 outbuf[vindex++] = c; 1083 if (vindex >= BUFBIG) 1084 flush_buf(); 1085 return (0); 1086 } 1087 1088 /* 1089 * flush_buf() Flush buffer with decoded output. 1090 */ 1091 void 1092 flush_buf() 1093 { 1094 if (vindex) 1095 write(lfd, outbuf, vindex); 1096 vindex = 0; 1097 } 1098 1099 /* 1100 * char *tmcapcnv(sd,ss) Routine to convert VT100 escapes to termcap 1101 * format 1102 * Processes only the \33[#m sequence (converts . files for termcap use 1103 */ 1104 char * 1105 tmcapcnv(sd, ss) 1106 char *sd, *ss; 1107 { 1108 int tmstate = 0; /* 0=normal, 1=\33 2=[ 3=# */ 1109 char tmdigit = 0; /* the # in \33[#m */ 1110 while (*ss) { 1111 switch (tmstate) { 1112 case 0: 1113 if (*ss == '\33') { 1114 tmstate++; 1115 break; 1116 } 1117 ign: *sd++ = *ss; 1118 ign2: tmstate = 0; 1119 break; 1120 case 1: 1121 if (*ss != '[') 1122 goto ign; 1123 tmstate++; 1124 break; 1125 case 2: 1126 if (isdigit((u_char)*ss)) { 1127 tmdigit = *ss - '0'; 1128 tmstate++; 1129 break; 1130 } 1131 if (*ss == 'm') { 1132 *sd++ = ST_END; 1133 goto ign2; 1134 } 1135 goto ign; 1136 case 3: 1137 if (*ss == 'm') { 1138 if (tmdigit) 1139 *sd++ = ST_START; 1140 else 1141 *sd++ = ST_END; 1142 goto ign2; 1143 } 1144 default: 1145 goto ign; 1146 }; 1147 ss++; 1148 } 1149 *sd = 0; /* NULL terminator */ 1150 return (sd); 1151 } 1152 #endif /* VT100 */ 1153 1154 /* 1155 * beep() Routine to emit a beep if enabled (see no-beep in .larnopts) 1156 */ 1157 void 1158 beep() 1159 { 1160 if (!nobeep) 1161 *lpnt++ = '\7'; 1162 } 1163