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