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 14 static char sccsid[] = "@(#)curses.c 5.1 (Berkeley) 11/25/87"; 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 47 boolean 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 58 char terminal[DROWS][DCOLS]; 59 char buffer[DROWS][DCOLS]; 60 char *tc_file; 61 62 char cm_esc[16]; 63 char cm_sep[16]; 64 char cm_end[16]; 65 boolean cm_reverse = 0; 66 boolean cm_two = 0; 67 boolean cm_three = 0; 68 boolean cm_char = 0; 69 short cm_inc = 0; 70 71 boolean screen_dirty; 72 boolean lines_dirty[DROWS]; 73 boolean buf_stand_out = 0; 74 boolean term_stand_out = 0; 75 76 int LINES = DROWS; 77 int COLS = DCOLS; 78 WINDOW scr_buf; 79 WINDOW *curscr = &scr_buf; 80 81 char *CL = (char *) 0; 82 char *CM = (char *) 0; 83 char *UC = (char *) 0; /* UP */ 84 char *DO = (char *) 0; 85 char *VS = ""; 86 char *VE = ""; 87 char *TI = ""; 88 char *TE = ""; 89 char *SO = ""; 90 char *SE = ""; 91 92 short cur_row; 93 short cur_col; 94 95 initscr() 96 { 97 clear(); 98 get_term_info(); 99 printf("%s%s", TI, VS); 100 } 101 102 endwin() 103 { 104 printf("%s%s", TE, VE); 105 md_cbreak_no_echo_nonl(0); 106 } 107 108 move(row, col) 109 short row, col; 110 { 111 curscr->_cury = row; 112 curscr->_curx = col; 113 screen_dirty = 1; 114 } 115 116 mvaddstr(row, col, str) 117 short row, col; 118 char *str; 119 { 120 move(row, col); 121 addstr(str); 122 } 123 124 addstr(str) 125 char *str; 126 { 127 while (*str) { 128 addch((int) *str++); 129 } 130 } 131 132 addch(ch) 133 register 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 148 mvaddch(row, col, ch) 149 short row, col; 150 int ch; 151 { 152 move(row, col); 153 addch(ch); 154 } 155 156 refresh() 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 184 wrefresh(scr) 185 WINDOW *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 213 mvinch(row, col) 214 short row, col; 215 { 216 move(row, col); 217 return((int) buffer[row][col]); 218 } 219 220 clear() 221 { 222 printf("%s", CL); 223 fflush(stdout); 224 cur_row = cur_col = 0; 225 move(0, 0); 226 clear_buffers(); 227 } 228 229 clrtoeol() 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 241 standout() 242 { 243 buf_stand_out = 1; 244 } 245 246 standend() 247 { 248 buf_stand_out = 0; 249 } 250 251 crmode() 252 { 253 md_cbreak_no_echo_nonl(1); 254 } 255 256 noecho() 257 { 258 /* crmode() takes care of this */ 259 } 260 261 nonl() 262 { 263 /* crmode() takes care of this */ 264 } 265 266 clear_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 281 put_char_at(row, col, ch) 282 register 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 290 put_cursor(row, col) 291 register 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 344 put_st_char(ch) 345 register 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 360 get_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 394 boolean 395 tc_tname(fp, term, buf) 396 FILE *fp; 397 char *term; 398 char *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 435 tc_gtdata(fp, buf) 436 FILE *fp; 437 char *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 495 tc_gets(ibuf, tcstr) 496 char *ibuf; 497 char **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 571 tc_gnum(ibuf, n) 572 char *ibuf; 573 int *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 587 tstp() 588 { 589 endwin(); 590 md_tstp(); 591 592 start_window(); 593 printf("%s%s", TI, VS); 594 wrefresh(curscr); 595 md_slurp(); 596 } 597 598 tc_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 659