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