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