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