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