Home | History | Annotate | Line # | Download | only in resize
resize.c revision 1.1
      1 /* $NetBSD: resize.c,v 1.1 2020/12/27 21:13:18 reinoud Exp $ */
      2 /* $XTermId: resize.c,v 1.139 2017/05/31 08:58:56 tom Exp $ */
      3 
      4 /*
      5  * Copyright 2003-2015,2017 by Thomas E. Dickey
      6  *
      7  *                         All Rights Reserved
      8  *
      9  * Permission is hereby granted, free of charge, to any person obtaining a
     10  * copy of this software and associated documentation files (the
     11  * "Software"), to deal in the Software without restriction, including
     12  * without limitation the rights to use, copy, modify, merge, publish,
     13  * distribute, sublicense, and/or sell copies of the Software, and to
     14  * permit persons to whom the Software is furnished to do so, subject to
     15  * the following conditions:
     16  *
     17  * The above copyright notice and this permission notice shall be included
     18  * in all copies or substantial portions of the Software.
     19  *
     20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     23  * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
     24  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     25  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     26  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     27  *
     28  * Except as contained in this notice, the name(s) of the above copyright
     29  * holders shall not be used in advertising or otherwise to promote the
     30  * sale, use or other dealings in this Software without prior written
     31  * authorization.
     32  *
     33  *
     34  * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
     35  *
     36  *                         All Rights Reserved
     37  *
     38  * Permission to use, copy, modify, and distribute this software and its
     39  * documentation for any purpose and without fee is hereby granted,
     40  * provided that the above copyright notice appear in all copies and that
     41  * both that copyright notice and this permission notice appear in
     42  * supporting documentation, and that the name of Digital Equipment
     43  * Corporation not be used in advertising or publicity pertaining to
     44  * distribution of the software without specific, written prior permission.
     45  *
     46  *
     47  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
     48  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
     49  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
     50  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
     51  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
     52  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     53  * SOFTWARE.
     54  */
     55 
     56 /*
     57  * Extracted version from Xterm tailored for NetBSD
     58  */
     59 /* resize.c */
     60 
     61 #include <stdio.h>
     62 #include <ctype.h>
     63 #include <stdlib.h>
     64 #include <sys/ioctl.h>
     65 #include <sys/time.h>
     66 #include <errno.h>
     67 #include <unistd.h>
     68 #include <strings.h>
     69 #include <libgen.h>
     70 #include <termios.h>
     71 #include "xstrings.h"
     72 
     73 
     74 /* imported from origional <xterm.h> */
     75 #define DFT_TERMTYPE "xterm"
     76 #define UIntClr(dst,bits) dst = dst & (unsigned) ~(bits)
     77 
     78 #include <signal.h>
     79 #include <pwd.h>
     80 
     81 #define ESCAPE(string) "\033" string
     82 
     83 #define	EMULATIONS	2
     84 #define	SUN		1
     85 #define	VT100		0
     86 
     87 #define	TIMEOUT		10
     88 
     89 #define	SHELL_UNKNOWN	0
     90 #define	SHELL_C		1
     91 #define	SHELL_BOURNE	2
     92 /* *INDENT-OFF* */
     93 static struct {
     94     const char *name;
     95     int type;
     96 } shell_list[] = {
     97     { "csh",	SHELL_C },	/* vanilla cshell */
     98     { "jcsh",   SHELL_C },
     99     { "tcsh",   SHELL_C },
    100     { "sh",	SHELL_BOURNE }, /* vanilla Bourne shell */
    101     { "ash",    SHELL_BOURNE },
    102     { "bash",	SHELL_BOURNE }, /* GNU Bourne again shell */
    103     { "dash",	SHELL_BOURNE },
    104     { "jsh",    SHELL_BOURNE },
    105     { "ksh",	SHELL_BOURNE }, /* Korn shell (from AT&T toolchest) */
    106     { "ksh-i",	SHELL_BOURNE }, /* another name for Korn shell */
    107     { "ksh93",	SHELL_BOURNE }, /* Korn shell */
    108     { "mksh",   SHELL_BOURNE },
    109     { "pdksh",  SHELL_BOURNE },
    110     { "zsh",    SHELL_BOURNE },
    111     { NULL,	SHELL_BOURNE }	/* default (same as xterm's) */
    112 };
    113 /* *INDENT-ON* */
    114 
    115 static const char *const emuname[EMULATIONS] =
    116 {
    117     "VT100",
    118     "Sun",
    119 };
    120 static char *myname;
    121 static int shell_type = SHELL_UNKNOWN;
    122 static const char *const getsize[EMULATIONS] =
    123 {
    124     ESCAPE("7") ESCAPE("[r") ESCAPE("[9999;9999H") ESCAPE("[6n"),
    125     ESCAPE("[18t"),
    126 };
    127 static const char *const restore[EMULATIONS] =
    128 {
    129     ESCAPE("8"),
    130     0,
    131 };
    132 static const char *const setsize[EMULATIONS] =
    133 {
    134     0,
    135     ESCAPE("[8;%s;%st"),
    136 };
    137 
    138 static struct termios tioorig;
    139 
    140 static const char *const size[EMULATIONS] =
    141 {
    142     ESCAPE("[%d;%dR"),
    143     ESCAPE("[8;%d;%dt"),
    144 };
    145 static const char sunname[] = "sunsize";
    146 static int tty;
    147 static FILE *ttyfp;
    148 
    149 
    150 static void
    151 failed(const char *s)
    152 {
    153     int save = errno;
    154     IGNORE_RC(write(2, myname, strlen(myname)));
    155     IGNORE_RC(write(2, ": ", (size_t) 2));
    156     errno = save;
    157     perror(s);
    158     exit(EXIT_FAILURE);
    159 }
    160 
    161 /* ARGSUSED */
    162 static void
    163 onintr(int sig GCC_UNUSED)
    164 {
    165     (void) tcsetattr(tty, TCSADRAIN, &tioorig);
    166     exit(EXIT_FAILURE);
    167 }
    168 
    169 static void
    170 resize_timeout(int sig)
    171 {
    172     fprintf(stderr, "\n%s: Time out occurred\r\n", myname);
    173     onintr(sig);
    174 }
    175 
    176 static void
    177 Usage(void)
    178 {
    179     fprintf(stderr, strcmp(myname, sunname) == 0 ?
    180 	    "Usage: %s [rows cols]\n" :
    181 	    "Usage: %s [-v] [-u] [-c] [-s [rows cols]]\n", myname);
    182     exit(EXIT_FAILURE);
    183 }
    184 
    185 
    186 static int
    187 checkdigits(char *str)
    188 {
    189     while (*str) {
    190 	if (!isdigit(CharOf(*str)))
    191 	    return (0);
    192 	str++;
    193     }
    194     return (1);
    195 }
    196 
    197 static void
    198 readstring(FILE *fp, char *buf, const char *str)
    199 {
    200     int last, c;
    201     struct itimerval it;
    202 
    203     signal(SIGALRM, resize_timeout);
    204     memset((char *) &it, 0, sizeof(struct itimerval));
    205     it.it_value.tv_sec = TIMEOUT;
    206     setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL);
    207     if ((c = getc(fp)) == 0233) {	/* meta-escape, CSI */
    208 	c = ESCAPE("")[0];
    209 	*buf++ = (char) c;
    210 	*buf++ = '[';
    211     } else {
    212 	*buf++ = (char) c;
    213     }
    214     if (c != *str) {
    215 	fprintf(stderr, "%s: unknown character, exiting.\r\n", myname);
    216 	onintr(0);
    217     }
    218     last = str[strlen(str) - 1];
    219     while ((*buf++ = (char) getc(fp)) != last) {
    220 	;
    221     }
    222     memset((char *) &it, 0, sizeof(struct itimerval));
    223     setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL);
    224     *buf = 0;
    225 }
    226 
    227 /*
    228    resets termcap string to reflect current screen size
    229  */
    230 int
    231 main(int argc, char **argv ENVP_ARG)
    232 {
    233     char *ptr;
    234     int emu = VT100;
    235     char *shell;
    236     int i;
    237     int rc;
    238     int rows, cols;
    239     struct termios tio;
    240     char buf[BUFSIZ];
    241     char *name_of_tty;
    242     const char *setname = "";
    243 
    244     myname = x_basename(argv[0]);
    245     if (strcmp(myname, sunname) == 0)
    246 	emu = SUN;
    247     for (argv++, argc--; argc > 0 && **argv == '-'; argv++, argc--) {
    248 	switch ((*argv)[1]) {
    249 	case 's':		/* Sun emulation */
    250 	    if (emu == SUN)
    251 		Usage();	/* Never returns */
    252 	    emu = SUN;
    253 	    break;
    254 	case 'u':		/* Bourne (Unix) shell */
    255 	    shell_type = SHELL_BOURNE;
    256 	    break;
    257 	case 'c':		/* C shell */
    258 	    shell_type = SHELL_C;
    259 	    break;
    260 	case 'v':
    261 	    printf("Xterm(330)\n");
    262 	    exit(EXIT_SUCCESS);
    263 	default:
    264 	    Usage();		/* Never returns */
    265 	}
    266     }
    267 
    268     if (SHELL_UNKNOWN == shell_type) {
    269 	/* Find out what kind of shell this user is running.
    270 	 * This is the same algorithm that xterm uses.
    271 	 */
    272 	if ((ptr = x_getenv("SHELL")) == NULL) {
    273 	    uid_t uid = getuid();
    274 	    struct passwd pw;
    275 
    276 	    if (x_getpwuid(uid, &pw)) {
    277 		(void) x_getlogin(uid, &pw);
    278 	    }
    279 	    if (!OkPasswd(&pw)
    280 		|| *(ptr = pw.pw_shell) == 0) {
    281 		/* this is the same default that xterm uses */
    282 		ptr = x_strdup("/bin/sh");
    283 	    }
    284 	}
    285 
    286 	shell = x_basename(ptr);
    287 
    288 	/* now that we know, what kind is it? */
    289 	for (i = 0; shell_list[i].name; i++) {
    290 	    if (!strcmp(shell_list[i].name, shell)) {
    291 		break;
    292 	    }
    293 	}
    294 	shell_type = shell_list[i].type;
    295     }
    296 
    297     if (argc == 2) {
    298 	if (!setsize[emu]) {
    299 	    fprintf(stderr,
    300 		    "%s: Can't set window size under %s emulation\n",
    301 		    myname, emuname[emu]);
    302 	    exit(EXIT_FAILURE);
    303 	}
    304 	if (!checkdigits(argv[0]) || !checkdigits(argv[1])) {
    305 	    Usage();		/* Never returns */
    306 	}
    307     } else if (argc != 0) {
    308 	Usage();		/* Never returns */
    309     }
    310 	name_of_tty = x_strdup("/dev/tty");
    311 
    312     if ((ttyfp = fopen(name_of_tty, "r+")) == NULL) {
    313 	fprintf(stderr, "%s:  can't open terminal %s\n",
    314 		myname, name_of_tty);
    315 	exit(EXIT_FAILURE);
    316     }
    317     tty = fileno(ttyfp);
    318     if (x_getenv("TERM") == 0) {
    319 	if (SHELL_BOURNE == shell_type) {
    320 	    setname = "TERM=" DFT_TERMTYPE ";\nexport TERM;\n";
    321 	} else {
    322 	    setname = "setenv TERM " DFT_TERMTYPE ";\n";
    323 	}
    324     }
    325 
    326     rc = tcgetattr(tty, &tioorig);
    327     tio = tioorig;
    328     UIntClr(tio.c_iflag, ICRNL);
    329     UIntClr(tio.c_lflag, (ICANON | ECHO));
    330     tio.c_cflag |= CS8;
    331     tio.c_cc[VMIN] = 6;
    332     tio.c_cc[VTIME] = 1;
    333     if (rc != 0)
    334 	failed("get tty settings");
    335 
    336     signal(SIGINT, onintr);
    337     signal(SIGQUIT, onintr);
    338     signal(SIGTERM, onintr);
    339 
    340     rc = tcsetattr(tty, TCSADRAIN, &tio);
    341     if (rc != 0)
    342 	failed("set tty settings");
    343 
    344     if (argc == 2) {		/* look for optional parameters of "-s" */
    345 	char *tmpbuf = TypeMallocN(char,
    346 				   strlen(setsize[emu]) +
    347 				   strlen(argv[0]) +
    348 				   strlen(argv[1]) +
    349 				   1);
    350 	if (tmpbuf == 0) {
    351 	    fprintf(stderr, "%s: Cannot query size\n", myname);
    352 	    onintr(0);
    353 	} else {
    354 	    sprintf(tmpbuf, setsize[emu], argv[0], argv[1]);
    355 	    IGNORE_RC(write(tty, tmpbuf, strlen(tmpbuf)));
    356 	    free(tmpbuf);
    357 	}
    358     }
    359     IGNORE_RC(write(tty, getsize[emu], strlen(getsize[emu])));
    360     readstring(ttyfp, buf, size[emu]);
    361     if (sscanf(buf, size[emu], &rows, &cols) != 2) {
    362 	fprintf(stderr, "%s: Can't get rows and columns\r\n", myname);
    363 	onintr(0);
    364     }
    365     if (restore[emu])
    366 	IGNORE_RC(write(tty, restore[emu], strlen(restore[emu])));
    367 
    368     rc = tcsetattr(tty, TCSADRAIN, &tioorig);
    369     if (rc != 0)
    370 	failed("set tty settings");
    371 
    372     signal(SIGINT, SIG_DFL);
    373     signal(SIGQUIT, SIG_DFL);
    374     signal(SIGTERM, SIG_DFL);
    375 
    376 
    377     if (SHELL_BOURNE == shell_type) {
    378 
    379 	printf("%sCOLUMNS=%d;\nLINES=%d;\nexport COLUMNS LINES;\n",
    380 	       setname, cols, rows);
    381 
    382     } else {			/* not Bourne shell */
    383 
    384 	printf("set noglob;\n%ssetenv COLUMNS '%d';\nsetenv LINES '%d';\nunset noglob;\n",
    385 	       setname, cols, rows);
    386     }
    387     exit(EXIT_SUCCESS);
    388 }
    389