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