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