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.4 2006/08/08 16:36:11 pavalos Exp $ 36 */ 37 38 #include <string.h> 39 #include <termcap.h> 40 #include "back.h" 41 42 static void bsect(int, int, int, int); 43 static void fixpos(int, int, int, int, int); 44 static void fixcol(int, int, int, int, int); 45 static void newline(void); 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 void 89 fboard(void) 90 { 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 static void 199 bsect(int b, int rpos, int cpos, int cnext) 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 bct = 0; 208 n = abs(b); /* initialize n and pc */ 209 pc = (b > 0? 'r': 'w'); 210 211 if (n < 6 && cpos < 54) /* position cursor at start */ 212 curmove (rpos,cpos+1); 213 else 214 curmove (rpos,cpos); 215 216 for (j = 0; j < 5; j++) { /* print position row by row */ 217 218 for (k = 0; k < 15; k += 5) /* print men */ 219 if (n > j+k) 220 fancyc (pc); 221 222 if (j < 4) { /* figure how far to 223 * back up for next 224 * row */ 225 if (n < 6) { /* stop if none left */ 226 if (j+1 == n) 227 break; 228 bct = 1; /* single column */ 229 } else { 230 if (n < 11) { /* two columns */ 231 if (cpos == 54) { /* home pos */ 232 if (j+5 >= n) 233 bct = 1; 234 else 235 bct = 2; 236 } 237 if (cpos < 54) { /* not home */ 238 if (j+6 >= n) 239 bct = 1; 240 else 241 bct = 2; 242 } 243 } else { /* three columns */ 244 if (j+10 >= n) 245 bct = 2; 246 else 247 bct = 3; 248 } 249 } 250 curmove (curr+cnext,curc-bct); /* reposition cursor */ 251 } 252 } 253 } 254 255 void 256 refresh(void) 257 { 258 int i, r, c; 259 260 r = curr; /* save current position */ 261 c = curc; 262 263 for (i = 12; i > 6; i--) /* fix positions 12-7 */ 264 if (board[i] != oldb[i]) { 265 fixpos (oldb[i],board[i],13,1+(12-i)*4,-1); 266 oldb[i] = board[i]; 267 } 268 269 if (board[0] != oldb[0]) { /* fix red men on bar */ 270 fixpos (oldb[0],board[0],13,25,-1); 271 oldb[0] = board[0]; 272 } 273 274 for (i = 6; i > 0; i--) /* fix positions 6-1 */ 275 if (board[i] != oldb[i]) { 276 fixpos (oldb[i],board[i],13,29+(6-i)*4,-1); 277 oldb[i] = board[i]; 278 } 279 280 i = -(off[0] < 0? off[0]+15: off[0]); /* fix white's home */ 281 if (oldw != i) { 282 fixpos (oldw,i,13,54,-1); 283 oldw = i; 284 } 285 286 for (i = 13; i < 19; i++) /* fix positions 13-18 */ 287 if (board[i] != oldb[i]) { 288 fixpos (oldb[i],board[i],3,1+(i-13)*4,1); 289 oldb[i] = board[i]; 290 } 291 292 if (board[25] != oldb[25]) { /* fix white men on bar */ 293 fixpos (oldb[25],board[25],3,25,1); 294 oldb[25] = board[25]; 295 } 296 297 for (i = 19; i < 25; i++) /* fix positions 19-24 */ 298 if (board[i] != oldb[i]) { 299 fixpos (oldb[i],board[i],3,29+(i-19)*4,1); 300 oldb[i] = board[i]; 301 } 302 303 i = (off[1] < 0? off[1]+15: off[1]); /* fix red's home */ 304 if (oldr != i) { 305 fixpos (oldr,i,3,54,1); 306 oldr = i; 307 } 308 309 curmove (r,c); /* return to saved position */ 310 newpos(); 311 buflush(); 312 } 313 314 static void 315 fixpos(int cur, int new, int r, int c, int inc) 316 { 317 int o, n, nv; 318 int ov, nc; 319 char col; 320 321 nc = 0; 322 if (cur*new >= 0) { 323 ov = abs(cur); 324 nv = abs(new); 325 col = (cur+new > 0? 'r': 'w'); 326 o = (ov-1)/5; 327 n = (nv-1)/5; 328 if (o == n) { 329 if (o == 2) 330 nc = c+2; 331 if (o == 1) 332 nc = c < 54? c: c+1; 333 if (o == 0) 334 nc = c < 54? c+1: c; 335 if (ov > nv) 336 fixcol (r+inc*(nv-n*5),nc,abs(ov-nv),' ',inc); 337 else 338 fixcol (r+inc*(ov-o*5),nc,abs(ov-nv),col,inc); 339 return; 340 } else { 341 if (c < 54) { 342 if (o+n == 1) { 343 if (n) { 344 fixcol (r,c,abs(nv-5),col,inc); 345 if (ov != 5) 346 fixcol (r+inc*ov,c+1,abs(ov-5),col,inc); 347 } else { 348 fixcol (r,c,abs(ov-5),' ',inc); 349 if (nv != 5) 350 fixcol (r+inc*nv,c+1,abs(nv-5),' ',inc); 351 } 352 return; 353 } 354 if (n == 2) { 355 if (ov != 10) 356 fixcol (r+inc*(ov-5),c,abs(ov-10),col,inc); 357 fixcol (r,c+2,abs(nv-10),col,inc); 358 } else { 359 if (nv != 10) 360 fixcol (r+inc*(nv-5),c,abs(nv-10),' ',inc); 361 fixcol (r,c+2,abs(ov-10),' ',inc); 362 } 363 return; 364 } 365 if (n > o) { 366 fixcol (r+inc*(ov%5),c+o,abs(5*n-ov),col,inc); 367 if (nv != 5*n) 368 fixcol (r,c+n,abs(5*n-nv),col,inc); 369 } else { 370 fixcol (r+inc*(nv%5),c+n,abs(5*n-nv),' ',inc); 371 if (ov != 5*o) 372 fixcol (r,c+o,abs(5*o-ov),' ',inc); 373 } 374 return; 375 } 376 } 377 nv = abs(new); 378 fixcol (r,c+1,nv,new > 0? 'r': 'w',inc); 379 if (abs(cur) <= abs(new)) 380 return; 381 fixcol (r+inc*new,c+1,abs(cur+new),' ',inc); 382 } 383 384 static void 385 fixcol(int r, int c, int l, int ch, int inc) 386 { 387 int i; 388 389 curmove (r,c); 390 fancyc (ch); 391 for (i = 1; i < l; i++) { 392 curmove (curr+inc,curc-1); 393 fancyc (ch); 394 } 395 } 396 397 void 398 curmove(int r, int c) 399 { 400 if (curr == r && curc == c) 401 return; 402 if (realr == -1) { 403 realr = curr; 404 realc = curc; 405 } 406 curr = r; 407 curc = c; 408 } 409 410 void 411 newpos(void) 412 { 413 int r; /* destination row */ 414 int c; /* destination column */ 415 int mode = -1; /* mode of movement */ 416 417 int ccount = 1000; /* character count */ 418 int i; /* index */ 419 int n; /* temporary variable */ 420 char *m; /* string containing CM movement */ 421 422 m = NULL; 423 if (realr == -1) /* see if already there */ 424 return; 425 426 r = curr; /* set current and dest. positions */ 427 c = curc; 428 curr = realr; 429 curc = realc; 430 431 /* double check position */ 432 if (curr == r && curc == c) { 433 realr = realc = -1; 434 return; 435 } 436 437 if (CM) { /* try CM to get there */ 438 mode = 0; 439 m = (char *)tgoto (CM,c,r); 440 ccount = strlen (m); 441 } 442 443 /* try HO and local movement */ 444 if (HO && (n = r+c*lND+lHO) < ccount) { 445 mode = 1; 446 ccount = n; 447 } 448 449 /* try various LF combinations */ 450 if (r >= curr) { 451 /* CR, LF, and ND */ 452 if ((n = (r-curr)+c*lND+1) < ccount) { 453 mode = 2; 454 ccount = n; 455 } 456 /* LF, ND */ 457 if (c >= curc && (n = (r-curr)+(c-curc)*lND) < ccount) { 458 mode = 3; 459 ccount = n; 460 } 461 /* LF, BS */ 462 if (c < curc && (n = (r-curr)+(curc-c)*lBC) < ccount) { 463 mode = 4; 464 ccount = n; 465 } 466 } 467 468 /* try corresponding UP combinations */ 469 if (r < curr) { 470 /* CR, UP, and ND */ 471 if ((n = (curr-r)*lUP+c*lND+1) < ccount) { 472 mode = 5; 473 ccount = n; 474 } 475 /* UP and ND */ 476 if (c >= curc && (n = (curr-r)*lUP+(c-curc)*lND) < ccount) { 477 mode = 6; 478 ccount = n; 479 } 480 /* UP and BS */ 481 if (c < curc && (n = (curr-r)*lUP+(curc-c)*lBC) < ccount) { 482 mode = 7; 483 ccount = n; 484 } 485 } 486 487 /* space over */ 488 if (curr == r && c > curc && linect[r] < curc && c-curc < ccount) 489 mode = 8; 490 491 switch (mode) { 492 493 case -1: /* error! */ 494 write (2,"\r\nInternal cursor error.\r\n",26); 495 getout(); 496 497 /* direct cursor motion */ 498 case 0: 499 tputs (m,abs(curr-r),addbuf); 500 break; 501 502 /* relative to "home" */ 503 case 1: 504 tputs (HO,r,addbuf); 505 for (i = 0; i < r; i++) 506 addbuf ('\012'); 507 for (i = 0; i < c; i++) 508 tputs (ND,1,addbuf); 509 break; 510 511 /* CR and down and over */ 512 case 2: 513 addbuf ('\015'); 514 for (i = 0; i < r-curr; i++) 515 addbuf ('\012'); 516 for (i = 0; i < c; i++) 517 tputs (ND,1,addbuf); 518 break; 519 520 /* down and over */ 521 case 3: 522 for (i = 0; i < r-curr; i++) 523 addbuf ('\012'); 524 for (i = 0; i < c-curc; i++) 525 tputs (ND,1,addbuf); 526 break; 527 528 /* down and back */ 529 case 4: 530 for (i = 0; i < r-curr; i++) 531 addbuf ('\012'); 532 for (i = 0; i < curc-c; i++) 533 addbuf ('\010'); 534 break; 535 536 /* CR and up and over */ 537 case 5: 538 addbuf ('\015'); 539 for (i = 0; i < curr-r; i++) 540 tputs (UP,1,addbuf); 541 for (i = 0; i < c; i++) 542 tputs (ND,1,addbuf); 543 break; 544 545 /* up and over */ 546 case 6: 547 for (i = 0; i < curr-r; i++) 548 tputs (UP,1,addbuf); 549 for (i = 0; i < c-curc; i++) 550 tputs (ND,1,addbuf); 551 break; 552 553 /* up and back */ 554 case 7: 555 for (i = 0; i < curr-r; i++) 556 tputs (UP,1,addbuf); 557 for (i = 0; i < curc-c; i++) { 558 if (BC) 559 tputs (BC,1,addbuf); 560 else 561 addbuf ('\010'); 562 } 563 break; 564 565 /* safe space */ 566 case 8: 567 for (i = 0; i < c-curc; i++) 568 addbuf (' '); 569 } 570 571 /* fix positions */ 572 curr = r; 573 curc = c; 574 realr = -1; 575 realc = -1; 576 } 577 578 void 579 clear(void) 580 { 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 /* input is character to output */ 599 void 600 fancyc(char c) 601 { 602 int sp; /* counts spaces in a tab */ 603 604 if (c == '\007') { /* bells go in blindly */ 605 addbuf (c); 606 return; 607 } 608 609 /* process tabs, use spaces if the 610 * the tab should be erasing things, 611 * otherwise use cursor movement 612 * routines. Note this does not use 613 * hardware tabs at all. */ 614 if (c == '\t') { 615 sp = (curc+8) & (~ 7); /* compute spaces */ 616 /* check line length */ 617 if (linect[curr] >= curc || sp < 4) { 618 for (; sp > curc; sp--) 619 addbuf (' '); 620 curc = sp; /* fix curc */ 621 } else 622 curmove (curr,sp); 623 return; 624 } 625 626 /* do newline be calling newline */ 627 if (c == '\n') { 628 newline(); 629 return; 630 } 631 632 /* ignore any other control chars */ 633 if (c < ' ') 634 return; 635 636 /* if an erasing space or non-space, 637 * just add it to buffer. Otherwise 638 * use cursor movement routine, so that 639 * multiple spaces will be grouped 640 * together */ 641 if (c > ' ' || linect[curr] >= curc) { 642 newpos (); /* make sure position correct */ 643 addbuf (c); /* add character to buffer */ 644 /* fix line length */ 645 if (c == ' ' && linect[curr] == curc) 646 linect[curr]--; 647 else if (linect[curr] < curc) 648 linect[curr] = curc; 649 curc++; /* fix curc */ 650 } else 651 /* use cursor movement routine */ 652 curmove (curr,curc+1); 653 } 654 655 void 656 clend(void) 657 { 658 int i; 659 660 if (CD) { 661 tputs (CD,CO-curr,addbuf); 662 for (i = curr; i < LI; i++) 663 linect[i] = -1; 664 return; 665 } 666 667 curmove (i = curr,0); 668 cline(); 669 while (curr < LI-1) { 670 curmove (curr+1,0); 671 if (linect[curr] > -1) 672 cline (); 673 } 674 curmove (i,0); 675 } 676 677 void 678 cline(void) 679 { 680 int c; 681 682 if (curc > linect[curr]) 683 return; 684 newpos (); 685 if (CE) { 686 tputs (CE,1,addbuf); 687 linect[curr] = curc-1; 688 } else { 689 c = curc-1; 690 while (linect[curr] > c) { 691 addbuf (' '); 692 curc++; 693 linect[curr]--; 694 } 695 curmove (curr,c+1); 696 } 697 } 698 699 static void 700 newline(void) 701 { 702 cline(); 703 if (curr == LI-1) 704 curmove (begscr,0); 705 else 706 curmove (curr+1,0); 707 } 708 709 int 710 getcaps(const char *s) 711 { 712 char *code; /* two letter code */ 713 char ***cap; /* pointer to cap string */ 714 char *bufp; /* pointer to cap buffer */ 715 char tentry[1024]; /* temporary uncoded caps buffer */ 716 717 tgetent (tentry, s); /* get uncoded termcap entry */ 718 719 LI = tgetnum ("li"); /* get number of lines */ 720 if (LI == -1) 721 LI = 12; 722 CO = tgetnum ("co"); /* get number of columns */ 723 if (CO == -1) 724 CO = 65; 725 726 bufp = tbuf; /* get padding character */ 727 tgetstr ("pc",&bufp); 728 if (bufp != tbuf) 729 PC = *tbuf; 730 else 731 PC = 0; 732 733 bufp = tbuf; /* get string entries */ 734 cap = tstr; 735 for (code = tcap; *code; code += 2) 736 **cap++ = (char *)tgetstr (code,&bufp); 737 738 /* get pertinent lengths */ 739 if (HO) 740 lHO = strlen (HO); 741 if (BC) 742 lBC = strlen (BC); 743 else 744 lBC = 1; 745 if (UP) 746 lUP = strlen (UP); 747 if (ND) 748 lND = strlen (ND); 749 if (LI < 24 || CO < 72 || !(CL && UP && ND)) 750 return (0); 751 linect = (int *)calloc (LI+1,sizeof(int)); 752 return (1); 753 } 754