Home | History | Annotate | Line # | Download | only in resize
      1 /* $XTermId: resize.c,v 1.144 2020/06/03 00:26:23 tom Exp $ */
      2 
      3 /*
      4  * Copyright 2003-2018,2020 by Thomas E. Dickey
      5  *
      6  *                         All Rights Reserved
      7  *
      8  * Permission is hereby granted, free of charge, to any person obtaining a
      9  * copy of this software and associated documentation files (the
     10  * "Software"), to deal in the Software without restriction, including
     11  * without limitation the rights to use, copy, modify, merge, publish,
     12  * distribute, sublicense, and/or sell copies of the Software, and to
     13  * permit persons to whom the Software is furnished to do so, subject to
     14  * the following conditions:
     15  *
     16  * The above copyright notice and this permission notice shall be included
     17  * in all copies or substantial portions of the Software.
     18  *
     19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     22  * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
     23  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     26  *
     27  * Except as contained in this notice, the name(s) of the above copyright
     28  * holders shall not be used in advertising or otherwise to promote the
     29  * sale, use or other dealings in this Software without prior written
     30  * authorization.
     31  *
     32  *
     33  * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
     34  *
     35  *                         All Rights Reserved
     36  *
     37  * Permission to use, copy, modify, and distribute this software and its
     38  * documentation for any purpose and without fee is hereby granted,
     39  * provided that the above copyright notice appear in all copies and that
     40  * both that copyright notice and this permission notice appear in
     41  * supporting documentation, and that the name of Digital Equipment
     42  * Corporation not be used in advertising or publicity pertaining to
     43  * distribution of the software without specific, written prior permission.
     44  *
     45  *
     46  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
     47  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
     48  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
     49  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
     50  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
     51  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     52  * SOFTWARE.
     53  */
     54 
     55 /* resize.c */
     56 
     57 #include <stdio.h>
     58 #include <ctype.h>
     59 
     60 #ifdef RESIZE_ONLY
     61 #include "resize.h"
     62 #else
     63 #include <xterm.h>
     64 #include <version.h>
     65 #include <xstrings.h>
     66 #include <xtermcap.h>
     67 #include <xterm_io.h>
     68 #endif
     69 
     70 #ifndef USE_TERMINFO		/* avoid conflict with configure script */
     71 #if defined(__QNX__) || defined(__SCO__) || defined(linux) || defined(__OpenBSD__) || defined(__UNIXWARE__)
     72 #define USE_TERMINFO
     73 #endif
     74 #endif
     75 
     76 #if defined(__QNX__)
     77 #include <unix.h>
     78 #endif
     79 
     80 /*
     81  * Some OS's may want to use both, like SCO for example.  We catch here anyone
     82  * who hasn't decided what they want.
     83  */
     84 #if !defined(USE_TERMCAP) && !defined(USE_TERMINFO)
     85 #define USE_TERMINFO
     86 #endif
     87 
     88 #include <signal.h>
     89 #include <pwd.h>
     90 
     91 #ifdef USE_IGNORE_RC
     92 int ignore_unused;
     93 #endif
     94 
     95 #ifdef __MVS__
     96 #define ESCAPE(string) "\047" string
     97 #else
     98 #define ESCAPE(string) "\033" string
     99 #endif
    100 
    101 #define	EMULATIONS	2
    102 #define	SUN		1
    103 #define	VT100		0
    104 
    105 #define	TIMEOUT		10
    106 
    107 #define	SHELL_UNKNOWN	0
    108 #define	SHELL_C		1
    109 #define	SHELL_BOURNE	2
    110 
    111 /* *INDENT-OFF* */
    112 static struct {
    113     const char *name;
    114     int type;
    115 } shell_list[] = {
    116     { "csh",	SHELL_C },	/* vanilla cshell */
    117     { "jcsh",   SHELL_C },
    118     { "tcsh",   SHELL_C },
    119     { "sh",	SHELL_BOURNE }, /* vanilla Bourne shell */
    120     { "ash",    SHELL_BOURNE },
    121     { "bash",	SHELL_BOURNE }, /* GNU Bourne again shell */
    122     { "dash",	SHELL_BOURNE },
    123     { "jsh",    SHELL_BOURNE },
    124     { "ksh",	SHELL_BOURNE }, /* Korn shell (from AT&T toolchest) */
    125     { "ksh-i",	SHELL_BOURNE }, /* another name for Korn shell */
    126     { "ksh93",	SHELL_BOURNE }, /* Korn shell */
    127     { "mksh",   SHELL_BOURNE },
    128     { "pdksh",  SHELL_BOURNE },
    129     { "zsh",    SHELL_BOURNE },
    130     { NULL,	SHELL_BOURNE }	/* default (same as xterm's) */
    131 };
    132 /* *INDENT-ON* */
    133 
    134 static const char *const emuname[EMULATIONS] =
    135 {
    136     "VT100",
    137     "Sun",
    138 };
    139 static char *myname;
    140 static int shell_type = SHELL_UNKNOWN;
    141 static const char *const getsize[EMULATIONS] =
    142 {
    143     ESCAPE("7") ESCAPE("[r") ESCAPE("[9999;9999H") ESCAPE("[6n"),
    144     ESCAPE("[18t"),
    145 };
    146 #if defined(USE_STRUCT_WINSIZE)
    147 static const char *const getwsize[EMULATIONS] =
    148 {				/* size in pixels */
    149     0,
    150     ESCAPE("[14t"),
    151 };
    152 #endif /* USE_STRUCT_WINSIZE */
    153 static const char *const restore[EMULATIONS] =
    154 {
    155     ESCAPE("8"),
    156     0,
    157 };
    158 static const char *const setsize[EMULATIONS] =
    159 {
    160     0,
    161     ESCAPE("[8;%s;%st"),
    162 };
    163 
    164 #ifdef USE_ANY_SYSV_TERMIO
    165 static struct termio tioorig;
    166 #elif defined(USE_TERMIOS)
    167 static struct termios tioorig;
    168 #else
    169 static struct sgttyb sgorig;
    170 #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
    171 
    172 static const char *const size[EMULATIONS] =
    173 {
    174     ESCAPE("[%d;%dR"),
    175     ESCAPE("[8;%d;%dt"),
    176 };
    177 static const char sunname[] = "sunsize";
    178 static int tty;
    179 static FILE *ttyfp;
    180 
    181 #if defined(USE_STRUCT_WINSIZE)
    182 static const char *wsize[EMULATIONS] =
    183 {
    184     0,
    185     ESCAPE("[4;%hd;%hdt"),
    186 };
    187 #endif /* USE_STRUCT_WINSIZE */
    188 
    189 static void failed(const char *) GCC_NORETURN;
    190 static void onintr(int) GCC_NORETURN;
    191 static void resize_timeout(int) GCC_NORETURN;
    192 static void Usage(void) GCC_NORETURN;
    193 
    194 static void
    195 failed(const char *s)
    196 {
    197     int save = errno;
    198     IGNORE_RC(write(2, myname, strlen(myname)));
    199     IGNORE_RC(write(2, ": ", (size_t) 2));
    200     errno = save;
    201     perror(s);
    202     exit(EXIT_FAILURE);
    203 }
    204 
    205 /* ARGSUSED */
    206 static void
    207 onintr(int sig GCC_UNUSED)
    208 {
    209 #ifdef USE_ANY_SYSV_TERMIO
    210     (void) ioctl(tty, TCSETAW, &tioorig);
    211 #elif defined(USE_TERMIOS)
    212     (void) tcsetattr(tty, TCSADRAIN, &tioorig);
    213 #else /* not USE_TERMIOS */
    214     (void) ioctl(tty, TIOCSETP, &sgorig);
    215 #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
    216     exit(EXIT_FAILURE);
    217 }
    218 
    219 static void
    220 resize_timeout(int sig)
    221 {
    222     fprintf(stderr, "\n%s: Time out occurred\r\n", myname);
    223     onintr(sig);
    224 }
    225 
    226 static void
    227 Usage(void)
    228 {
    229     fprintf(stderr, strcmp(myname, sunname) == 0 ?
    230 	    "Usage: %s [rows cols]\n" :
    231 	    "Usage: %s [-v] [-u] [-c] [-s [rows cols]]\n", myname);
    232     exit(EXIT_FAILURE);
    233 }
    234 
    235 #ifdef USE_TERMCAP
    236 static void
    237 print_termcap(const char *termcap)
    238 {
    239     int ch;
    240 
    241     putchar('\'');
    242     while ((ch = *termcap++) != '\0') {
    243 	switch (ch & 0xff) {
    244 	case 127:		/* undo bug in GNU termcap */
    245 	    printf("^?");
    246 	    break;
    247 	case '\'':		/* must escape anyway (unlikely) */
    248 	    /* FALLTHRU */
    249 	case '!':		/* must escape for SunOS csh */
    250 	    putchar('\\');
    251 	    /* FALLTHRU */
    252 	default:
    253 	    putchar(ch);
    254 	    break;
    255 	}
    256     }
    257     putchar('\'');
    258 }
    259 #endif /* USE_TERMCAP */
    260 
    261 static int
    262 checkdigits(char *str)
    263 {
    264     while (*str) {
    265 	if (!isdigit(CharOf(*str)))
    266 	    return (0);
    267 	str++;
    268     }
    269     return (1);
    270 }
    271 
    272 static void
    273 readstring(FILE *fp, char *buf, const char *str)
    274 {
    275     int last, c;
    276 #if !defined(USG) && !defined(__minix)
    277     /* What is the advantage of setitimer() over alarm()? */
    278     struct itimerval it;
    279 #endif
    280 
    281     signal(SIGALRM, resize_timeout);
    282 #if defined(USG) || defined(__minix)
    283     alarm(TIMEOUT);
    284 #else
    285     memset((char *) &it, 0, sizeof(struct itimerval));
    286     it.it_value.tv_sec = TIMEOUT;
    287     setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL);
    288 #endif
    289     if ((c = getc(fp)) == 0233) {	/* meta-escape, CSI */
    290 	c = ESCAPE("")[0];
    291 	*buf++ = (char) c;
    292 	*buf++ = '[';
    293     } else {
    294 	*buf++ = (char) c;
    295     }
    296     if (c != *str) {
    297 	fprintf(stderr, "%s: unknown character, exiting.\r\n", myname);
    298 	onintr(0);
    299     }
    300     last = str[strlen(str) - 1];
    301     while ((*buf++ = (char) getc(fp)) != last) {
    302 	;
    303     }
    304 #if defined(USG) || defined(__minix)
    305     alarm(0);
    306 #else
    307     memset((char *) &it, 0, sizeof(struct itimerval));
    308     setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL);
    309 #endif
    310     *buf = 0;
    311 }
    312 
    313 /*
    314    resets termcap string to reflect current screen size
    315  */
    316 int
    317 main(int argc, char **argv ENVP_ARG)
    318 {
    319 #ifdef USE_TERMCAP
    320     char *env;
    321 #endif
    322     char *ptr;
    323     int emu = VT100;
    324     char *shell;
    325     int i;
    326     int rc;
    327     int rows, cols;
    328 #ifdef USE_ANY_SYSV_TERMIO
    329     struct termio tio;
    330 #elif defined(USE_TERMIOS)
    331     struct termios tio;
    332 #else
    333     struct sgttyb sg;
    334 #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
    335 #ifdef USE_TERMCAP
    336     int ok_tcap = 1;
    337     char termcap[TERMCAP_SIZE];
    338     char newtc[TERMCAP_SIZE];
    339 #endif /* USE_TERMCAP */
    340     char buf[BUFSIZ];
    341 #ifdef TTYSIZE_STRUCT
    342     TTYSIZE_STRUCT ts;
    343 #endif
    344     char *name_of_tty;
    345 #ifdef CANT_OPEN_DEV_TTY
    346     extern char *ttyname();
    347 #endif
    348     const char *setname = "";
    349 
    350     myname = x_basename(argv[0]);
    351     if (strcmp(myname, sunname) == 0)
    352 	emu = SUN;
    353     for (argv++, argc--; argc > 0 && **argv == '-'; argv++, argc--) {
    354 	switch ((*argv)[1]) {
    355 	case 's':		/* Sun emulation */
    356 	    if (emu == SUN)
    357 		Usage();	/* Never returns */
    358 	    emu = SUN;
    359 	    break;
    360 	case 'u':		/* Bourne (Unix) shell */
    361 	    shell_type = SHELL_BOURNE;
    362 	    break;
    363 	case 'c':		/* C shell */
    364 	    shell_type = SHELL_C;
    365 	    break;
    366 	case 'v':
    367 	    printf("%s\n", xtermVersion());
    368 	    exit(EXIT_SUCCESS);
    369 	default:
    370 	    Usage();		/* Never returns */
    371 	}
    372     }
    373 
    374     if (SHELL_UNKNOWN == shell_type) {
    375 	/* Find out what kind of shell this user is running.
    376 	 * This is the same algorithm that xterm uses.
    377 	 */
    378 	if ((ptr = x_getenv("SHELL")) == NULL) {
    379 	    uid_t uid = getuid();
    380 	    struct passwd pw;
    381 
    382 	    if (x_getpwuid(uid, &pw)) {
    383 		(void) x_getlogin(uid, &pw);
    384 	    }
    385 	    if (!OkPasswd(&pw)
    386 		|| *(ptr = pw.pw_shell) == 0) {
    387 		/* this is the same default that xterm uses */
    388 		ptr = x_strdup("/bin/sh");
    389 	    }
    390 	}
    391 
    392 	shell = x_basename(ptr);
    393 
    394 	/* now that we know, what kind is it? */
    395 	for (i = 0; shell_list[i].name; i++) {
    396 	    if (!strcmp(shell_list[i].name, shell)) {
    397 		break;
    398 	    }
    399 	}
    400 	shell_type = shell_list[i].type;
    401     }
    402 
    403     if (argc == 2) {
    404 	if (!setsize[emu]) {
    405 	    fprintf(stderr,
    406 		    "%s: Can't set window size under %s emulation\n",
    407 		    myname, emuname[emu]);
    408 	    exit(EXIT_FAILURE);
    409 	}
    410 	if (!checkdigits(argv[0]) || !checkdigits(argv[1])) {
    411 	    Usage();		/* Never returns */
    412 	}
    413     } else if (argc != 0) {
    414 	Usage();		/* Never returns */
    415     }
    416 #ifdef CANT_OPEN_DEV_TTY
    417     if ((name_of_tty = ttyname(fileno(stderr))) == NULL)
    418 #endif
    419 	name_of_tty = x_strdup("/dev/tty");
    420 
    421     if ((ttyfp = fopen(name_of_tty, "r+")) == NULL) {
    422 	fprintf(stderr, "%s:  can't open terminal %s\n",
    423 		myname, name_of_tty);
    424 	exit(EXIT_FAILURE);
    425     }
    426     tty = fileno(ttyfp);
    427 #ifdef USE_TERMCAP
    428     if ((env = x_getenv("TERM")) == 0) {
    429 	env = x_strdup(DFT_TERMTYPE);
    430 	if (SHELL_BOURNE == shell_type) {
    431 	    setname = "TERM=" DFT_TERMTYPE ";\nexport TERM;\n";
    432 	} else {
    433 	    setname = "setenv TERM " DFT_TERMTYPE ";\n";
    434 	}
    435     }
    436     termcap[0] = 0;		/* ...just in case we've accidentally gotten terminfo */
    437     if (tgetent(termcap, env) <= 0 || termcap[0] == 0) {
    438 	ok_tcap = 0;
    439     }
    440 #endif /* USE_TERMCAP */
    441 #ifdef USE_TERMINFO
    442     if (x_getenv("TERM") == 0) {
    443 	if (SHELL_BOURNE == shell_type) {
    444 	    setname = "TERM=" DFT_TERMTYPE ";\nexport TERM;\n";
    445 	} else {
    446 	    setname = "setenv TERM " DFT_TERMTYPE ";\n";
    447 	}
    448     }
    449 #endif /* USE_TERMINFO */
    450 
    451 #ifdef USE_ANY_SYSV_TERMIO
    452     rc = ioctl(tty, TCGETA, &tioorig);
    453     tio = tioorig;
    454     UIntClr(tio.c_iflag, (ICRNL | IUCLC));
    455     UIntClr(tio.c_lflag, (ICANON | ECHO));
    456     tio.c_cflag |= CS8;
    457     tio.c_cc[VMIN] = 6;
    458     tio.c_cc[VTIME] = 1;
    459 #elif defined(USE_TERMIOS)
    460     rc = tcgetattr(tty, &tioorig);
    461     tio = tioorig;
    462     UIntClr(tio.c_iflag, ICRNL);
    463     UIntClr(tio.c_lflag, (ICANON | ECHO));
    464     tio.c_cflag |= CS8;
    465     tio.c_cc[VMIN] = 6;
    466     tio.c_cc[VTIME] = 1;
    467 #else /* not USE_TERMIOS */
    468     rc = ioctl(tty, TIOCGETP, &sgorig);
    469     sg = sgorig;
    470     sg.sg_flags |= RAW;
    471     UIntClr(sg.sg_flags, ECHO);
    472 #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
    473     if (rc != 0)
    474 	failed("get tty settings");
    475 
    476     signal(SIGINT, onintr);
    477     signal(SIGQUIT, onintr);
    478     signal(SIGTERM, onintr);
    479 
    480 #ifdef USE_ANY_SYSV_TERMIO
    481     rc = ioctl(tty, TCSETAW, &tio);
    482 #elif defined(USE_TERMIOS)
    483     rc = tcsetattr(tty, TCSADRAIN, &tio);
    484 #else /* not USE_TERMIOS */
    485     rc = ioctl(tty, TIOCSETP, &sg);
    486 #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
    487     if (rc != 0)
    488 	failed("set tty settings");
    489 
    490     if (argc == 2) {		/* look for optional parameters of "-s" */
    491 	char *tmpbuf = TypeMallocN(char,
    492 				   strlen(setsize[emu]) +
    493 				   strlen(argv[0]) +
    494 				   strlen(argv[1]) +
    495 				   1);
    496 	if (tmpbuf == 0) {
    497 	    fprintf(stderr, "%s: Cannot query size\n", myname);
    498 	    onintr(0);
    499 	} else {
    500 	    sprintf(tmpbuf, setsize[emu], argv[0], argv[1]);
    501 	    IGNORE_RC(write(tty, tmpbuf, strlen(tmpbuf)));
    502 	    free(tmpbuf);
    503 	}
    504     }
    505     IGNORE_RC(write(tty, getsize[emu], strlen(getsize[emu])));
    506     readstring(ttyfp, buf, size[emu]);
    507     if (sscanf(buf, size[emu], &rows, &cols) != 2) {
    508 	fprintf(stderr, "%s: Can't get rows and columns\r\n", myname);
    509 	onintr(0);
    510     }
    511     if (restore[emu])
    512 	IGNORE_RC(write(tty, restore[emu], strlen(restore[emu])));
    513 #if defined(USE_STRUCT_WINSIZE)
    514     /* finally, set the tty's window size */
    515     if (getwsize[emu]) {
    516 	/* get the window size in pixels */
    517 	IGNORE_RC(write(tty, getwsize[emu], strlen(getwsize[emu])));
    518 	readstring(ttyfp, buf, wsize[emu]);
    519 	if (sscanf(buf, wsize[emu], &ts.ws_xpixel, &ts.ws_ypixel) != 2) {
    520 	    fprintf(stderr, "%s: Can't get window size\r\n", myname);
    521 	    onintr(0);
    522 	}
    523 	setup_winsize(ts, rows, cols, 0, 0);
    524 	SET_TTYSIZE(tty, ts);
    525     } else if (ioctl(tty, TIOCGWINSZ, &ts) != -1) {
    526 	/* we don't have any way of directly finding out
    527 	   the current height & width of the window in pixels.  We try
    528 	   our best by computing the font height and width from the "old"
    529 	   window-size values, and multiplying by these ratios... */
    530 #define scaled(old,new,len) (old)?((unsigned)(new)*(len)/(old)):(len)
    531 	setup_winsize(ts, rows, cols,
    532 		      scaled(TTYSIZE_ROWS(ts), rows, ts.ws_ypixel),
    533 		      scaled(TTYSIZE_COLS(ts), cols, ts.ws_xpixel));
    534 	SET_TTYSIZE(tty, ts);
    535     }
    536 #endif /* USE_STRUCT_WINSIZE */
    537 
    538 #ifdef USE_ANY_SYSV_TERMIO
    539     rc = ioctl(tty, TCSETAW, &tioorig);
    540 #elif defined(USE_TERMIOS)
    541     rc = tcsetattr(tty, TCSADRAIN, &tioorig);
    542 #else /* not USE_TERMIOS */
    543     rc = ioctl(tty, TIOCSETP, &sgorig);
    544 #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
    545     if (rc != 0)
    546 	failed("set tty settings");
    547 
    548     signal(SIGINT, SIG_DFL);
    549     signal(SIGQUIT, SIG_DFL);
    550     signal(SIGTERM, SIG_DFL);
    551 
    552 #ifdef USE_TERMCAP
    553     if (ok_tcap) {
    554 	/* update termcap string */
    555 	/* first do columns */
    556 	if ((ptr = x_strindex(termcap, "co#")) == NULL) {
    557 	    fprintf(stderr, "%s: No `co#'\n", myname);
    558 	    exit(EXIT_FAILURE);
    559 	}
    560 
    561 	i = (int) (ptr - termcap) + 3;
    562 	strncpy(newtc, termcap, (size_t) i);
    563 	sprintf(newtc + i, "%d", cols);
    564 	if ((ptr = strchr(ptr, ':')) != 0)
    565 	    strcat(newtc, ptr);
    566 
    567 	/* now do lines */
    568 	if ((ptr = x_strindex(newtc, "li#")) == NULL) {
    569 	    fprintf(stderr, "%s: No `li#'\n", myname);
    570 	    exit(EXIT_FAILURE);
    571 	}
    572 
    573 	i = (int) (ptr - newtc) + 3;
    574 	strncpy(termcap, newtc, (size_t) i);
    575 	sprintf(termcap + i, "%d", rows);
    576 	if ((ptr = strchr(ptr, ':')) != 0)
    577 	    strcat(termcap, ptr);
    578     }
    579 #endif /* USE_TERMCAP */
    580 
    581     if (SHELL_BOURNE == shell_type) {
    582 
    583 #ifdef USE_TERMCAP
    584 	if (ok_tcap) {
    585 	    printf("%sTERMCAP=", setname);
    586 	    print_termcap(termcap);
    587 	    printf(";\nexport TERMCAP;\n");
    588 	}
    589 #endif /* USE_TERMCAP */
    590 #ifdef USE_TERMINFO
    591 	printf("%sCOLUMNS=%d;\nLINES=%d;\nexport COLUMNS LINES;\n",
    592 	       setname, cols, rows);
    593 #endif /* USE_TERMINFO */
    594 
    595     } else {			/* not Bourne shell */
    596 
    597 #ifdef USE_TERMCAP
    598 	if (ok_tcap) {
    599 	    printf("set noglob;\n%ssetenv TERMCAP ", setname);
    600 	    print_termcap(termcap);
    601 	    printf(";\nunset noglob;\n");
    602 	}
    603 #endif /* USE_TERMCAP */
    604 #ifdef USE_TERMINFO
    605 	printf("set noglob;\n%ssetenv COLUMNS '%d';\nsetenv LINES '%d';\nunset noglob;\n",
    606 	       setname, cols, rows);
    607 #endif /* USE_TERMINFO */
    608     }
    609     exit(EXIT_SUCCESS);
    610 }
    611