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 22 static char sccsid[] = "@(#)curses.c 5.2 (Berkeley) 02/07/89"; 23 #endif /* not lint */ 24 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 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 67 boolean 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 78 char terminal[DROWS][DCOLS]; 79 char buffer[DROWS][DCOLS]; 80 char *tc_file; 81 82 char cm_esc[16]; 83 char cm_sep[16]; 84 char cm_end[16]; 85 boolean cm_reverse = 0; 86 boolean cm_two = 0; 87 boolean cm_three = 0; 88 boolean cm_char = 0; 89 short cm_inc = 0; 90 91 boolean screen_dirty; 92 boolean lines_dirty[DROWS]; 93 boolean buf_stand_out = 0; 94 boolean term_stand_out = 0; 95 96 int LINES = DROWS; 97 int COLS = DCOLS; 98 WINDOW scr_buf; 99 WINDOW *curscr = &scr_buf; 100 101 char *CL = (char *) 0; 102 char *CM = (char *) 0; 103 char *UC = (char *) 0; /* UP */ 104 char *DO = (char *) 0; 105 char *VS = ""; 106 char *VE = ""; 107 char *TI = ""; 108 char *TE = ""; 109 char *SO = ""; 110 char *SE = ""; 111 112 short cur_row; 113 short cur_col; 114 115 initscr() 116 { 117 clear(); 118 get_term_info(); 119 printf("%s%s", TI, VS); 120 } 121 122 endwin() 123 { 124 printf("%s%s", TE, VE); 125 md_cbreak_no_echo_nonl(0); 126 } 127 128 move(row, col) 129 short row, col; 130 { 131 curscr->_cury = row; 132 curscr->_curx = col; 133 screen_dirty = 1; 134 } 135 136 mvaddstr(row, col, str) 137 short row, col; 138 char *str; 139 { 140 move(row, col); 141 addstr(str); 142 } 143 144 addstr(str) 145 char *str; 146 { 147 while (*str) { 148 addch((int) *str++); 149 } 150 } 151 152 addch(ch) 153 register 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 168 mvaddch(row, col, ch) 169 short row, col; 170 int ch; 171 { 172 move(row, col); 173 addch(ch); 174 } 175 176 refresh() 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 204 wrefresh(scr) 205 WINDOW *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 233 mvinch(row, col) 234 short row, col; 235 { 236 move(row, col); 237 return((int) buffer[row][col]); 238 } 239 240 clear() 241 { 242 printf("%s", CL); 243 fflush(stdout); 244 cur_row = cur_col = 0; 245 move(0, 0); 246 clear_buffers(); 247 } 248 249 clrtoeol() 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 261 standout() 262 { 263 buf_stand_out = 1; 264 } 265 266 standend() 267 { 268 buf_stand_out = 0; 269 } 270 271 crmode() 272 { 273 md_cbreak_no_echo_nonl(1); 274 } 275 276 noecho() 277 { 278 /* crmode() takes care of this */ 279 } 280 281 nonl() 282 { 283 /* crmode() takes care of this */ 284 } 285 286 clear_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 301 put_char_at(row, col, ch) 302 register 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 310 put_cursor(row, col) 311 register 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 364 put_st_char(ch) 365 register 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 380 get_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 414 boolean 415 tc_tname(fp, term, buf) 416 FILE *fp; 417 char *term; 418 char *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 455 tc_gtdata(fp, buf) 456 FILE *fp; 457 char *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 515 tc_gets(ibuf, tcstr) 516 char *ibuf; 517 char **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 591 tc_gnum(ibuf, n) 592 char *ibuf; 593 int *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 607 tstp() 608 { 609 endwin(); 610 md_tstp(); 611 612 start_window(); 613 printf("%s%s", TI, VS); 614 wrefresh(curscr); 615 md_slurp(); 616 } 617 618 tc_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 679