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