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 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 static char sccsid[] = "@(#)curses.c 5.3 (Berkeley) 06/01/90"; 13 #endif /* not lint */ 14 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 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 57 boolean 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 68 char terminal[DROWS][DCOLS]; 69 char buffer[DROWS][DCOLS]; 70 char *tc_file; 71 72 char cm_esc[16]; 73 char cm_sep[16]; 74 char cm_end[16]; 75 boolean cm_reverse = 0; 76 boolean cm_two = 0; 77 boolean cm_three = 0; 78 boolean cm_char = 0; 79 short cm_inc = 0; 80 81 boolean screen_dirty; 82 boolean lines_dirty[DROWS]; 83 boolean buf_stand_out = 0; 84 boolean term_stand_out = 0; 85 86 int LINES = DROWS; 87 int COLS = DCOLS; 88 WINDOW scr_buf; 89 WINDOW *curscr = &scr_buf; 90 91 char *CL = (char *) 0; 92 char *CM = (char *) 0; 93 char *UC = (char *) 0; /* UP */ 94 char *DO = (char *) 0; 95 char *VS = ""; 96 char *VE = ""; 97 char *TI = ""; 98 char *TE = ""; 99 char *SO = ""; 100 char *SE = ""; 101 102 short cur_row; 103 short cur_col; 104 105 initscr() 106 { 107 clear(); 108 get_term_info(); 109 printf("%s%s", TI, VS); 110 } 111 112 endwin() 113 { 114 printf("%s%s", TE, VE); 115 md_cbreak_no_echo_nonl(0); 116 } 117 118 move(row, col) 119 short row, col; 120 { 121 curscr->_cury = row; 122 curscr->_curx = col; 123 screen_dirty = 1; 124 } 125 126 mvaddstr(row, col, str) 127 short row, col; 128 char *str; 129 { 130 move(row, col); 131 addstr(str); 132 } 133 134 addstr(str) 135 char *str; 136 { 137 while (*str) { 138 addch((int) *str++); 139 } 140 } 141 142 addch(ch) 143 register 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 158 mvaddch(row, col, ch) 159 short row, col; 160 int ch; 161 { 162 move(row, col); 163 addch(ch); 164 } 165 166 refresh() 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 194 wrefresh(scr) 195 WINDOW *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 223 mvinch(row, col) 224 short row, col; 225 { 226 move(row, col); 227 return((int) buffer[row][col]); 228 } 229 230 clear() 231 { 232 printf("%s", CL); 233 fflush(stdout); 234 cur_row = cur_col = 0; 235 move(0, 0); 236 clear_buffers(); 237 } 238 239 clrtoeol() 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 251 standout() 252 { 253 buf_stand_out = 1; 254 } 255 256 standend() 257 { 258 buf_stand_out = 0; 259 } 260 261 crmode() 262 { 263 md_cbreak_no_echo_nonl(1); 264 } 265 266 noecho() 267 { 268 /* crmode() takes care of this */ 269 } 270 271 nonl() 272 { 273 /* crmode() takes care of this */ 274 } 275 276 clear_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 291 put_char_at(row, col, ch) 292 register 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 300 put_cursor(row, col) 301 register 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 354 put_st_char(ch) 355 register 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 370 get_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 404 boolean 405 tc_tname(fp, term, buf) 406 FILE *fp; 407 char *term; 408 char *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 445 tc_gtdata(fp, buf) 446 FILE *fp; 447 char *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 505 tc_gets(ibuf, tcstr) 506 char *ibuf; 507 char **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 581 tc_gnum(ibuf, n) 582 char *ibuf; 583 int *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 597 tstp() 598 { 599 endwin(); 600 md_tstp(); 601 602 start_window(); 603 printf("%s%s", TI, VS); 604 wrefresh(curscr); 605 md_slurp(); 606 } 607 608 tc_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 669