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