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