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