Use hardware timer to simulate interrupt moderation.
[dragonfly.git] / games / backgammon / common_source / fancy.c
blob3f70c1f8f5dca048bf3ff74c568794d5bead70ee
1 /*
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
33 * @(#)fancy.c 8.1 (Berkeley) 5/31/93
34 * $FreeBSD: src/games/backgammon/common_source/fancy.c,v 1.7 1999/11/30 03:48:25 billf Exp $
35 * $DragonFly: src/games/backgammon/common_source/fancy.c,v 1.4 2006/08/08 16:36:11 pavalos Exp $
38 #include <string.h>
39 #include <termcap.h>
40 #include "back.h"
42 static void bsect(int, int, int, int);
43 static void fixpos(int, int, int, int, int);
44 static void fixcol(int, int, int, int, int);
45 static void newline(void);
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 */
59 int lHO; /* length of HO */
60 int lBC; /* length of BC */
61 int lND; /* length of ND */
62 int lUP; /* length of UP */
63 int CO; /* number of columns */
64 int LI; /* number of lines */
65 int *linect; /* array of lengths of lines on screen
66 (the actual screen is not stored) */
68 /* two letter codes */
69 char tcap[] = "bccdceclcmhomcmlndup";
70 /* corresponding strings */
71 char **tstr[] = { &BC, &CD, &CE, &CL, &CM, &HO, &MC, &ML, &ND, &UP };
73 int buffnum; /* pointer to output buffer */
75 char tbuf[1024]; /* buffer for decoded termcap entries */
77 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};
79 int oldr;
80 int oldw;
81 /* "real" cursor positions, so
82 * it knows when to reposition.
83 * These are -1 if curr and curc
84 * are accurate */
85 int realr;
86 int realc;
88 void
89 fboard(void)
91 int i, j, l;
93 curmove (0,0); /* do top line */
94 for (i = 0; i < 53; i++)
95 fancyc ('_');
97 curmove (15,0); /* do botttom line */
98 for (i = 0; i < 53; i++)
99 fancyc ('_');
101 l = 1; /* do vertical lines */
102 for (i = 52; i > -1; i -= 28) {
103 curmove ( (l == 1? 1: 15) ,i);
104 fancyc ('|');
105 for (j = 0; j < 14; j++) {
106 curmove (curr+l,curc-1);
107 fancyc ('|');
109 if (i == 24)
110 i += 32;
111 l = -l; /* alternate directions */
114 curmove (2,1); /* label positions 13-18 */
115 for (i = 13; i < 18; i++) {
116 fancyc ('1');
117 fancyc ((i % 10)+'0');
118 curmove (curr,curc+2);
120 fancyc ('1');
121 fancyc ('8');
123 curmove (2,29); /* label positions 19-24 */
124 fancyc ('1');
125 fancyc ('9');
126 for (i = 20; i < 25; i++) {
127 curmove (curr,curc+2);
128 fancyc ('2');
129 fancyc ((i % 10)+'0');
132 curmove (14,1); /* label positions 12-7 */
133 fancyc ('1');
134 fancyc ('2');
135 for (i = 11; i > 6; i--) {
136 curmove (curr,curc+2);
137 fancyc (i > 9? '1': ' ');
138 fancyc ((i % 10)+'0');
141 curmove (14,30); /* label positions 6-1 */
142 fancyc ('6');
143 for (i = 5; i > 0; i--) {
144 curmove (curr,curc+3);
145 fancyc (i+'0');
148 for (i = 12; i > 6; i--) /* print positions 12-7 */
149 if (board[i])
150 bsect (board[i],13,1+4*(12-i),-1);
152 if (board[0]) /* print red men on bar */
153 bsect (board[0],13,25,-1);
155 for (i = 6; i > 0; i--) /* print positions 6-1 */
156 if (board[i])
157 bsect (board[i],13,29+4*(6-i),-1);
159 l = (off[1] < 0? off[1]+15: off[1]); /* print white's home */
160 bsect (l,3,54,1);
162 curmove (8,25); /* print the word BAR */
163 fancyc ('B');
164 fancyc ('A');
165 fancyc ('R');
167 for (i = 13; i < 19; i++) /* print positions 13-18 */
168 if (board[i])
169 bsect (board[i],3,1+4*(i-13),1);
171 if (board[25]) /* print white's men on bar */
172 bsect (board[25],3,25,1);
174 for (i = 19; i < 25; i++) /* print positions 19-24 */
175 if (board[i])
176 bsect (board[i],3,29+4*(i-19),1);
178 l = (off[0] < 0? off[0]+15: off[0]); /* print red's home */
179 bsect (-l,13,54,-1);
181 for (i = 0; i < 26; i++) /* save board position
182 * for refresh later */
183 oldb[i] = board[i];
184 oldr = (off[1] < 0? off[1]+15: off[1]);
185 oldw = -(off[0] < 0? off[0]+15: off[0]);
189 * bsect (b,rpos,cpos,cnext)
190 * Print the contents of a board position. "b" has the value of the
191 * position, "rpos" is the row to start printing, "cpos" is the column to
192 * start printing, and "cnext" is positive if the position starts at the top
193 * and negative if it starts at the bottom. The value of "cpos" is checked
194 * to see if the position is a player's home, since those are printed
195 * differently.
198 static void
199 bsect(int b, int rpos, int cpos, int cnext)
201 int j; /* index */
202 int n; /* number of men on position */
203 int bct; /* counter */
204 int k; /* index */
205 char pc; /* color of men on position */
207 bct = 0;
208 n = abs(b); /* initialize n and pc */
209 pc = (b > 0? 'r': 'w');
211 if (n < 6 && cpos < 54) /* position cursor at start */
212 curmove (rpos,cpos+1);
213 else
214 curmove (rpos,cpos);
216 for (j = 0; j < 5; j++) { /* print position row by row */
218 for (k = 0; k < 15; k += 5) /* print men */
219 if (n > j+k)
220 fancyc (pc);
222 if (j < 4) { /* figure how far to
223 * back up for next
224 * 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;
237 if (cpos < 54) { /* not home */
238 if (j+6 >= n)
239 bct = 1;
240 else
241 bct = 2;
243 } else { /* three columns */
244 if (j+10 >= n)
245 bct = 2;
246 else
247 bct = 3;
250 curmove (curr+cnext,curc-bct); /* reposition cursor */
255 void
256 refresh(void)
258 int i, r, c;
260 r = curr; /* save current position */
261 c = curc;
263 for (i = 12; i > 6; i--) /* fix positions 12-7 */
264 if (board[i] != oldb[i]) {
265 fixpos (oldb[i],board[i],13,1+(12-i)*4,-1);
266 oldb[i] = board[i];
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];
274 for (i = 6; i > 0; i--) /* fix positions 6-1 */
275 if (board[i] != oldb[i]) {
276 fixpos (oldb[i],board[i],13,29+(6-i)*4,-1);
277 oldb[i] = board[i];
280 i = -(off[0] < 0? off[0]+15: off[0]); /* fix white's home */
281 if (oldw != i) {
282 fixpos (oldw,i,13,54,-1);
283 oldw = i;
286 for (i = 13; i < 19; i++) /* fix positions 13-18 */
287 if (board[i] != oldb[i]) {
288 fixpos (oldb[i],board[i],3,1+(i-13)*4,1);
289 oldb[i] = board[i];
292 if (board[25] != oldb[25]) { /* fix white men on bar */
293 fixpos (oldb[25],board[25],3,25,1);
294 oldb[25] = board[25];
297 for (i = 19; i < 25; i++) /* fix positions 19-24 */
298 if (board[i] != oldb[i]) {
299 fixpos (oldb[i],board[i],3,29+(i-19)*4,1);
300 oldb[i] = board[i];
303 i = (off[1] < 0? off[1]+15: off[1]); /* fix red's home */
304 if (oldr != i) {
305 fixpos (oldr,i,3,54,1);
306 oldr = i;
309 curmove (r,c); /* return to saved position */
310 newpos();
311 buflush();
314 static void
315 fixpos(int cur, int new, int r, int c, int inc)
317 int o, n, nv;
318 int ov, nc;
319 char col;
321 nc = 0;
322 if (cur*new >= 0) {
323 ov = abs(cur);
324 nv = abs(new);
325 col = (cur+new > 0? 'r': 'w');
326 o = (ov-1)/5;
327 n = (nv-1)/5;
328 if (o == n) {
329 if (o == 2)
330 nc = c+2;
331 if (o == 1)
332 nc = c < 54? c: c+1;
333 if (o == 0)
334 nc = c < 54? c+1: c;
335 if (ov > nv)
336 fixcol (r+inc*(nv-n*5),nc,abs(ov-nv),' ',inc);
337 else
338 fixcol (r+inc*(ov-o*5),nc,abs(ov-nv),col,inc);
339 return;
340 } else {
341 if (c < 54) {
342 if (o+n == 1) {
343 if (n) {
344 fixcol (r,c,abs(nv-5),col,inc);
345 if (ov != 5)
346 fixcol (r+inc*ov,c+1,abs(ov-5),col,inc);
347 } else {
348 fixcol (r,c,abs(ov-5),' ',inc);
349 if (nv != 5)
350 fixcol (r+inc*nv,c+1,abs(nv-5),' ',inc);
352 return;
354 if (n == 2) {
355 if (ov != 10)
356 fixcol (r+inc*(ov-5),c,abs(ov-10),col,inc);
357 fixcol (r,c+2,abs(nv-10),col,inc);
358 } else {
359 if (nv != 10)
360 fixcol (r+inc*(nv-5),c,abs(nv-10),' ',inc);
361 fixcol (r,c+2,abs(ov-10),' ',inc);
363 return;
365 if (n > o) {
366 fixcol (r+inc*(ov%5),c+o,abs(5*n-ov),col,inc);
367 if (nv != 5*n)
368 fixcol (r,c+n,abs(5*n-nv),col,inc);
369 } else {
370 fixcol (r+inc*(nv%5),c+n,abs(5*n-nv),' ',inc);
371 if (ov != 5*o)
372 fixcol (r,c+o,abs(5*o-ov),' ',inc);
374 return;
377 nv = abs(new);
378 fixcol (r,c+1,nv,new > 0? 'r': 'w',inc);
379 if (abs(cur) <= abs(new))
380 return;
381 fixcol (r+inc*new,c+1,abs(cur+new),' ',inc);
384 static void
385 fixcol(int r, int c, int l, int ch, int inc)
387 int i;
389 curmove (r,c);
390 fancyc (ch);
391 for (i = 1; i < l; i++) {
392 curmove (curr+inc,curc-1);
393 fancyc (ch);
397 void
398 curmove(int r, int c)
400 if (curr == r && curc == c)
401 return;
402 if (realr == -1) {
403 realr = curr;
404 realc = curc;
406 curr = r;
407 curc = c;
410 void
411 newpos(void)
413 int r; /* destination row */
414 int c; /* destination column */
415 int mode = -1; /* mode of movement */
417 int ccount = 1000; /* character count */
418 int i; /* index */
419 int n; /* temporary variable */
420 char *m; /* string containing CM movement */
422 m = NULL;
423 if (realr == -1) /* see if already there */
424 return;
426 r = curr; /* set current and dest. positions */
427 c = curc;
428 curr = realr;
429 curc = realc;
431 /* double check position */
432 if (curr == r && curc == c) {
433 realr = realc = -1;
434 return;
437 if (CM) { /* try CM to get there */
438 mode = 0;
439 m = (char *)tgoto (CM,c,r);
440 ccount = strlen (m);
443 /* try HO and local movement */
444 if (HO && (n = r+c*lND+lHO) < ccount) {
445 mode = 1;
446 ccount = n;
449 /* try various LF combinations */
450 if (r >= curr) {
451 /* CR, LF, and ND */
452 if ((n = (r-curr)+c*lND+1) < ccount) {
453 mode = 2;
454 ccount = n;
456 /* LF, ND */
457 if (c >= curc && (n = (r-curr)+(c-curc)*lND) < ccount) {
458 mode = 3;
459 ccount = n;
461 /* LF, BS */
462 if (c < curc && (n = (r-curr)+(curc-c)*lBC) < ccount) {
463 mode = 4;
464 ccount = n;
468 /* try corresponding UP combinations */
469 if (r < curr) {
470 /* CR, UP, and ND */
471 if ((n = (curr-r)*lUP+c*lND+1) < ccount) {
472 mode = 5;
473 ccount = n;
475 /* UP and ND */
476 if (c >= curc && (n = (curr-r)*lUP+(c-curc)*lND) < ccount) {
477 mode = 6;
478 ccount = n;
480 /* UP and BS */
481 if (c < curc && (n = (curr-r)*lUP+(curc-c)*lBC) < ccount) {
482 mode = 7;
483 ccount = n;
487 /* space over */
488 if (curr == r && c > curc && linect[r] < curc && c-curc < ccount)
489 mode = 8;
491 switch (mode) {
493 case -1: /* error! */
494 write (2,"\r\nInternal cursor error.\r\n",26);
495 getout();
497 /* direct cursor motion */
498 case 0:
499 tputs (m,abs(curr-r),addbuf);
500 break;
502 /* relative to "home" */
503 case 1:
504 tputs (HO,r,addbuf);
505 for (i = 0; i < r; i++)
506 addbuf ('\012');
507 for (i = 0; i < c; i++)
508 tputs (ND,1,addbuf);
509 break;
511 /* CR and down and over */
512 case 2:
513 addbuf ('\015');
514 for (i = 0; i < r-curr; i++)
515 addbuf ('\012');
516 for (i = 0; i < c; i++)
517 tputs (ND,1,addbuf);
518 break;
520 /* down and over */
521 case 3:
522 for (i = 0; i < r-curr; i++)
523 addbuf ('\012');
524 for (i = 0; i < c-curc; i++)
525 tputs (ND,1,addbuf);
526 break;
528 /* down and back */
529 case 4:
530 for (i = 0; i < r-curr; i++)
531 addbuf ('\012');
532 for (i = 0; i < curc-c; i++)
533 addbuf ('\010');
534 break;
536 /* CR and up and over */
537 case 5:
538 addbuf ('\015');
539 for (i = 0; i < curr-r; i++)
540 tputs (UP,1,addbuf);
541 for (i = 0; i < c; i++)
542 tputs (ND,1,addbuf);
543 break;
545 /* up and over */
546 case 6:
547 for (i = 0; i < curr-r; i++)
548 tputs (UP,1,addbuf);
549 for (i = 0; i < c-curc; i++)
550 tputs (ND,1,addbuf);
551 break;
553 /* up and back */
554 case 7:
555 for (i = 0; i < curr-r; i++)
556 tputs (UP,1,addbuf);
557 for (i = 0; i < curc-c; i++) {
558 if (BC)
559 tputs (BC,1,addbuf);
560 else
561 addbuf ('\010');
563 break;
565 /* safe space */
566 case 8:
567 for (i = 0; i < c-curc; i++)
568 addbuf (' ');
571 /* fix positions */
572 curr = r;
573 curc = c;
574 realr = -1;
575 realc = -1;
578 void
579 clear(void)
581 int i;
583 /* double space if can't clear */
584 if (CL == 0) {
585 writel ("\n\n");
586 return;
589 curr = curc = 0; /* fix position markers */
590 realr = realc = -1;
591 for (i = 0; i < 24; i++) /* clear line counts */
592 linect[i] = -1;
593 buffnum = -1; /* ignore leftover buffer contents */
594 tputs (CL,CO,addbuf); /* put CL in buffer */
598 /* input is character to output */
599 void
600 fancyc(char c)
602 int sp; /* counts spaces in a tab */
604 if (c == '\007') { /* bells go in blindly */
605 addbuf (c);
606 return;
609 /* process tabs, use spaces if the
610 * the tab should be erasing things,
611 * otherwise use cursor movement
612 * routines. Note this does not use
613 * hardware tabs at all. */
614 if (c == '\t') {
615 sp = (curc+8) & (~ 7); /* compute spaces */
616 /* check line length */
617 if (linect[curr] >= curc || sp < 4) {
618 for (; sp > curc; sp--)
619 addbuf (' ');
620 curc = sp; /* fix curc */
621 } else
622 curmove (curr,sp);
623 return;
626 /* do newline be calling newline */
627 if (c == '\n') {
628 newline();
629 return;
632 /* ignore any other control chars */
633 if (c < ' ')
634 return;
636 /* if an erasing space or non-space,
637 * just add it to buffer. Otherwise
638 * use cursor movement routine, so that
639 * multiple spaces will be grouped
640 * together */
641 if (c > ' ' || linect[curr] >= curc) {
642 newpos (); /* make sure position correct */
643 addbuf (c); /* add character to buffer */
644 /* fix line length */
645 if (c == ' ' && linect[curr] == curc)
646 linect[curr]--;
647 else if (linect[curr] < curc)
648 linect[curr] = curc;
649 curc++; /* fix curc */
650 } else
651 /* use cursor movement routine */
652 curmove (curr,curc+1);
655 void
656 clend(void)
658 int i;
660 if (CD) {
661 tputs (CD,CO-curr,addbuf);
662 for (i = curr; i < LI; i++)
663 linect[i] = -1;
664 return;
667 curmove (i = curr,0);
668 cline();
669 while (curr < LI-1) {
670 curmove (curr+1,0);
671 if (linect[curr] > -1)
672 cline ();
674 curmove (i,0);
677 void
678 cline(void)
680 int c;
682 if (curc > linect[curr])
683 return;
684 newpos ();
685 if (CE) {
686 tputs (CE,1,addbuf);
687 linect[curr] = curc-1;
688 } else {
689 c = curc-1;
690 while (linect[curr] > c) {
691 addbuf (' ');
692 curc++;
693 linect[curr]--;
695 curmove (curr,c+1);
699 static void
700 newline(void)
702 cline();
703 if (curr == LI-1)
704 curmove (begscr,0);
705 else
706 curmove (curr+1,0);
710 getcaps(const char *s)
712 char *code; /* two letter code */
713 char ***cap; /* pointer to cap string */
714 char *bufp; /* pointer to cap buffer */
715 char tentry[1024]; /* temporary uncoded caps buffer */
717 tgetent (tentry, s); /* get uncoded termcap entry */
719 LI = tgetnum ("li"); /* get number of lines */
720 if (LI == -1)
721 LI = 12;
722 CO = tgetnum ("co"); /* get number of columns */
723 if (CO == -1)
724 CO = 65;
726 bufp = tbuf; /* get padding character */
727 tgetstr ("pc",&bufp);
728 if (bufp != tbuf)
729 PC = *tbuf;
730 else
731 PC = 0;
733 bufp = tbuf; /* get string entries */
734 cap = tstr;
735 for (code = tcap; *code; code += 2)
736 **cap++ = (char *)tgetstr (code,&bufp);
738 /* get pertinent lengths */
739 if (HO)
740 lHO = strlen (HO);
741 if (BC)
742 lBC = strlen (BC);
743 else
744 lBC = 1;
745 if (UP)
746 lUP = strlen (UP);
747 if (ND)
748 lND = strlen (ND);
749 if (LI < 24 || CO < 72 || !(CL && UP && ND))
750 return (0);
751 linect = (int *)calloc (LI+1,sizeof(int));
752 return (1);