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