Home | History | Annotate | Line # | Download | only in dist
      1 /* $XTermId: resize.c,v 1.153 2024/12/01 20:21:19 tom Exp $ */
      2 
      3 /*
      4  * Copyright 2003-2023,2024 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 #define ESCAPE(string) "\033" string
     96 
     97 #define	EMULATIONS	2
     98 #define	SUN		1
     99 #define	VT100		0
    100 
    101 #define	TIMEOUT		3
    102 
    103 #define	SHELL_UNKNOWN	0
    104 #define	SHELL_C		1
    105 #define	SHELL_BOURNE	2
    106 /* *INDENT-OFF* */
    107 static struct {
    108     const char *name;
    109     int type;
    110 } shell_list[] = {
    111     { "csh",	SHELL_C },	/* vanilla cshell */
    112     { "jcsh",   SHELL_C },
    113     { "tcsh",   SHELL_C },
    114     { "sh",	SHELL_BOURNE }, /* vanilla Bourne shell */
    115     { "ash",    SHELL_BOURNE },
    116     { "bash",	SHELL_BOURNE }, /* GNU Bourne again shell */
    117     { "dash",	SHELL_BOURNE },
    118     { "jsh",    SHELL_BOURNE },
    119     { "ksh",	SHELL_BOURNE }, /* Korn shell (from AT&T toolchest) */
    120     { "ksh-i",	SHELL_BOURNE }, /* another name for Korn shell */
    121     { "ksh93",	SHELL_BOURNE }, /* Korn shell */
    122     { "mksh",   SHELL_BOURNE },
    123     { "pdksh",  SHELL_BOURNE },
    124     { "zsh",    SHELL_BOURNE },
    125     { NULL,	SHELL_BOURNE }	/* default (same as xterm's) */
    126 };
    127 /* *INDENT-ON* */
    128 
    129 static const char *const emuname[EMULATIONS] =
    130 {
    131     "VT100",
    132     "Sun",
    133 };
    134 static char *myname;
    135 static int shell_type = SHELL_UNKNOWN;
    136 static const char *const getattr[EMULATIONS] =
    137 {
    138     ESCAPE("[c"),
    139     NULL,
    140 };
    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     NULL,
    150     ESCAPE("[14t"),
    151 };
    152 #endif /* USE_STRUCT_WINSIZE */
    153 static const char *const restore[EMULATIONS] =
    154 {
    155     ESCAPE("8"),
    156     NULL,
    157 };
    158 static const char *const setsize[EMULATIONS] =
    159 {
    160     NULL,
    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 reply_attr[EMULATIONS] =
    173 {
    174     ESCAPE("[?%d;%dc"),
    175     NULL,
    176 };
    177 static const char *const reply_size[EMULATIONS] =
    178 {
    179     ESCAPE("[%d;%dR"),
    180     ESCAPE("[8;%d;%dt"),
    181 };
    182 static const char sunname[] = "sunsize";
    183 static int tty;
    184 static FILE *ttyfp;
    185 
    186 #if defined(USE_STRUCT_WINSIZE)
    187 static const char *wsize[EMULATIONS] =
    188 {
    189     NULL,
    190     ESCAPE("[4;%hd;%hdt"),
    191 };
    192 #endif /* USE_STRUCT_WINSIZE */
    193 
    194 static GCC_NORETURN void failed(const char *);
    195 static GCC_NORETURN void onintr(int);
    196 static GCC_NORETURN void resize_timeout(int);
    197 static GCC_NORETURN void Usage(void);
    198 
    199 static void
    200 failed(const char *s)
    201 {
    202     int save = errno;
    203     IGNORE_RC(write(2, myname, strlen(myname)));
    204     IGNORE_RC(write(2, ": ", (size_t) 2));
    205     errno = save;
    206     perror(s);
    207     exit(EXIT_FAILURE);
    208 }
    209 
    210 /* ARGSUSED */
    211 static void
    212 onintr(int sig GCC_UNUSED)
    213 {
    214 #ifdef USE_ANY_SYSV_TERMIO
    215     (void) ioctl(tty, TCSETAW, &tioorig);
    216 #elif defined(USE_TERMIOS)
    217     (void) tcsetattr(tty, TCSADRAIN, &tioorig);
    218 #else /* not USE_TERMIOS */
    219     (void) ioctl(tty, TIOCSETP, &sgorig);
    220 #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
    221     exit(EXIT_FAILURE);
    222 }
    223 
    224 const char *timeout_message = "?";
    225 
    226 static void
    227 resize_timeout(int sig)
    228 {
    229     fprintf(stderr, "\n%s: %s\r\n", myname, timeout_message);
    230     onintr(sig);
    231 }
    232 
    233 static void
    234 Usage(void)
    235 {
    236     fprintf(stderr, strcmp(myname, sunname) == 0 ?
    237 	    "Usage: %s [rows cols]\n" :
    238 	    "Usage: %s [-v] [-u] [-c] [-s [rows cols]]\n", myname);
    239     exit(EXIT_FAILURE);
    240 }
    241 
    242 #ifdef USE_TERMCAP
    243 static void
    244 print_termcap(const char *termcap)
    245 {
    246     int ch;
    247 
    248     putchar('\'');
    249     while ((ch = *termcap++) != '\0') {
    250 	switch (ch & 0xff) {
    251 	case 127:		/* undo bug in GNU termcap */
    252 	    printf("^?");
    253 	    break;
    254 	case '\'':		/* must escape anyway (unlikely) */
    255 	    /* FALLTHRU */
    256 	case '!':		/* must escape for SunOS csh */
    257 	    putchar('\\');
    258 	    /* FALLTHRU */
    259 	default:
    260 	    putchar(ch);
    261 	    break;
    262 	}
    263     }
    264     putchar('\'');
    265 }
    266 #endif /* USE_TERMCAP */
    267 
    268 static int
    269 checkdigits(char *str)
    270 {
    271     while (*str) {
    272 	if (!isdigit(CharOf(*str)))
    273 	    return (0);
    274 	str++;
    275     }
    276     return (1);
    277 }
    278 
    279 static void
    280 unexpected_char(int c)
    281 {
    282     fprintf(stderr,
    283 	    "%s: unknown character %#x, exiting.\r\n",
    284 	    myname, (unsigned) c);
    285     onintr(0);
    286 }
    287 
    288 static void
    289 readstring(FILE *fp, char *buf, const char *str)
    290 {
    291     int last, c;
    292 #if HAVE_SETITIMER
    293     struct itimerval it;
    294 #endif
    295     int limit = (BUFSIZ - 3);
    296 
    297     signal(SIGALRM, resize_timeout);
    298 #if HAVE_SETITIMER
    299     memset((char *) &it, 0, sizeof(struct itimerval));
    300     it.it_value.tv_sec = TIMEOUT;
    301     setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL);
    302 #else
    303     alarm(TIMEOUT);
    304 #endif
    305     if ((c = getc(fp)) == 0233) {	/* meta-escape, CSI */
    306 	c = ESCAPE("")[0];
    307 	*buf++ = (char) c;
    308 	*buf++ = '[';
    309     } else {
    310 	*buf++ = (char) c;
    311     }
    312     if (c != *str) {
    313 	unexpected_char(c);
    314     }
    315     last = str[strlen(str) - 1];
    316     while ((c = getc(fp)) != EOF) {
    317 	if (--limit <= 0) {
    318 	    fprintf(stderr, "%s: unexpected response\n", myname);
    319 	    onintr(0);
    320 	}
    321 	if (c < 32 || c > 126) {
    322 	    unexpected_char(c);
    323 	}
    324 	*buf++ = (char) c;
    325 	if (c == last)
    326 	    break;
    327     }
    328 #if HAVE_SETITIMER
    329     memset((char *) &it, 0, sizeof(struct itimerval));
    330     setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL);
    331 #else
    332     alarm(0);
    333 #endif
    334     *buf = 0;
    335 }
    336 
    337 /*
    338    resets termcap string to reflect current screen size
    339  */
    340 int
    341 main(int argc, char **argv ENVP_ARG)
    342 {
    343 #ifdef USE_TERMCAP
    344     char *env;
    345 #endif
    346     char *ptr;
    347     int emu = VT100;
    348     char *shell;
    349     int i;
    350     int rc;
    351     int rows, cols;
    352 #ifdef USE_ANY_SYSV_TERMIO
    353     struct termio tio;
    354 #elif defined(USE_TERMIOS)
    355     struct termios tio;
    356 #else
    357     struct sgttyb sg;
    358 #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
    359 #ifdef USE_TERMCAP
    360     int ok_tcap = 1;
    361     char termcap[TERMCAP_SIZE];
    362     char newtc[TERMCAP_SIZE];
    363 #endif /* USE_TERMCAP */
    364     char buf[BUFSIZ];
    365 #ifdef TTYSIZE_STRUCT
    366     TTYSIZE_STRUCT ts;
    367 #endif
    368     char *name_of_tty;
    369 #ifdef CANT_OPEN_DEV_TTY
    370     extern char *ttyname();
    371 #endif
    372     const char *setname = "";
    373 
    374     myname = x_basename(argv[0]);
    375     if (strcmp(myname, sunname) == 0)
    376 	emu = SUN;
    377     for (argv++, argc--; argc > 0 && **argv == '-'; argv++, argc--) {
    378 	switch ((*argv)[1]) {
    379 	case 's':		/* Sun emulation */
    380 	    if (emu == SUN)
    381 		Usage();	/* Never returns */
    382 	    emu = SUN;
    383 	    break;
    384 	case 'u':		/* Bourne (Unix) shell */
    385 	    shell_type = SHELL_BOURNE;
    386 	    break;
    387 	case 'c':		/* C shell */
    388 	    shell_type = SHELL_C;
    389 	    break;
    390 	case 'v':
    391 	    printf("%s\n", xtermVersion());
    392 	    exit(EXIT_SUCCESS);
    393 	default:
    394 	    Usage();		/* Never returns */
    395 	}
    396     }
    397 
    398     if (SHELL_UNKNOWN == shell_type) {
    399 	/* Find out what kind of shell this user is running.
    400 	 * This is the same algorithm that xterm uses.
    401 	 */
    402 	if ((ptr = x_getenv("SHELL")) == NULL) {
    403 	    uid_t uid = getuid();
    404 	    struct passwd pw;
    405 
    406 	    if (x_getpwuid(uid, &pw)) {
    407 		(void) x_getlogin(uid, &pw);
    408 	    }
    409 	    if (!OkPasswd(&pw)
    410 		|| *(ptr = pw.pw_shell) == 0) {
    411 		/* this is the same default that xterm uses */
    412 		ptr = x_strdup("/bin/sh");
    413 	    }
    414 	}
    415 
    416 	shell = x_basename(ptr);
    417 
    418 	/* now that we know, what kind is it? */
    419 	for (i = 0; shell_list[i].name; i++) {
    420 	    if (!strcmp(shell_list[i].name, shell)) {
    421 		break;
    422 	    }
    423 	}
    424 	shell_type = shell_list[i].type;
    425     }
    426 
    427     if (argc == 2) {
    428 	if (!setsize[emu]) {
    429 	    fprintf(stderr,
    430 		    "%s: Can't set window size under %s emulation\n",
    431 		    myname, emuname[emu]);
    432 	    exit(EXIT_FAILURE);
    433 	}
    434 	if (!checkdigits(argv[0]) || !checkdigits(argv[1])) {
    435 	    Usage();		/* Never returns */
    436 	}
    437     } else if (argc != 0) {
    438 	Usage();		/* Never returns */
    439     }
    440 #ifdef CANT_OPEN_DEV_TTY
    441     if ((name_of_tty = ttyname(fileno(stderr))) == NULL)
    442 #endif
    443 	name_of_tty = x_strdup("/dev/tty");
    444 
    445     if ((ttyfp = fopen(name_of_tty, "r+")) == NULL) {
    446 	fprintf(stderr, "%s:  can't open terminal %s\n",
    447 		myname, name_of_tty);
    448 	exit(EXIT_FAILURE);
    449     }
    450     tty = fileno(ttyfp);
    451 #ifdef USE_TERMCAP
    452     if ((env = x_getenv("TERM")) == 0) {
    453 	env = x_strdup(DFT_TERMTYPE);
    454 	if (SHELL_BOURNE == shell_type) {
    455 	    setname = "TERM=" DFT_TERMTYPE ";\nexport TERM;\n";
    456 	} else {
    457 	    setname = "setenv TERM " DFT_TERMTYPE ";\n";
    458 	}
    459     }
    460     termcap[0] = 0;		/* ...just in case we've accidentally gotten terminfo */
    461     if (tgetent(termcap, env) <= 0 || termcap[0] == 0) {
    462 	ok_tcap = 0;
    463     }
    464 #endif /* USE_TERMCAP */
    465 #ifdef USE_TERMINFO
    466     if (x_getenv("TERM") == NULL) {
    467 	if (SHELL_BOURNE == shell_type) {
    468 	    setname = "TERM=" DFT_TERMTYPE ";\nexport TERM;\n";
    469 	} else {
    470 	    setname = "setenv TERM " DFT_TERMTYPE ";\n";
    471 	}
    472     }
    473 #endif /* USE_TERMINFO */
    474 
    475 #ifdef USE_ANY_SYSV_TERMIO
    476     rc = ioctl(tty, TCGETA, &tioorig);
    477     tio = tioorig;
    478     UIntClr(tio.c_iflag, (ICRNL | IUCLC));
    479     UIntClr(tio.c_lflag, (ICANON | ECHO));
    480     tio.c_cflag |= CS8;
    481     tio.c_cc[VMIN] = 6;
    482     tio.c_cc[VTIME] = 1;
    483 #elif defined(USE_TERMIOS)
    484     rc = tcgetattr(tty, &tioorig);
    485     tio = tioorig;
    486     UIntClr(tio.c_iflag, ICRNL);
    487     UIntClr(tio.c_lflag, (ICANON | ECHO));
    488     tio.c_cflag |= CS8;
    489     tio.c_cc[VMIN] = 6;
    490     tio.c_cc[VTIME] = 1;
    491 #else /* not USE_TERMIOS */
    492     rc = ioctl(tty, TIOCGETP, &sgorig);
    493     sg = sgorig;
    494     sg.sg_flags |= RAW;
    495     UIntClr(sg.sg_flags, ECHO);
    496 #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
    497     if (rc != 0)
    498 	failed("get tty settings");
    499 
    500     signal(SIGINT, onintr);
    501     signal(SIGQUIT, onintr);
    502     signal(SIGTERM, onintr);
    503 
    504 #ifdef USE_ANY_SYSV_TERMIO
    505     rc = ioctl(tty, TCSETAW, &tio);
    506 #elif defined(USE_TERMIOS)
    507     rc = tcsetattr(tty, TCSADRAIN, &tio);
    508 #else /* not USE_TERMIOS */
    509     rc = ioctl(tty, TIOCSETP, &sg);
    510 #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
    511     if (rc != 0)
    512 	failed("set tty settings");
    513 
    514     if (argc == 2) {		/* look for optional parameters of "-s" */
    515 	char *tmpbuf = TypeMallocN(char,
    516 				   strlen(setsize[emu]) +
    517 				   strlen(argv[0]) +
    518 				   strlen(argv[1]) +
    519 				   1);
    520 	if (tmpbuf == NULL) {
    521 	    fprintf(stderr, "%s: Cannot query size\n", myname);
    522 	    onintr(0);
    523 	} else {
    524 	    sprintf(tmpbuf, setsize[emu], argv[0], argv[1]);
    525 	    IGNORE_RC(write(tty, tmpbuf, strlen(tmpbuf)));
    526 	    free(tmpbuf);
    527 	}
    528     }
    529     if (getattr[emu]) {
    530 	timeout_message = "Terminal is not VT100-compatible";
    531 	IGNORE_RC(write(tty, getattr[emu], strlen(getattr[emu])));
    532 	readstring(ttyfp, buf, reply_attr[emu]);
    533     }
    534     timeout_message = "Time out occurred";
    535     IGNORE_RC(write(tty, getsize[emu], strlen(getsize[emu])));
    536     readstring(ttyfp, buf, reply_size[emu]);
    537     if (sscanf(buf, reply_size[emu], &rows, &cols) != 2) {
    538 	fprintf(stderr, "%s: Can't get rows and columns\r\n", myname);
    539 	onintr(0);
    540     }
    541     if (restore[emu])
    542 	IGNORE_RC(write(tty, restore[emu], strlen(restore[emu])));
    543 #if defined(USE_STRUCT_WINSIZE)
    544     /* finally, set the tty's window size */
    545     if (getwsize[emu]) {
    546 	/* get the window size in pixels */
    547 	IGNORE_RC(write(tty, getwsize[emu], strlen(getwsize[emu])));
    548 	readstring(ttyfp, buf, wsize[emu]);
    549 	if (sscanf(buf, wsize[emu], &ts.ws_xpixel, &ts.ws_ypixel) != 2) {
    550 	    fprintf(stderr, "%s: Can't get window size\r\n", myname);
    551 	    onintr(0);
    552 	}
    553 	setup_winsize(ts, rows, cols, 0, 0);
    554 	SET_TTYSIZE(tty, ts);
    555     } else if (ioctl(tty, TIOCGWINSZ, &ts) != -1) {
    556 	/* we don't have any way of directly finding out
    557 	   the current height & width of the window in pixels.  We try
    558 	   our best by computing the font height and width from the "old"
    559 	   window-size values, and multiplying by these ratios... */
    560 #define scaled(old,new,len) (old)?((unsigned)(new)*(len)/(old)):(len)
    561 	setup_winsize(ts, rows, cols,
    562 		      scaled(TTYSIZE_ROWS(ts), rows, ts.ws_ypixel),
    563 		      scaled(TTYSIZE_COLS(ts), cols, ts.ws_xpixel));
    564 	SET_TTYSIZE(tty, ts);
    565     }
    566 #endif /* USE_STRUCT_WINSIZE */
    567 
    568 #ifdef USE_ANY_SYSV_TERMIO
    569     rc = ioctl(tty, TCSETAW, &tioorig);
    570 #elif defined(USE_TERMIOS)
    571     rc = tcsetattr(tty, TCSADRAIN, &tioorig);
    572 #else /* not USE_TERMIOS */
    573     rc = ioctl(tty, TIOCSETP, &sgorig);
    574 #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
    575     if (rc != 0)
    576 	failed("set tty settings");
    577 
    578     signal(SIGINT, SIG_DFL);
    579     signal(SIGQUIT, SIG_DFL);
    580     signal(SIGTERM, SIG_DFL);
    581 
    582 #ifdef USE_TERMCAP
    583     if (ok_tcap) {
    584 	/* update termcap string */
    585 	/* first do columns */
    586 	if ((ptr = x_strindex(termcap, "co#")) == NULL) {
    587 	    fprintf(stderr, "%s: No `co#'\n", myname);
    588 	    exit(EXIT_FAILURE);
    589 	}
    590 
    591 	i = (int) (ptr - termcap) + 3;
    592 	strncpy(newtc, termcap, (size_t) i);
    593 	sprintf(newtc + i, "%d", cols);
    594 	if ((ptr = strchr(ptr, ':')) != 0)
    595 	    strcat(newtc, ptr);
    596 
    597 	/* now do lines */
    598 	if ((ptr = x_strindex(newtc, "li#")) == NULL) {
    599 	    fprintf(stderr, "%s: No `li#'\n", myname);
    600 	    exit(EXIT_FAILURE);
    601 	}
    602 
    603 	i = (int) (ptr - newtc) + 3;
    604 	strncpy(termcap, newtc, (size_t) i);
    605 	sprintf(termcap + i, "%d", rows);
    606 	if ((ptr = strchr(ptr, ':')) != 0)
    607 	    strcat(termcap, ptr);
    608     }
    609 #endif /* USE_TERMCAP */
    610 
    611     if (SHELL_BOURNE == shell_type) {
    612 
    613 #ifdef USE_TERMCAP
    614 	if (ok_tcap) {
    615 	    printf("%sTERMCAP=", setname);
    616 	    print_termcap(termcap);
    617 	    printf(";\nexport TERMCAP;\n");
    618 	}
    619 #endif /* USE_TERMCAP */
    620 #ifdef USE_TERMINFO
    621 	printf("%sCOLUMNS=%d;\nLINES=%d;\nexport COLUMNS LINES;\n",
    622 	       setname, cols, rows);
    623 #endif /* USE_TERMINFO */
    624 
    625     } else {			/* not Bourne shell */
    626 
    627 #ifdef USE_TERMCAP
    628 	if (ok_tcap) {
    629 	    printf("set noglob;\n%ssetenv TERMCAP ", setname);
    630 	    print_termcap(termcap);
    631 	    printf(";\nunset noglob;\n");
    632 	}
    633 #endif /* USE_TERMCAP */
    634 #ifdef USE_TERMINFO
    635 	printf("set noglob;\n%ssetenv COLUMNS '%d';\nsetenv LINES '%d';\nunset noglob;\n",
    636 	       setname, cols, rows);
    637 #endif /* USE_TERMINFO */
    638     }
    639     exit(EXIT_SUCCESS);
    640 }
    641