]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - rogue/curses.c
Sync to 4.4BSD-Lite2
[bsdgames-darwin.git] / rogue / curses.c
1 /* $NetBSD: curses.c,v 1.3 1995/04/22 10:27:27 cgd Exp $ */
2
3 /*
4 * Copyright (c) 1988, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Timothy C. Stoehr.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #ifndef lint
40 #if 0
41 static char sccsid[] = "@(#)curses.c 8.1 (Berkeley) 5/31/93";
42 #else
43 static char rcsid[] = "$NetBSD: curses.c,v 1.3 1995/04/22 10:27:27 cgd Exp $";
44 #endif
45 #endif /* not lint */
46
47 /*
48 * curses.c
49 *
50 * This source herein may be modified and/or distributed by anybody who
51 * so desires, with the following restrictions:
52 * 1.) No portion of this notice shall be removed.
53 * 2.) Credit shall not be taken for the creation of this source.
54 * 3.) This code is not to be traded, sold, or used for personal
55 * gain or profit.
56 *
57 */
58
59 #ifdef CURSES
60
61 /* The following is a curses emulation package suitable for the rogue program
62 * in which it is included. No other suitability is claimed or suspected.
63 * Only those routines currently needed by this rogue program are included.
64 * This is being provided for those systems that don't have a suitable
65 * curses package and want to run this rogue program.
66 *
67 * Compile the entire program with -DCURSES to incorporate this package.
68 *
69 * The following is NOT supported:
70 * "%D", "%B", "%n", or "%>" inside a cursor motion (cm) termcap string.
71 * Terminals in which the cursor motion addresses the row differently from
72 * the column, as in ":cm=\E%2,%3" or ":cm=\EY%+x;%+y"
73 * Termcap database stored in the TERMCAP environ variable as returned
74 * from md_getenv(). Only the termcap file name can be stored there.
75 * See the comments for md_getenv() in machdep.c.
76 * Terminals without non-destructive backspace. Backspace (^H) is used
77 * for cursor motion regardless of any termcap entries.
78 * The ":tc=" termcap entry is ignored.
79 *
80 * Suggestions:
81 * Use line-feed as your termcap "do" entry: ":do=^J", ":do=\012" or
82 * ":do=\n" This will help cursor motion optimization. If line-feed
83 * won't work, then a short escape sequence will do.
84 */
85
86 #include <stdio.h>
87 #include "rogue.h"
88
89 boolean tc_tname();
90
91 #define BS 010
92 #define LF 012
93 #define CR 015
94 #define ESC '\033'
95 #define TAB '\011'
96
97 #define ST_MASK 0x80
98 #define BUFLEN 256
99
100 char terminal[DROWS][DCOLS];
101 char buffer[DROWS][DCOLS];
102 char *tc_file;
103
104 char cm_esc[16];
105 char cm_sep[16];
106 char cm_end[16];
107 boolean cm_reverse = 0;
108 boolean cm_two = 0;
109 boolean cm_three = 0;
110 boolean cm_char = 0;
111 short cm_inc = 0;
112
113 boolean screen_dirty;
114 boolean lines_dirty[DROWS];
115 boolean buf_stand_out = 0;
116 boolean term_stand_out = 0;
117
118 int LINES = DROWS;
119 int COLS = DCOLS;
120 WINDOW scr_buf;
121 WINDOW *curscr = &scr_buf;
122
123 char *CL = (char *) 0;
124 char *CM = (char *) 0;
125 char *UC = (char *) 0; /* UP */
126 char *DO = (char *) 0;
127 char *VS = "";
128 char *VE = "";
129 char *TI = "";
130 char *TE = "";
131 char *SO = "";
132 char *SE = "";
133
134 short cur_row;
135 short cur_col;
136
137 initscr()
138 {
139 clear();
140 get_term_info();
141 printf("%s%s", TI, VS);
142 }
143
144 endwin()
145 {
146 printf("%s%s", TE, VE);
147 md_cbreak_no_echo_nonl(0);
148 }
149
150 move(row, col)
151 short row, col;
152 {
153 curscr->_cury = row;
154 curscr->_curx = col;
155 screen_dirty = 1;
156 }
157
158 mvaddstr(row, col, str)
159 short row, col;
160 char *str;
161 {
162 move(row, col);
163 addstr(str);
164 }
165
166 addstr(str)
167 char *str;
168 {
169 while (*str) {
170 addch((int) *str++);
171 }
172 }
173
174 addch(ch)
175 register int ch;
176 {
177 short row, col;
178
179 row = curscr->_cury;
180 col = curscr->_curx++;
181
182 if (buf_stand_out) {
183 ch |= ST_MASK;
184 }
185 buffer[row][col] = (char) ch;
186 lines_dirty[row] = 1;
187 screen_dirty = 1;
188 }
189
190 mvaddch(row, col, ch)
191 short row, col;
192 int ch;
193 {
194 move(row, col);
195 addch(ch);
196 }
197
198 refresh()
199 {
200 register i, j, line;
201 short old_row, old_col, first_row;
202
203 if (screen_dirty) {
204
205 old_row = curscr->_cury;
206 old_col = curscr->_curx;
207 first_row = cur_row;
208
209 for (i = 0; i < DROWS; i++) {
210 line = (first_row + i) % DROWS;
211 if (lines_dirty[line]) {
212 for (j = 0; j < DCOLS; j++) {
213 if (buffer[line][j] != terminal[line][j]) {
214 put_char_at(line, j, buffer[line][j]);
215 }
216 }
217 lines_dirty[line] = 0;
218 }
219 }
220 put_cursor(old_row, old_col);
221 screen_dirty = 0;
222 fflush(stdout);
223 }
224 }
225
226 wrefresh(scr)
227 WINDOW *scr;
228 {
229 short i, col;
230
231 printf("%s", CL);
232 cur_row = cur_col = 0;
233
234 for (i = 0; i < DROWS; i++) {
235 col = 0;
236 while (col < DCOLS) {
237 while ((col < DCOLS) && (buffer[i][col] == ' ')) {
238 col++;
239 }
240 if (col < DCOLS) {
241 put_cursor(i, col);
242 }
243 while ((col < DCOLS) && (buffer[i][col] != ' ')) {
244 put_st_char((int) buffer[i][col]);
245 cur_col++;
246 col++;
247 }
248 }
249 }
250 put_cursor(curscr->_cury, curscr->_curx);
251 fflush(stdout);
252 scr = scr; /* make lint happy */
253 }
254
255 mvinch(row, col)
256 short row, col;
257 {
258 move(row, col);
259 return((int) buffer[row][col]);
260 }
261
262 clear()
263 {
264 printf("%s", CL);
265 fflush(stdout);
266 cur_row = cur_col = 0;
267 move(0, 0);
268 clear_buffers();
269 }
270
271 clrtoeol()
272 {
273 short row, col;
274
275 row = curscr->_cury;
276
277 for (col = curscr->_curx; col < DCOLS; col++) {
278 buffer[row][col] = ' ';
279 }
280 lines_dirty[row] = 1;
281 }
282
283 standout()
284 {
285 buf_stand_out = 1;
286 }
287
288 standend()
289 {
290 buf_stand_out = 0;
291 }
292
293 crmode()
294 {
295 md_cbreak_no_echo_nonl(1);
296 }
297
298 noecho()
299 {
300 /* crmode() takes care of this */
301 }
302
303 nonl()
304 {
305 /* crmode() takes care of this */
306 }
307
308 clear_buffers()
309 {
310 register i, j;
311
312 screen_dirty = 0;
313
314 for (i = 0; i < DROWS; i++) {
315 lines_dirty[i] = 0;
316 for (j = 0; j < DCOLS; j++) {
317 terminal[i][j] = ' ';
318 buffer[i][j] = ' ';
319 }
320 }
321 }
322
323 put_char_at(row, col, ch)
324 register row, col, ch;
325 {
326 put_cursor(row, col);
327 put_st_char(ch);
328 terminal[row][col] = (char) ch;
329 cur_col++;
330 }
331
332 put_cursor(row, col)
333 register row, col;
334 {
335 register i, rdif, cdif;
336 short ch, t;
337
338 rdif = (row > cur_row) ? row - cur_row : cur_row - row;
339 cdif = (col > cur_col) ? col - cur_col : cur_col - col;
340
341 if (((row > cur_row) && DO) || ((cur_row > row) && UC)) {
342 if ((rdif < 4) && (cdif < 4)) {
343 for (i = 0; i < rdif; i++) {
344 printf("%s", ((row < cur_row) ? UC : DO));
345 }
346 cur_row = row;
347 if (col == cur_col) {
348 return;
349 }
350 }
351 }
352 if (row == cur_row) {
353 if (cdif <= 6) {
354 for (i = 0; i < cdif; i++) {
355 ch = (col < cur_col) ? BS :
356 terminal[row][cur_col + i];
357 put_st_char((int) ch);
358 }
359 cur_row = row;
360 cur_col = col;
361 return;
362 }
363 }
364 cur_row = row;
365 cur_col = col;
366
367 row += cm_inc;
368 col += cm_inc;
369
370 if (cm_reverse) {
371 t = row;
372 row = col;
373 col = t;
374 }
375 if (cm_two) {
376 printf("%s%02d%s%02d%s", cm_esc, row, cm_sep, col, cm_end);
377 } else if (cm_three) {
378 printf("%s%03d%s%03d%s", cm_esc, row, cm_sep, col, cm_end);
379 } else if (cm_char) {
380 printf("%s%c%s%c%s", cm_esc, row, cm_sep, col, cm_end);
381 } else {
382 printf("%s%d%s%d%s", cm_esc, row, cm_sep, col, cm_end);
383 }
384 }
385
386 put_st_char(ch)
387 register ch;
388 {
389 if ((ch & ST_MASK) && (!term_stand_out)) {
390 ch &= ~ST_MASK;
391 printf("%s%c", SO, ch);
392 term_stand_out = 1;
393 } else if ((!(ch & ST_MASK)) && term_stand_out) {
394 printf("%s%c", SE, ch);
395 term_stand_out = 0;
396 } else {
397 ch &= ~ST_MASK;
398 putchar(ch);
399 }
400 }
401
402 get_term_info()
403 {
404 FILE *fp;
405 char *term, *tcf;
406 char buf[BUFLEN];
407
408 if (tcf = md_getenv("TERMCAP")) {
409 if (strlen(tcf) > 40) {
410 clean_up("TERMCAP file name too long");
411 }
412 tc_file = tcf;
413 } else {
414 if (!(tc_file = md_gdtcf())) {
415 clean_up("I need a termcap file");
416 }
417 }
418
419 if (!(term = md_getenv("TERM"))) {
420 clean_up("Cannot find TERM variable in environ");
421 }
422 if ((fp = fopen(tc_file, "r")) == NULL) {
423 sprintf(buf, "Cannot open TERMCAP file: %s", tc_file);
424 clean_up(buf);
425 }
426
427 if (!tc_tname(fp, term, buf)) {
428 sprintf(buf, "Cannot find TERM type: %s in TERMCAP file: %s", term,
429 tc_file);
430 clean_up(buf);
431 }
432 tc_gtdata(fp, buf);
433 fclose(fp);
434 }
435
436 boolean
437 tc_tname(fp, term, buf)
438 FILE *fp;
439 char *term;
440 char *buf;
441 {
442 short i, j;
443 boolean found = 0;
444 char *fg;
445
446 while (!found) {
447 i = 0;
448 fg = fgets(buf, BUFLEN, fp);
449 if (fg != NULL) {
450 if ( (buf[0] != '#') && (buf[0] != ' ') && (buf[0] != TAB) &&
451 (buf[0] != CR) && (buf[0] != LF)) {
452 while (buf[i] && (!found)) {
453 j = 0;
454 while (buf[i] == term[j]) {
455 i++;
456 j++;
457 }
458 if ((!term[j]) && ((buf[i] == '|') || (buf[i] == ':'))) {
459 found = 1;
460 } else {
461 while (buf[i] && (buf[i] != '|') && (buf[i] != ':')) {
462 i++;
463 }
464 if (buf[i]) {
465 i++;
466 }
467 }
468 }
469 }
470 } else {
471 break;
472 }
473 }
474 return(found);
475 }
476
477 tc_gtdata(fp, buf)
478 FILE *fp;
479 char *buf;
480 {
481 short i;
482 boolean first = 1;
483
484 do {
485 if (!first) {
486 if ((buf[0] != TAB) && (buf[0] != ' ')) {
487 break;
488 }
489 }
490 first = 0;
491 i = 0;
492 while (buf[i]) {
493 while (buf[i] && (buf[i] != ':')) {
494 i++;
495 }
496 if (buf[i] == ':') {
497 if (!strncmp(buf + i, ":cl=", 4)) {
498 tc_gets(buf + i, &CL);
499 } else if (!strncmp(buf + i, ":cm=", 4)) {
500 tc_gets(buf + i, &CM);
501 } else if (!strncmp(buf + i, ":up=", 4)) {
502 tc_gets(buf + i, &UC);
503 } else if (!strncmp(buf + i, ":do=", 4)) {
504 tc_gets(buf + i, &DO);
505 } else if (!strncmp(buf + i, ":vs=", 4)) {
506 tc_gets(buf + i, &VS);
507 } else if (!strncmp(buf + i, ":ve=", 4)) {
508 tc_gets(buf + i, &VE);
509 } else if (!strncmp(buf + i, ":ti=", 4)) {
510 tc_gets(buf + i, &TI);
511 } else if (!strncmp(buf + i, ":te=", 4)) {
512 tc_gets(buf + i, &TE);
513 } else if (!strncmp(buf + i, ":vs=", 4)) {
514 tc_gets(buf + i, &VS);
515 } else if (!strncmp(buf + i, ":ve=", 4)) {
516 tc_gets(buf + i, &VE);
517 } else if (!strncmp(buf + i, ":so=", 4)) {
518 tc_gets(buf + i, &SO);
519 } else if (!strncmp(buf + i, ":se=", 4)) {
520 tc_gets(buf + i, &SE);
521 } else if (!strncmp(buf + i, ":li#", 4)) {
522 tc_gnum(buf + i, &LINES);
523 } else if (!strncmp(buf + i, ":co#", 4)) {
524 tc_gnum(buf + i, &COLS);
525 }
526 i++;
527 }
528 }
529 } while (fgets(buf, BUFLEN, fp) != NULL);
530
531 if ((!CM) || (!CL)) {
532 clean_up("Terminal and termcap must have cm and cl");
533 }
534 tc_cmget();
535 }
536
537 tc_gets(ibuf, tcstr)
538 char *ibuf;
539 char **tcstr;
540 {
541 short i, j, k, n;
542 char obuf[BUFLEN];
543
544 i = 4;
545 j = 0;
546
547 while (ibuf[i] && is_digit(ibuf[i])) {
548 i++;
549 }
550
551 while (ibuf[i] && (ibuf[i] != ':')) {
552 if (ibuf[i] == '\\') {
553 i++;
554 switch(ibuf[i]) {
555 case 'E':
556 obuf[j] = ESC;
557 i++;
558 break;
559 case 'n':
560 obuf[j] = LF;
561 i++;
562 break;
563 case 'r':
564 obuf[j] = CR;
565 i++;
566 break;
567 case 'b':
568 obuf[j] = BS;
569 i++;
570 break;
571 case 't':
572 obuf[j] = TAB;
573 i++;
574 break;
575 case '0':
576 case '1':
577 case '2':
578 case '3':
579 case '4':
580 case '5':
581 case '6':
582 case '7':
583 case '8':
584 case '9':
585 n = 0;
586 k = 0;
587 while (k < 3 && ibuf[i] && is_digit(ibuf[i])) {
588 n = (8 * n) + (ibuf[i] - '0');
589 i++;
590 k++;
591 }
592 obuf[j] = (char) n;
593 break;
594 default:
595 obuf[j] = ibuf[i];
596 i++;
597 }
598 } else if (ibuf[i] == '^') {
599 obuf[j] = ibuf[i+1] - 64;
600 i += 2;
601 } else {
602 obuf[j] = ibuf[i++];
603 }
604 j++;
605 }
606 obuf[j] = 0;
607 if (!(*tcstr = md_malloc(j + 1))) {
608 clean_up("cannot alloc() memory");
609 }
610 (void) strcpy(*tcstr, obuf);
611 }
612
613 tc_gnum(ibuf, n)
614 char *ibuf;
615 int *n;
616 {
617 short i;
618 int r = 0;
619
620 i = 4;
621
622 while (is_digit(ibuf[i])) {
623 r = (r * 10) + (ibuf[i] - '0');
624 i++;
625 }
626 *n = r;
627 }
628
629 tstp()
630 {
631 endwin();
632 md_tstp();
633
634 start_window();
635 printf("%s%s", TI, VS);
636 wrefresh(curscr);
637 md_slurp();
638 }
639
640 tc_cmget()
641 {
642 short i = 0, j = 0, rc_spec = 0;
643
644 while (CM[i] && (CM[i] != '%') && (j < 15)) {
645 cm_esc[j++] = CM[i++];
646 }
647 cm_esc[j] = 0;
648
649 while (CM[i] && (rc_spec < 2)) {
650 if (CM[i] == '%') {
651 i++;
652 switch(CM[i]) {
653 case 'd':
654 rc_spec++;
655 break;
656 case 'i':
657 cm_inc = 1;
658 break;
659 case '2':
660 cm_two = 1;
661 rc_spec++;
662 break;
663 case '3':
664 cm_three = 1;
665 rc_spec++;
666 break;
667 case '.':
668 cm_char = 1;
669 rc_spec++;
670 break;
671 case 'r':
672 cm_reverse = 1;
673 break;
674 case '+':
675 i++;
676 cm_inc = CM[i];
677 cm_char = 1;
678 rc_spec++;
679 break;
680 }
681 i++;
682 } else {
683 j = 0;
684 while (CM[i] && (CM[i] != '%')) {
685 cm_sep[j++] = CM[i++];
686 }
687 cm_sep[j] = 0;
688 }
689 }
690
691 j = 0;
692 if (rc_spec == 2) {
693 while (CM[i] && (j < 15)) {
694 cm_end[j++] = CM[i++];
695 }
696 }
697 cm_end[j] = 0;
698 }
699
700 #endif