Annotation of src/usr.bin/tic/reset_cmd.c, Revision 1.1
1.1 ! nicm 1: /****************************************************************************
! 2: * Copyright 2019-2021,2023 Thomas E. Dickey *
! 3: * Copyright 2016,2017 Free Software Foundation, Inc. *
! 4: * *
! 5: * Permission is hereby granted, free of charge, to any person obtaining a *
! 6: * copy of this software and associated documentation files (the *
! 7: * "Software"), to deal in the Software without restriction, including *
! 8: * without limitation the rights to use, copy, modify, merge, publish, *
! 9: * distribute, distribute with modifications, sublicense, and/or sell *
! 10: * copies of the Software, and to permit persons to whom the Software is *
! 11: * furnished to do so, subject to the following conditions: *
! 12: * *
! 13: * The above copyright notice and this permission notice shall be included *
! 14: * in all copies or substantial portions of the Software. *
! 15: * *
! 16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
! 17: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
! 18: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
! 19: * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
! 20: * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
! 21: * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
! 22: * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
! 23: * *
! 24: * Except as contained in this notice, the name(s) of the above copyright *
! 25: * holders shall not be used in advertising or otherwise to promote the *
! 26: * sale, use or other dealings in this Software without prior written *
! 27: * authorization. *
! 28: ****************************************************************************/
! 29:
! 30: /****************************************************************************
! 31: * Author: Thomas E. Dickey *
! 32: ****************************************************************************/
! 33:
! 34: #include <reset_cmd.h>
! 35: #include <tty_settings.h>
! 36:
! 37: #include <errno.h>
! 38: #include <stdio.h>
! 39: #include <fcntl.h>
! 40:
! 41: #if HAVE_SIZECHANGE
! 42: # if !defined(sun) || !TERMIOS
! 43: # if HAVE_SYS_IOCTL_H
! 44: # include <sys/ioctl.h>
! 45: # endif
! 46: # endif
! 47: #endif
! 48:
! 49: #if NEED_PTEM_H
! 50: /* they neglected to define struct winsize in termios.h -- it is only
! 51: in termio.h */
! 52: #include <sys/stream.h>
! 53: #include <sys/ptem.h>
! 54: #endif
! 55:
! 56: MODULE_ID("$Id: reset_cmd.c,v 1.29 2023/01/07 21:50:34 tom Exp $")
! 57:
! 58: /*
! 59: * SCO defines TIOCGSIZE and the corresponding struct. Other systems (SunOS,
! 60: * Solaris, IRIX) define TIOCGWINSZ and struct winsize.
! 61: */
! 62: #ifdef TIOCGSIZE
! 63: # define IOCTL_GET_WINSIZE TIOCGSIZE
! 64: # define IOCTL_SET_WINSIZE TIOCSSIZE
! 65: # define STRUCT_WINSIZE struct ttysize
! 66: # define WINSIZE_ROWS(n) n.ts_lines
! 67: # define WINSIZE_COLS(n) n.ts_cols
! 68: #else
! 69: # ifdef TIOCGWINSZ
! 70: # define IOCTL_GET_WINSIZE TIOCGWINSZ
! 71: # define IOCTL_SET_WINSIZE TIOCSWINSZ
! 72: # define STRUCT_WINSIZE struct winsize
! 73: # define WINSIZE_ROWS(n) n.ws_row
! 74: # define WINSIZE_COLS(n) n.ws_col
! 75: # endif
! 76: #endif
! 77:
! 78: static FILE *my_file;
! 79:
! 80: static bool use_reset = FALSE; /* invoked as reset */
! 81: static bool use_init = FALSE; /* invoked as init */
! 82:
! 83: static GCC_NORETURN void
! 84: failed(const char *msg)
! 85: {
! 86: int code = errno;
! 87:
! 88: (void) fprintf(stderr, "%s: %s: %s\n", _nc_progname, msg, strerror(code));
! 89: restore_tty_settings();
! 90: (void) fprintf(my_file, "\n");
! 91: fflush(my_file);
! 92: ExitProgram(ErrSystem(code));
! 93: /* NOTREACHED */
! 94: }
! 95:
! 96: static bool
! 97: cat_file(char *file)
! 98: {
! 99: FILE *fp;
! 100: size_t nr;
! 101: char buf[BUFSIZ];
! 102: bool sent = FALSE;
! 103:
! 104: if (file != 0) {
! 105: if ((fp = safe_fopen(file, "r")) == 0)
! 106: failed(file);
! 107:
! 108: while ((nr = fread(buf, sizeof(char), sizeof(buf), fp)) != 0) {
! 109: if (fwrite(buf, sizeof(char), nr, my_file) != nr) {
! 110: failed(file);
! 111: }
! 112: sent = TRUE;
! 113: }
! 114: fclose(fp);
! 115: }
! 116: return sent;
! 117: }
! 118:
! 119: static int
! 120: out_char(int c)
! 121: {
! 122: return putc(c, my_file);
! 123: }
! 124:
! 125: /**************************************************************************
! 126: * Mode-setting logic
! 127: **************************************************************************/
! 128:
! 129: /* some BSD systems have these built in, some systems are missing
! 130: * one or more definitions. The safest solution is to override unless the
! 131: * commonly-altered ones are defined.
! 132: */
! 133: #if !(defined(CERASE) && defined(CINTR) && defined(CKILL) && defined(CQUIT))
! 134: #undef CEOF
! 135: #undef CERASE
! 136: #undef CINTR
! 137: #undef CKILL
! 138: #undef CLNEXT
! 139: #undef CRPRNT
! 140: #undef CQUIT
! 141: #undef CSTART
! 142: #undef CSTOP
! 143: #undef CSUSP
! 144: #endif
! 145:
! 146: /* control-character defaults */
! 147: #ifndef CEOF
! 148: #define CEOF CTRL('D')
! 149: #endif
! 150: #ifndef CERASE
! 151: #define CERASE CTRL('H')
! 152: #endif
! 153: #ifndef CINTR
! 154: #define CINTR 127 /* ^? */
! 155: #endif
! 156: #ifndef CKILL
! 157: #define CKILL CTRL('U')
! 158: #endif
! 159: #ifndef CLNEXT
! 160: #define CLNEXT CTRL('v')
! 161: #endif
! 162: #ifndef CRPRNT
! 163: #define CRPRNT CTRL('r')
! 164: #endif
! 165: #ifndef CQUIT
! 166: #define CQUIT CTRL('\\')
! 167: #endif
! 168: #ifndef CSTART
! 169: #define CSTART CTRL('Q')
! 170: #endif
! 171: #ifndef CSTOP
! 172: #define CSTOP CTRL('S')
! 173: #endif
! 174: #ifndef CSUSP
! 175: #define CSUSP CTRL('Z')
! 176: #endif
! 177:
! 178: #if defined(_POSIX_VDISABLE)
! 179: #define DISABLED(val) (((_POSIX_VDISABLE != -1) \
! 180: && ((val) == _POSIX_VDISABLE)) \
! 181: || ((val) <= 0))
! 182: #else
! 183: #define DISABLED(val) ((int)(val) <= 0)
! 184: #endif
! 185:
! 186: #define CHK(val, dft) (unsigned char) (DISABLED(val) ? dft : val)
! 187:
! 188: #define reset_char(item, value) \
! 189: tty_settings->c_cc[item] = CHK(tty_settings->c_cc[item], value)
! 190:
! 191: /*
! 192: * Reset the terminal mode bits to a sensible state. Very useful after
! 193: * a child program dies in raw mode.
! 194: */
! 195: void
! 196: reset_tty_settings(int fd, TTY * tty_settings, int noset)
! 197: {
! 198: GET_TTY(fd, tty_settings);
! 199:
! 200: #ifdef TERMIOS
! 201: #if defined(VDISCARD) && defined(CDISCARD)
! 202: reset_char(VDISCARD, CDISCARD);
! 203: #endif
! 204: reset_char(VEOF, CEOF);
! 205: reset_char(VERASE, CERASE);
! 206: #if defined(VERASE2) && defined(CERASE2)
! 207: reset_char(VERASE2, CERASE2);
! 208: #endif
! 209: #if defined(VFLUSH) && defined(CFLUSH)
! 210: reset_char(VFLUSH, CFLUSH);
! 211: #endif
! 212: reset_char(VINTR, CINTR);
! 213: reset_char(VKILL, CKILL);
! 214: #if defined(VLNEXT) && defined(CLNEXT)
! 215: reset_char(VLNEXT, CLNEXT);
! 216: #endif
! 217: reset_char(VQUIT, CQUIT);
! 218: #if defined(VREPRINT) && defined(CRPRNT)
! 219: reset_char(VREPRINT, CRPRNT);
! 220: #endif
! 221: #if defined(VSTART) && defined(CSTART)
! 222: reset_char(VSTART, CSTART);
! 223: #endif
! 224: #if defined(VSTOP) && defined(CSTOP)
! 225: reset_char(VSTOP, CSTOP);
! 226: #endif
! 227: #if defined(VSUSP) && defined(CSUSP)
! 228: reset_char(VSUSP, CSUSP);
! 229: #endif
! 230: #if defined(VWERASE) && defined(CWERASE)
! 231: reset_char(VWERASE, CWERASE);
! 232: #endif
! 233:
! 234: tty_settings->c_iflag &= ~((unsigned) (IGNBRK
! 235: | PARMRK
! 236: | INPCK
! 237: | ISTRIP
! 238: | INLCR
! 239: | IGNCR
! 240: #ifdef IUCLC
! 241: | IUCLC
! 242: #endif
! 243: #ifdef IXANY
! 244: | IXANY
! 245: #endif
! 246: | IXOFF));
! 247:
! 248: tty_settings->c_iflag |= (BRKINT
! 249: | IGNPAR
! 250: | ICRNL
! 251: | IXON
! 252: #ifdef IMAXBEL
! 253: | IMAXBEL
! 254: #endif
! 255: );
! 256:
! 257: tty_settings->c_oflag &= ~((unsigned) (0
! 258: #ifdef OLCUC
! 259: | OLCUC
! 260: #endif
! 261: #ifdef OCRNL
! 262: | OCRNL
! 263: #endif
! 264: #ifdef ONOCR
! 265: | ONOCR
! 266: #endif
! 267: #ifdef ONLRET
! 268: | ONLRET
! 269: #endif
! 270: #ifdef OFILL
! 271: | OFILL
! 272: #endif
! 273: #ifdef OFDEL
! 274: | OFDEL
! 275: #endif
! 276: #ifdef NLDLY
! 277: | NLDLY
! 278: #endif
! 279: #ifdef CRDLY
! 280: | CRDLY
! 281: #endif
! 282: #ifdef TABDLY
! 283: | TABDLY
! 284: #endif
! 285: #ifdef BSDLY
! 286: | BSDLY
! 287: #endif
! 288: #ifdef VTDLY
! 289: | VTDLY
! 290: #endif
! 291: #ifdef FFDLY
! 292: | FFDLY
! 293: #endif
! 294: ));
! 295:
! 296: tty_settings->c_oflag |= (OPOST
! 297: #ifdef ONLCR
! 298: | ONLCR
! 299: #endif
! 300: );
! 301:
! 302: tty_settings->c_cflag &= ~((unsigned) (CSIZE
! 303: | CSTOPB
! 304: | PARENB
! 305: | PARODD
! 306: | CLOCAL));
! 307: tty_settings->c_cflag |= (CS8 | CREAD);
! 308: tty_settings->c_lflag &= ~((unsigned) (ECHONL
! 309: | NOFLSH
! 310: #ifdef TOSTOP
! 311: | TOSTOP
! 312: #endif
! 313: #ifdef ECHOPTR
! 314: | ECHOPRT
! 315: #endif
! 316: #ifdef XCASE
! 317: | XCASE
! 318: #endif
! 319: ));
! 320:
! 321: tty_settings->c_lflag |= (ISIG
! 322: | ICANON
! 323: | ECHO
! 324: | ECHOE
! 325: | ECHOK
! 326: #ifdef ECHOCTL
! 327: | ECHOCTL
! 328: #endif
! 329: #ifdef ECHOKE
! 330: | ECHOKE
! 331: #endif
! 332: );
! 333: #endif
! 334:
! 335: if (!noset) {
! 336: SET_TTY(fd, tty_settings);
! 337: }
! 338: }
! 339:
! 340: /*
! 341: * Returns a "good" value for the erase character. This is loosely based on
! 342: * the BSD4.4 logic.
! 343: */
! 344: static int
! 345: default_erase(void)
! 346: {
! 347: int result;
! 348:
! 349: if (over_strike
! 350: && VALID_STRING(key_backspace)
! 351: && strlen(key_backspace) == 1) {
! 352: result = key_backspace[0];
! 353: } else {
! 354: result = CERASE;
! 355: }
! 356:
! 357: return result;
! 358: }
! 359:
! 360: /*
! 361: * Update the values of the erase, interrupt, and kill characters in the TTY
! 362: * parameter.
! 363: *
! 364: * SVr4 tset (e.g., Solaris 2.5) only modifies the intr, quit or erase
! 365: * characters if they're unset, or if we specify them as options. This differs
! 366: * from BSD 4.4 tset, which always sets erase.
! 367: */
! 368: void
! 369: set_control_chars(TTY * tty_settings, int my_erase, int my_intr, int my_kill)
! 370: {
! 371: #if defined(EXP_WIN32_DRIVER)
! 372: /* noop */
! 373: (void) tty_settings;
! 374: (void) my_erase;
! 375: (void) my_intr;
! 376: (void) my_kill;
! 377: #else
! 378: if (DISABLED(tty_settings->c_cc[VERASE]) || my_erase >= 0) {
! 379: tty_settings->c_cc[VERASE] = UChar((my_erase >= 0)
! 380: ? my_erase
! 381: : default_erase());
! 382: }
! 383:
! 384: if (DISABLED(tty_settings->c_cc[VINTR]) || my_intr >= 0) {
! 385: tty_settings->c_cc[VINTR] = UChar((my_intr >= 0)
! 386: ? my_intr
! 387: : CINTR);
! 388: }
! 389:
! 390: if (DISABLED(tty_settings->c_cc[VKILL]) || my_kill >= 0) {
! 391: tty_settings->c_cc[VKILL] = UChar((my_kill >= 0)
! 392: ? my_kill
! 393: : CKILL);
! 394: }
! 395: #endif
! 396: }
! 397:
! 398: /*
! 399: * Set up various conversions in the TTY parameter, including parity, tabs,
! 400: * returns, echo, and case, according to the termcap entry.
! 401: */
! 402: void
! 403: set_conversions(TTY * tty_settings)
! 404: {
! 405: #if defined(EXP_WIN32_DRIVER)
! 406: /* FIXME */
! 407: #else
! 408: #ifdef ONLCR
! 409: tty_settings->c_oflag |= ONLCR;
! 410: #endif
! 411: tty_settings->c_iflag |= ICRNL;
! 412: tty_settings->c_lflag |= ECHO;
! 413: #ifdef OXTABS
! 414: tty_settings->c_oflag |= OXTABS;
! 415: #endif /* OXTABS */
! 416:
! 417: /* test used to be tgetflag("NL") */
! 418: if (VALID_STRING(newline) && newline[0] == '\n' && !newline[1]) {
! 419: /* Newline, not linefeed. */
! 420: #ifdef ONLCR
! 421: tty_settings->c_oflag &= ~((unsigned) ONLCR);
! 422: #endif
! 423: tty_settings->c_iflag &= ~((unsigned) ICRNL);
! 424: }
! 425: #ifdef OXTABS
! 426: /* test used to be tgetflag("pt") */
! 427: if (VALID_STRING(set_tab) && VALID_STRING(clear_all_tabs))
! 428: tty_settings->c_oflag &= ~OXTABS;
! 429: #endif /* OXTABS */
! 430: tty_settings->c_lflag |= (ECHOE | ECHOK);
! 431: #endif
! 432: }
! 433:
! 434: static bool
! 435: sent_string(const char *s)
! 436: {
! 437: bool sent = FALSE;
! 438: if (VALID_STRING(s)) {
! 439: tputs(s, 0, out_char);
! 440: sent = TRUE;
! 441: }
! 442: return sent;
! 443: }
! 444:
! 445: static bool
! 446: to_left_margin(void)
! 447: {
! 448: if (VALID_STRING(carriage_return)) {
! 449: sent_string(carriage_return);
! 450: } else {
! 451: out_char('\r');
! 452: }
! 453: return TRUE;
! 454: }
! 455:
! 456: /*
! 457: * Set the hardware tabs on the terminal, using the 'ct' (clear all tabs),
! 458: * 'st' (set one tab) and 'ch' (horizontal cursor addressing) capabilities.
! 459: * This is done before 'if' and 'is', so they can recover in case of error.
! 460: *
! 461: * Return TRUE if we set any tab stops, FALSE if not.
! 462: */
! 463: static bool
! 464: reset_tabstops(int wide)
! 465: {
! 466: if ((init_tabs != 8)
! 467: && VALID_NUMERIC(init_tabs)
! 468: && VALID_STRING(set_tab)
! 469: && VALID_STRING(clear_all_tabs)) {
! 470: int c;
! 471:
! 472: to_left_margin();
! 473: tputs(clear_all_tabs, 0, out_char);
! 474: if (init_tabs > 1) {
! 475: if (init_tabs > wide)
! 476: init_tabs = (short) wide;
! 477: for (c = init_tabs; c < wide; c += init_tabs) {
! 478: fprintf(my_file, "%*s", init_tabs, " ");
! 479: tputs(set_tab, 0, out_char);
! 480: }
! 481: to_left_margin();
! 482: }
! 483: return (TRUE);
! 484: }
! 485: return (FALSE);
! 486: }
! 487:
! 488: /* Output startup string. */
! 489: bool
! 490: send_init_strings(int fd GCC_UNUSED, TTY * old_settings)
! 491: {
! 492: int i;
! 493: bool need_flush = FALSE;
! 494:
! 495: (void) old_settings;
! 496: #ifdef TAB3
! 497: if (old_settings != 0 &&
! 498: old_settings->c_oflag & (TAB3 | ONLCR | OCRNL | ONLRET)) {
! 499: old_settings->c_oflag &= (TAB3 | ONLCR | OCRNL | ONLRET);
! 500: SET_TTY(fd, old_settings);
! 501: }
! 502: #endif
! 503: if (use_reset || use_init) {
! 504: if (VALID_STRING(init_prog)) {
! 505: IGNORE_RC(system(init_prog));
! 506: }
! 507:
! 508: need_flush |= sent_string((use_reset && (reset_1string != 0))
! 509: ? reset_1string
! 510: : init_1string);
! 511:
! 512: need_flush |= sent_string((use_reset && (reset_2string != 0))
! 513: ? reset_2string
! 514: : init_2string);
! 515:
! 516: if (VALID_STRING(clear_margins)) {
! 517: need_flush |= sent_string(clear_margins);
! 518: } else
! 519: #if defined(set_lr_margin)
! 520: if (VALID_STRING(set_lr_margin)) {
! 521: need_flush |= sent_string(TIPARM_2(set_lr_margin, 0, columns - 1));
! 522: } else
! 523: #endif
! 524: #if defined(set_left_margin_parm) && defined(set_right_margin_parm)
! 525: if (VALID_STRING(set_left_margin_parm)
! 526: && VALID_STRING(set_right_margin_parm)) {
! 527: need_flush |= sent_string(TIPARM_1(set_left_margin_parm, 0));
! 528: need_flush |= sent_string(TIPARM_1(set_right_margin_parm,
! 529: columns - 1));
! 530: } else
! 531: #endif
! 532: if (VALID_STRING(set_left_margin)
! 533: && VALID_STRING(set_right_margin)) {
! 534: need_flush |= to_left_margin();
! 535: need_flush |= sent_string(set_left_margin);
! 536: if (VALID_STRING(parm_right_cursor)) {
! 537: need_flush |= sent_string(TIPARM_1(parm_right_cursor,
! 538: columns - 1));
! 539: } else {
! 540: for (i = 0; i < columns - 1; i++) {
! 541: out_char(' ');
! 542: need_flush = TRUE;
! 543: }
! 544: }
! 545: need_flush |= sent_string(set_right_margin);
! 546: need_flush |= to_left_margin();
! 547: }
! 548:
! 549: need_flush |= reset_tabstops(columns);
! 550:
! 551: need_flush |= cat_file((use_reset && reset_file) ? reset_file : init_file);
! 552:
! 553: need_flush |= sent_string((use_reset && (reset_3string != 0))
! 554: ? reset_3string
! 555: : init_3string);
! 556: }
! 557:
! 558: return need_flush;
! 559: }
! 560:
! 561: /*
! 562: * Tell the user if a control key has been changed from the default value.
! 563: */
! 564: static void
! 565: show_tty_change(TTY * old_settings,
! 566: TTY * new_settings,
! 567: const char *name,
! 568: int which,
! 569: unsigned def)
! 570: {
! 571: unsigned older = 0, newer = 0;
! 572: char *p;
! 573:
! 574: #if defined(EXP_WIN32_DRIVER)
! 575: /* noop */
! 576: (void) old_settings;
! 577: (void) new_settings;
! 578: (void) name;
! 579: (void) which;
! 580: (void) def;
! 581: #else
! 582: newer = new_settings->c_cc[which];
! 583: older = old_settings->c_cc[which];
! 584:
! 585: if (older == newer && older == def)
! 586: return;
! 587: #endif
! 588: (void) fprintf(stderr, "%s %s ", name, older == newer ? "is" : "set to");
! 589:
! 590: if (DISABLED(newer)) {
! 591: (void) fprintf(stderr, "undef.\n");
! 592: /*
! 593: * Check 'delete' before 'backspace', since the key_backspace value
! 594: * is ambiguous.
! 595: */
! 596: } else if (newer == 0177) {
! 597: (void) fprintf(stderr, "delete.\n");
! 598: } else if ((p = key_backspace) != 0
! 599: && newer == (unsigned char) p[0]
! 600: && p[1] == '\0') {
! 601: (void) fprintf(stderr, "backspace.\n");
! 602: } else if (newer < 040) {
! 603: newer ^= 0100;
! 604: (void) fprintf(stderr, "control-%c (^%c).\n", UChar(newer), UChar(newer));
! 605: } else
! 606: (void) fprintf(stderr, "%c.\n", UChar(newer));
! 607: }
! 608:
! 609: /**************************************************************************
! 610: * Miscellaneous.
! 611: **************************************************************************/
! 612:
! 613: void
! 614: reset_start(FILE *fp, bool is_reset, bool is_init)
! 615: {
! 616: my_file = fp;
! 617: use_reset = is_reset;
! 618: use_init = is_init;
! 619: }
! 620:
! 621: void
! 622: reset_flush(void)
! 623: {
! 624: if (my_file != 0)
! 625: fflush(my_file);
! 626: }
! 627:
! 628: void
! 629: print_tty_chars(TTY * old_settings, TTY * new_settings)
! 630: {
! 631: #if defined(EXP_WIN32_DRIVER)
! 632: /* noop */
! 633: #else
! 634: show_tty_change(old_settings, new_settings, "Erase", VERASE, CERASE);
! 635: show_tty_change(old_settings, new_settings, "Kill", VKILL, CKILL);
! 636: show_tty_change(old_settings, new_settings, "Interrupt", VINTR, CINTR);
! 637: #endif
! 638: }
! 639:
! 640: #if HAVE_SIZECHANGE
! 641: /*
! 642: * Set window size if not set already, but update our copy of the values if the
! 643: * size was set.
! 644: */
! 645: void
! 646: set_window_size(int fd, short *high, short *wide)
! 647: {
! 648: STRUCT_WINSIZE win;
! 649: (void) ioctl(fd, IOCTL_GET_WINSIZE, &win);
! 650: if (WINSIZE_ROWS(win) == 0 &&
! 651: WINSIZE_COLS(win) == 0) {
! 652: if (*high > 0 && *wide > 0) {
! 653: WINSIZE_ROWS(win) = (unsigned short) *high;
! 654: WINSIZE_COLS(win) = (unsigned short) *wide;
! 655: (void) ioctl(fd, IOCTL_SET_WINSIZE, &win);
! 656: }
! 657: } else if (WINSIZE_ROWS(win) > 0 &&
! 658: WINSIZE_COLS(win) > 0) {
! 659: *high = (short) WINSIZE_ROWS(win);
! 660: *wide = (short) WINSIZE_COLS(win);
! 661: }
! 662: }
! 663: #endif