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