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