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