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