1 /* 2 * Copyright (c) 1980, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 #if 0 36 static char sccsid[] = "@(#)fancy.c 8.1 (Berkeley) 5/31/93"; 37 #endif 38 static const char rcsid[] = 39 "$FreeBSD: src/games/backgammon/common_source/fancy.c,v 1.7 1999/11/30 03:48:25 billf Exp $"; 40 #endif /* not lint */ 41 42 #include <stdlib.h> 43 #include <string.h> 44 #include <termcap.h> 45 #include "back.h" 46 47 char PC; /* padding character */ 48 char *BC; /* backspace sequence */ 49 char *CD; /* clear to end of screen sequence */ 50 char *CE; /* clear to end of line sequence */ 51 char *CL; /* clear screen sequence */ 52 char *CM; /* cursor movement instructions */ 53 char *HO; /* home cursor sequence */ 54 char *MC; /* column cursor movement map */ 55 char *ML; /* row cursor movement map */ 56 char *ND; /* forward cursor sequence */ 57 char *UP; /* up cursor sequence */ 58 59 int lHO; /* length of HO */ 60 int lBC; /* length of BC */ 61 int lND; /* length of ND */ 62 int lUP; /* length of UP */ 63 int CO; /* number of columns */ 64 int LI; /* number of lines */ 65 int *linect; /* array of lengths of lines on screen 66 (the actual screen is not stored) */ 67 68 /* two letter codes */ 69 char tcap[] = "bccdceclcmhomcmlndup"; 70 /* corresponding strings */ 71 char **tstr[] = { &BC, &CD, &CE, &CL, &CM, &HO, &MC, &ML, &ND, &UP }; 72 73 int buffnum; /* pointer to output buffer */ 74 75 char tbuf[1024]; /* buffer for decoded termcap entries */ 76 77 int oldb[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 78 79 int oldr; 80 int oldw; 81 /* "real" cursor positions, so 82 * it knows when to reposition. 83 * These are -1 if curr and curc 84 * are accurate */ 85 int realr; 86 int realc; 87 88 int addbuf __P((int)); 89 90 fboard () { 91 int i, j, l; 92 93 curmove (0,0); /* do top line */ 94 for (i = 0; i < 53; i++) 95 fancyc ('_'); 96 97 curmove (15,0); /* do botttom line */ 98 for (i = 0; i < 53; i++) 99 fancyc ('_'); 100 101 l = 1; /* do vertical lines */ 102 for (i = 52; i > -1; i -= 28) { 103 curmove ( (l == 1? 1: 15) ,i); 104 fancyc ('|'); 105 for (j = 0; j < 14; j++) { 106 curmove (curr+l,curc-1); 107 fancyc ('|'); 108 } 109 if (i == 24) 110 i += 32; 111 l = -l; /* alternate directions */ 112 } 113 114 curmove (2,1); /* label positions 13-18 */ 115 for (i = 13; i < 18; i++) { 116 fancyc ('1'); 117 fancyc ((i % 10)+'0'); 118 curmove (curr,curc+2); 119 } 120 fancyc ('1'); 121 fancyc ('8'); 122 123 curmove (2,29); /* label positions 19-24 */ 124 fancyc ('1'); 125 fancyc ('9'); 126 for (i = 20; i < 25; i++) { 127 curmove (curr,curc+2); 128 fancyc ('2'); 129 fancyc ((i % 10)+'0'); 130 } 131 132 curmove (14,1); /* label positions 12-7 */ 133 fancyc ('1'); 134 fancyc ('2'); 135 for (i = 11; i > 6; i--) { 136 curmove (curr,curc+2); 137 fancyc (i > 9? '1': ' '); 138 fancyc ((i % 10)+'0'); 139 } 140 141 curmove (14,30); /* label positions 6-1 */ 142 fancyc ('6'); 143 for (i = 5; i > 0; i--) { 144 curmove (curr,curc+3); 145 fancyc (i+'0'); 146 } 147 148 for (i = 12; i > 6; i--) /* print positions 12-7 */ 149 if (board[i]) 150 bsect (board[i],13,1+4*(12-i),-1); 151 152 if (board[0]) /* print red men on bar */ 153 bsect (board[0],13,25,-1); 154 155 for (i = 6; i > 0; i--) /* print positions 6-1 */ 156 if (board[i]) 157 bsect (board[i],13,29+4*(6-i),-1); 158 159 l = (off[1] < 0? off[1]+15: off[1]); /* print white's home */ 160 bsect (l,3,54,1); 161 162 curmove (8,25); /* print the word BAR */ 163 fancyc ('B'); 164 fancyc ('A'); 165 fancyc ('R'); 166 167 for (i = 13; i < 19; i++) /* print positions 13-18 */ 168 if (board[i]) 169 bsect (board[i],3,1+4*(i-13),1); 170 171 if (board[25]) /* print white's men on bar */ 172 bsect (board[25],3,25,1); 173 174 for (i = 19; i < 25; i++) /* print positions 19-24 */ 175 if (board[i]) 176 bsect (board[i],3,29+4*(i-19),1); 177 178 l = (off[0] < 0? off[0]+15: off[0]); /* print red's home */ 179 bsect (-l,13,54,-1); 180 181 for (i = 0; i < 26; i++) /* save board position 182 * for refresh later */ 183 oldb[i] = board[i]; 184 oldr = (off[1] < 0? off[1]+15: off[1]); 185 oldw = -(off[0] < 0? off[0]+15: off[0]); 186 } 187 188 /* 189 * bsect (b,rpos,cpos,cnext) 190 * Print the contents of a board position. "b" has the value of the 191 * position, "rpos" is the row to start printing, "cpos" is the column to 192 * start printing, and "cnext" is positive if the position starts at the top 193 * and negative if it starts at the bottom. The value of "cpos" is checked 194 * to see if the position is a player's home, since those are printed 195 * differently. 196 */ 197 198 bsect (b,rpos,cpos,cnext) 199 int b; /* contents of position */ 200 int rpos; /* row of position */ 201 int cpos; /* column of position */ 202 int cnext; /* direction of position */ 203 204 { 205 int j; /* index */ 206 int n; /* number of men on position */ 207 int bct; /* counter */ 208 int k; /* index */ 209 char pc; /* color of men on position */ 210 211 n = abs(b); /* initialize n and pc */ 212 pc = (b > 0? 'r': 'w'); 213 214 if (n < 6 && cpos < 54) /* position cursor at start */ 215 curmove (rpos,cpos+1); 216 else 217 curmove (rpos,cpos); 218 219 for (j = 0; j < 5; j++) { /* print position row by row */ 220 221 for (k = 0; k < 15; k += 5) /* print men */ 222 if (n > j+k) 223 fancyc (pc); 224 225 if (j < 4) { /* figure how far to 226 * back up for next 227 * row */ 228 if (n < 6) { /* stop if none left */ 229 if (j+1 == n) 230 break; 231 bct = 1; /* single column */ 232 } else { 233 if (n < 11) { /* two columns */ 234 if (cpos == 54) { /* home pos */ 235 if (j+5 >= n) 236 bct = 1; 237 else 238 bct = 2; 239 } 240 if (cpos < 54) { /* not home */ 241 if (j+6 >= n) 242 bct = 1; 243 else 244 bct = 2; 245 } 246 } else { /* three columns */ 247 if (j+10 >= n) 248 bct = 2; 249 else 250 bct = 3; 251 } 252 } 253 curmove (curr+cnext,curc-bct); /* reposition cursor */ 254 } 255 } 256 } 257 258 refresh() { 259 int i, r, c; 260 261 r = curr; /* save current position */ 262 c = curc; 263 264 for (i = 12; i > 6; i--) /* fix positions 12-7 */ 265 if (board[i] != oldb[i]) { 266 fixpos (oldb[i],board[i],13,1+(12-i)*4,-1); 267 oldb[i] = board[i]; 268 } 269 270 if (board[0] != oldb[0]) { /* fix red men on bar */ 271 fixpos (oldb[0],board[0],13,25,-1); 272 oldb[0] = board[0]; 273 } 274 275 for (i = 6; i > 0; i--) /* fix positions 6-1 */ 276 if (board[i] != oldb[i]) { 277 fixpos (oldb[i],board[i],13,29+(6-i)*4,-1); 278 oldb[i] = board[i]; 279 } 280 281 i = -(off[0] < 0? off[0]+15: off[0]); /* fix white's home */ 282 if (oldw != i) { 283 fixpos (oldw,i,13,54,-1); 284 oldw = i; 285 } 286 287 for (i = 13; i < 19; i++) /* fix positions 13-18 */ 288 if (board[i] != oldb[i]) { 289 fixpos (oldb[i],board[i],3,1+(i-13)*4,1); 290 oldb[i] = board[i]; 291 } 292 293 if (board[25] != oldb[25]) { /* fix white men on bar */ 294 fixpos (oldb[25],board[25],3,25,1); 295 oldb[25] = board[25]; 296 } 297 298 for (i = 19; i < 25; i++) /* fix positions 19-24 */ 299 if (board[i] != oldb[i]) { 300 fixpos (oldb[i],board[i],3,29+(i-19)*4,1); 301 oldb[i] = board[i]; 302 } 303 304 i = (off[1] < 0? off[1]+15: off[1]); /* fix red's home */ 305 if (oldr != i) { 306 fixpos (oldr,i,3,54,1); 307 oldr = i; 308 } 309 310 curmove (r,c); /* return to saved position */ 311 newpos(); 312 buflush(); 313 } 314 315 fixpos (old,new,r,c,inc) 316 int old, new, r, c, inc; 317 318 { 319 int o, n, nv; 320 int ov, nc; 321 char col; 322 323 if (old*new >= 0) { 324 ov = abs(old); 325 nv = abs(new); 326 col = (old+new > 0? 'r': 'w'); 327 o = (ov-1)/5; 328 n = (nv-1)/5; 329 if (o == n) { 330 if (o == 2) 331 nc = c+2; 332 if (o == 1) 333 nc = c < 54? c: c+1; 334 if (o == 0) 335 nc = c < 54? c+1: c; 336 if (ov > nv) 337 fixcol (r+inc*(nv-n*5),nc,abs(ov-nv),' ',inc); 338 else 339 fixcol (r+inc*(ov-o*5),nc,abs(ov-nv),col,inc); 340 return; 341 } else { 342 if (c < 54) { 343 if (o+n == 1) { 344 if (n) { 345 fixcol (r,c,abs(nv-5),col,inc); 346 if (ov != 5) 347 fixcol (r+inc*ov,c+1,abs(ov-5),col,inc); 348 } else { 349 fixcol (r,c,abs(ov-5),' ',inc); 350 if (nv != 5) 351 fixcol (r+inc*nv,c+1,abs(nv-5),' ',inc); 352 } 353 return; 354 } 355 if (n == 2) { 356 if (ov != 10) 357 fixcol (r+inc*(ov-5),c,abs(ov-10),col,inc); 358 fixcol (r,c+2,abs(nv-10),col,inc); 359 } else { 360 if (nv != 10) 361 fixcol (r+inc*(nv-5),c,abs(nv-10),' ',inc); 362 fixcol (r,c+2,abs(ov-10),' ',inc); 363 } 364 return; 365 } 366 if (n > o) { 367 fixcol (r+inc*(ov%5),c+o,abs(5*n-ov),col,inc); 368 if (nv != 5*n) 369 fixcol (r,c+n,abs(5*n-nv),col,inc); 370 } else { 371 fixcol (r+inc*(nv%5),c+n,abs(5*n-nv),' ',inc); 372 if (ov != 5*o) 373 fixcol (r,c+o,abs(5*o-ov),' ',inc); 374 } 375 return; 376 } 377 } 378 nv = abs(new); 379 fixcol (r,c+1,nv,new > 0? 'r': 'w',inc); 380 if (abs(old) <= abs(new)) 381 return; 382 fixcol (r+inc*new,c+1,abs(old+new),' ',inc); 383 } 384 385 fixcol (r,c,l,ch,inc) 386 int l, ch, r, c, inc; 387 388 { 389 int i; 390 391 curmove (r,c); 392 fancyc (ch); 393 for (i = 1; i < l; i++) { 394 curmove (curr+inc,curc-1); 395 fancyc (ch); 396 } 397 } 398 399 curmove (r,c) 400 int r, c; 401 402 { 403 if (curr == r && curc == c) 404 return; 405 if (realr == -1) { 406 realr = curr; 407 realc = curc; 408 } 409 curr = r; 410 curc = c; 411 } 412 413 newpos () { 414 int r; /* destination row */ 415 int c; /* destination column */ 416 int mode = -1; /* mode of movement */ 417 418 int count = 1000; /* character count */ 419 int i; /* index */ 420 int j; /* index */ 421 int n; /* temporary variable */ 422 char *m; /* string containing CM movement */ 423 424 425 if (realr == -1) /* see if already there */ 426 return; 427 428 r = curr; /* set current and dest. positions */ 429 c = curc; 430 curr = realr; 431 curc = realc; 432 433 /* double check position */ 434 if (curr == r && curc == c) { 435 realr = realc = -1; 436 return; 437 } 438 439 if (CM) { /* try CM to get there */ 440 mode = 0; 441 m = (char *)tgoto (CM,c,r); 442 count = strlen (m); 443 } 444 445 /* try HO and local movement */ 446 if (HO && (n = r+c*lND+lHO) < count) { 447 mode = 1; 448 count = n; 449 } 450 451 /* try various LF combinations */ 452 if (r >= curr) { 453 /* CR, LF, and ND */ 454 if ((n = (r-curr)+c*lND+1) < count) { 455 mode = 2; 456 count = n; 457 } 458 /* LF, ND */ 459 if (c >= curc && (n = (r-curr)+(c-curc)*lND) < count) { 460 mode = 3; 461 count = n; 462 } 463 /* LF, BS */ 464 if (c < curc && (n = (r-curr)+(curc-c)*lBC) < count) { 465 mode = 4; 466 count = n; 467 } 468 } 469 470 /* try corresponding UP combinations */ 471 if (r < curr) { 472 /* CR, UP, and ND */ 473 if ((n = (curr-r)*lUP+c*lND+1) < count) { 474 mode = 5; 475 count = n; 476 } 477 /* UP and ND */ 478 if (c >= curc && (n = (curr-r)*lUP+(c-curc)*lND) < count) { 479 mode = 6; 480 count = n; 481 } 482 /* UP and BS */ 483 if (c < curc && (n = (curr-r)*lUP+(curc-c)*lBC) < count) { 484 mode = 7; 485 count = n; 486 } 487 } 488 489 /* space over */ 490 if (curr == r && c > curc && linect[r] < curc && c-curc < count) 491 mode = 8; 492 493 switch (mode) { 494 495 case -1: /* error! */ 496 write (2,"\r\nInternal cursor error.\r\n",26); 497 getout(); 498 499 /* direct cursor motion */ 500 case 0: 501 tputs (m,abs(curr-r),addbuf); 502 break; 503 504 /* relative to "home" */ 505 case 1: 506 tputs (HO,r,addbuf); 507 for (i = 0; i < r; i++) 508 addbuf ('\012'); 509 for (i = 0; i < c; i++) 510 tputs (ND,1,addbuf); 511 break; 512 513 /* CR and down and over */ 514 case 2: 515 addbuf ('\015'); 516 for (i = 0; i < r-curr; i++) 517 addbuf ('\012'); 518 for (i = 0; i < c; i++) 519 tputs (ND,1,addbuf); 520 break; 521 522 /* down and over */ 523 case 3: 524 for (i = 0; i < r-curr; i++) 525 addbuf ('\012'); 526 for (i = 0; i < c-curc; i++) 527 tputs (ND,1,addbuf); 528 break; 529 530 /* down and back */ 531 case 4: 532 for (i = 0; i < r-curr; i++) 533 addbuf ('\012'); 534 for (i = 0; i < curc-c; i++) 535 addbuf ('\010'); 536 break; 537 538 /* CR and up and over */ 539 case 5: 540 addbuf ('\015'); 541 for (i = 0; i < curr-r; i++) 542 tputs (UP,1,addbuf); 543 for (i = 0; i < c; i++) 544 tputs (ND,1,addbuf); 545 break; 546 547 /* up and over */ 548 case 6: 549 for (i = 0; i < curr-r; i++) 550 tputs (UP,1,addbuf); 551 for (i = 0; i < c-curc; i++) 552 tputs (ND,1,addbuf); 553 break; 554 555 /* up and back */ 556 case 7: 557 for (i = 0; i < curr-r; i++) 558 tputs (UP,1,addbuf); 559 for (i = 0; i < curc-c; i++) { 560 if (BC) 561 tputs (BC,1,addbuf); 562 else 563 addbuf ('\010'); 564 } 565 break; 566 567 /* safe space */ 568 case 8: 569 for (i = 0; i < c-curc; i++) 570 addbuf (' '); 571 } 572 573 /* fix positions */ 574 curr = r; 575 curc = c; 576 realr = -1; 577 realc = -1; 578 } 579 580 clear () { 581 int i; 582 583 /* double space if can't clear */ 584 if (CL == 0) { 585 writel ("\n\n"); 586 return; 587 } 588 589 curr = curc = 0; /* fix position markers */ 590 realr = realc = -1; 591 for (i = 0; i < 24; i++) /* clear line counts */ 592 linect[i] = -1; 593 buffnum = -1; /* ignore leftover buffer contents */ 594 tputs (CL,CO,addbuf); /* put CL in buffer */ 595 } 596 597 598 fancyc (c) 599 char c; /* character to output */ 600 { 601 int sp; /* counts spaces in a tab */ 602 603 if (c == '\007') { /* bells go in blindly */ 604 addbuf (c); 605 return; 606 } 607 608 /* process tabs, use spaces if the 609 * the tab should be erasing things, 610 * otherwise use cursor movement 611 * routines. Note this does not use 612 * hardware tabs at all. */ 613 if (c == '\t') { 614 sp = (curc+8) & (~ 7); /* compute spaces */ 615 /* check line length */ 616 if (linect[curr] >= curc || sp < 4) { 617 for (; sp > curc; sp--) 618 addbuf (' '); 619 curc = sp; /* fix curc */ 620 } else 621 curmove (curr,sp); 622 return; 623 } 624 625 /* do newline be calling newline */ 626 if (c == '\n') { 627 newline(); 628 return; 629 } 630 631 /* ignore any other control chars */ 632 if (c < ' ') 633 return; 634 635 /* if an erasing space or non-space, 636 * just add it to buffer. Otherwise 637 * use cursor movement routine, so that 638 * multiple spaces will be grouped 639 * together */ 640 if (c > ' ' || linect[curr] >= curc) { 641 newpos (); /* make sure position correct */ 642 addbuf (c); /* add character to buffer */ 643 /* fix line length */ 644 if (c == ' ' && linect[curr] == curc) 645 linect[curr]--; 646 else if (linect[curr] < curc) 647 linect[curr] = curc; 648 curc++; /* fix curc */ 649 } else 650 /* use cursor movement routine */ 651 curmove (curr,curc+1); 652 } 653 654 clend() { 655 int i; 656 char *s; 657 658 659 if (CD) { 660 tputs (CD,CO-curr,addbuf); 661 for (i = curr; i < LI; i++) 662 linect[i] = -1; 663 return; 664 } 665 666 curmove (i = curr,0); 667 cline(); 668 while (curr < LI-1) { 669 curmove (curr+1,0); 670 if (linect[curr] > -1) 671 cline (); 672 } 673 curmove (i,0); 674 } 675 676 cline () { 677 int i; 678 int c; 679 char *s; 680 681 if (curc > linect[curr]) 682 return; 683 newpos (); 684 if (CE) { 685 tputs (CE,1,addbuf); 686 linect[curr] = curc-1; 687 } else { 688 c = curc-1; 689 while (linect[curr] > c) { 690 addbuf (' '); 691 curc++; 692 linect[curr]--; 693 } 694 curmove (curr,c+1); 695 } 696 } 697 698 newline () { 699 cline(); 700 if (curr == LI-1) 701 curmove (begscr,0); 702 else 703 curmove (curr+1,0); 704 } 705 706 int 707 getcaps (s) 708 const char *s; 709 710 { 711 char *code; /* two letter code */ 712 char ***cap; /* pointer to cap string */ 713 char *bufp; /* pointer to cap buffer */ 714 char tentry[1024]; /* temporary uncoded caps buffer */ 715 716 tgetent (tentry, (char *)s); /* get uncoded termcap entry */ 717 718 LI = tgetnum ("li"); /* get number of lines */ 719 if (LI == -1) 720 LI = 12; 721 CO = tgetnum ("co"); /* get number of columns */ 722 if (CO == -1) 723 CO = 65; 724 725 bufp = tbuf; /* get padding character */ 726 tgetstr ("pc",&bufp); 727 if (bufp != tbuf) 728 PC = *tbuf; 729 else 730 PC = 0; 731 732 bufp = tbuf; /* get string entries */ 733 cap = tstr; 734 for (code = tcap; *code; code += 2) 735 **cap++ = (char *)tgetstr (code,&bufp); 736 737 /* get pertinent lengths */ 738 if (HO) 739 lHO = strlen (HO); 740 if (BC) 741 lBC = strlen (BC); 742 else 743 lBC = 1; 744 if (UP) 745 lUP = strlen (UP); 746 if (ND) 747 lND = strlen (ND); 748 if (LI < 24 || CO < 72 || !(CL && UP && ND)) 749 return (0); 750 linect = (int *)calloc (LI+1,sizeof(int)); 751 return (1); 752 } 753