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