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