root/foundation-apps/mxterm-maxx/resize.c

Revision 8, 15.1 KB (checked in by emasson, 3 years ago)

initial import for the community edition

Line 
1/* $XTermId: resize.c,v 1.106 2007/12/31 21:10:07 tom Exp $ */
2
3/*
4 * Copyright 2003-2006,2007 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 <xterm.h>
58#include <stdio.h>
59#include <ctype.h>
60#include <xstrings.h>
61#include <xtermcap.h>
62#include <xterm_io.h>
63
64#ifdef APOLLO_SR9
65#define CANT_OPEN_DEV_TTY
66#endif
67
68#ifndef USE_TERMINFO            /* avoid conflict with configure script */
69#if defined(__QNX__) || defined(__SCO__) || defined(linux) || defined(__OpenBSD__) || defined(__UNIXWARE__)
70#define USE_TERMINFO
71#endif
72#endif
73
74#if defined(__QNX__)
75#include <unix.h>
76#endif
77
78/*
79 * Some OS's may want to use both, like SCO for example.  We catch here anyone
80 * who hasn't decided what they want.
81 */
82#if !defined(USE_TERMCAP) && !defined(USE_TERMINFO)
83#define USE_TERMINFO
84#endif
85
86#include <signal.h>
87#include <pwd.h>
88
89#ifdef X_NOT_POSIX
90#if !defined(SYSV) && !defined(i386)
91extern struct passwd *getpwuid();       /* does ANYBODY need this? */
92#endif /* SYSV && i386 */
93#endif /* X_NOT_POSIX */
94
95#ifndef bzero
96#define bzero(s, n)     memset(s, 0, n)
97#endif
98
99#ifdef __MVS__
100#define ESCAPE(string) "\047" string
101#else
102#define ESCAPE(string) "\033" string
103#endif
104
105#define EMULATIONS      2
106#define SUN             1
107#define VT100           0
108
109#define TIMEOUT         10
110
111#define SHELL_UNKNOWN   0
112#define SHELL_C         1
113#define SHELL_BOURNE    2
114/* *INDENT-OFF* */
115static struct {
116    char *name;
117    int type;
118} shell_list[] = {
119    { "csh",    SHELL_C },      /* vanilla cshell */
120    { "tcsh",   SHELL_C },
121    { "jcsh",   SHELL_C },
122    { "sh",     SHELL_BOURNE }, /* vanilla Bourne shell */
123    { "ksh",    SHELL_BOURNE }, /* Korn shell (from AT&T toolchest) */
124    { "ksh-i",  SHELL_BOURNE }, /* other name for latest Korn shell */
125    { "bash",   SHELL_BOURNE }, /* GNU Bourne again shell */
126    { "jsh",    SHELL_BOURNE },
127    { NULL,     SHELL_BOURNE }  /* default (same as xterm's) */
128};
129/* *INDENT-ON* */
130
131static char *emuname[EMULATIONS] =
132{
133    "VT100",
134    "Sun",
135};
136static char *myname;
137static int shell_type = SHELL_UNKNOWN;
138static char *getsize[EMULATIONS] =
139{
140    ESCAPE("7") ESCAPE("[r") ESCAPE("[999;999H") ESCAPE("[6n"),
141    ESCAPE("[18t"),
142};
143#if defined(USE_STRUCT_TTYSIZE)
144#elif defined(USE_STRUCT_WINSIZE)
145static char *getwsize[EMULATIONS] =
146{                               /* size in pixels */
147    0,
148    ESCAPE("[14t"),
149};
150#endif /* USE_STRUCT_{TTYSIZE|WINSIZE} */
151static char *restore[EMULATIONS] =
152{
153    ESCAPE("8"),
154    0,
155};
156static char *setname = "";
157static char *setsize[EMULATIONS] =
158{
159    0,
160    ESCAPE("[8;%s;%st"),
161};
162
163#ifdef USE_ANY_SYSV_TERMIO
164static struct termio tioorig;
165#elif defined(USE_TERMIOS)
166static struct termios tioorig;
167#else
168static struct sgttyb sgorig;
169#endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
170
171static char *size[EMULATIONS] =
172{
173    ESCAPE("[%d;%dR"),
174    ESCAPE("[8;%d;%dt"),
175};
176static char sunname[] = "sunsize";
177static int tty;
178static FILE *ttyfp;
179
180#if defined(USE_STRUCT_TTYSIZE)
181#elif defined(USE_STRUCT_WINSIZE)
182static char *wsize[EMULATIONS] =
183{
184    0,
185    ESCAPE("[4;%hd;%hdt"),
186};
187#endif /* USE_STRUCT_{TTYSIZE|WINSIZE} */
188
189static SIGNAL_T onintr(int sig);
190static SIGNAL_T resize_timeout(int sig);
191static int checkdigits(char *str);
192static void Usage(void);
193static void readstring(FILE *fp, char *buf, char *str);
194
195#ifdef USE_TERMCAP
196static void
197print_termcap(const char *termcap)
198{
199    int ch;
200
201    putchar('\'');
202    while ((ch = *termcap++) != '\0') {
203        switch (ch & 0xff) {
204        case 127:               /* undo bug in GNU termcap */
205            printf("^?");
206            break;
207        case '\'':              /* must escape anyway (unlikely) */
208            /* FALLTHRU */
209        case '!':               /* must escape for SunOS csh */
210            putchar('\\');
211            /* FALLTHRU */
212        default:
213            putchar(ch);
214            break;
215        }
216    }
217    putchar('\'');
218}
219#endif /* USE_TERMCAP */
220
221/*
222   resets termcap string to reflect current screen size
223 */
224int
225main(int argc, char **argv ENVP_ARG)
226{
227#ifdef USE_TERMCAP
228    register char *env;
229#endif
230    register char *ptr;
231    register int emu = VT100;
232    char *shell;
233    struct passwd *pw;
234    int i;
235    int rows, cols;
236#ifdef USE_ANY_SYSV_TERMIO
237    struct termio tio;
238#elif defined(USE_TERMIOS)
239    struct termios tio;
240#else
241    struct sgttyb sg;
242#endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
243#ifdef USE_TERMCAP
244    int ok_tcap = 1;
245    char termcap[TERMCAP_SIZE];
246    char newtc[TERMCAP_SIZE];
247#endif /* USE_TERMCAP */
248    char buf[BUFSIZ];
249#ifdef TTYSIZE_STRUCT
250    TTYSIZE_STRUCT ts;
251#endif
252    char *name_of_tty;
253#ifdef CANT_OPEN_DEV_TTY
254    extern char *ttyname();
255#endif
256
257    myname = x_basename(argv[0]);
258    if (strcmp(myname, sunname) == 0)
259        emu = SUN;
260    for (argv++, argc--; argc > 0 && **argv == '-'; argv++, argc--) {
261        switch ((*argv)[1]) {
262        case 's':               /* Sun emulation */
263            if (emu == SUN)
264                Usage();        /* Never returns */
265            emu = SUN;
266            break;
267        case 'u':               /* Bourne (Unix) shell */
268            shell_type = SHELL_BOURNE;
269            break;
270        case 'c':               /* C shell */
271            shell_type = SHELL_C;
272            break;
273        default:
274            Usage();            /* Never returns */
275        }
276    }
277
278    if (SHELL_UNKNOWN == shell_type) {
279        /* Find out what kind of shell this user is running.
280         * This is the same algorithm that xterm uses.
281         */
282        if (((ptr = x_getenv("SHELL")) == NULL) &&
283            (((pw = getpwuid(getuid())) == NULL) ||
284             *(ptr = pw->pw_shell) == 0))
285            /* this is the same default that xterm uses */
286            ptr = "/bin/sh";
287
288        shell = x_basename(ptr);
289
290        /* now that we know, what kind is it? */
291        for (i = 0; shell_list[i].name; i++)
292            if (!strcmp(shell_list[i].name, shell))
293                break;
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(1);
303        }
304        if (!checkdigits(argv[0]) || !checkdigits(argv[1]))
305            Usage();            /* Never returns */
306    } else if (argc != 0)
307        Usage();                /* Never returns */
308
309#ifdef CANT_OPEN_DEV_TTY
310    if ((name_of_tty = ttyname(fileno(stderr))) == NULL)
311#endif
312        name_of_tty = "/dev/tty";
313
314    if ((ttyfp = fopen(name_of_tty, "r+")) == NULL) {
315        fprintf(stderr, "%s:  can't open terminal %s\n",
316                myname, name_of_tty);
317        exit(1);
318    }
319    tty = fileno(ttyfp);
320#ifdef USE_TERMCAP
321    if ((env = x_getenv("TERM")) == 0) {
322        env = DFT_TERMTYPE;
323        if (SHELL_BOURNE == shell_type)
324            setname = "TERM=" DFT_TERMTYPE ";\nexport TERM;\n";
325        else
326            setname = "setenv TERM " DFT_TERMTYPE ";\n";
327    }
328    termcap[0] = 0;             /* ...just in case we've accidentally gotten terminfo */
329    if (tgetent(termcap, env) <= 0 || termcap[0] == 0)
330        ok_tcap = 0;
331#endif /* USE_TERMCAP */
332#ifdef USE_TERMINFO
333    if (x_getenv("TERM") == 0) {
334        if (SHELL_BOURNE == shell_type)
335            setname = "TERM=" DFT_TERMTYPE ";\nexport TERM;\n";
336        else
337            setname = "setenv TERM " DFT_TERMTYPE ";\n";
338    }
339#endif /* USE_TERMINFO */
340
341#ifdef USE_ANY_SYSV_TERMIO
342    ioctl(tty, TCGETA, &tioorig);
343    tio = tioorig;
344    tio.c_iflag &= ~(ICRNL | IUCLC);
345    tio.c_lflag &= ~(ICANON | ECHO);
346    tio.c_cflag |= CS8;
347    tio.c_cc[VMIN] = 6;
348    tio.c_cc[VTIME] = 1;
349#elif defined(USE_TERMIOS)
350    tcgetattr(tty, &tioorig);
351    tio = tioorig;
352    tio.c_iflag &= ~ICRNL;
353    tio.c_lflag &= ~(ICANON | ECHO);
354    tio.c_cflag |= CS8;
355    tio.c_cc[VMIN] = 6;
356    tio.c_cc[VTIME] = 1;
357#else /* not USE_TERMIOS */
358    ioctl(tty, TIOCGETP, &sgorig);
359    sg = sgorig;
360    sg.sg_flags |= RAW;
361    sg.sg_flags &= ~ECHO;
362#endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
363    signal(SIGINT, onintr);
364    signal(SIGQUIT, onintr);
365    signal(SIGTERM, onintr);
366#ifdef USE_ANY_SYSV_TERMIO
367    ioctl(tty, TCSETAW, &tio);
368#elif defined(USE_TERMIOS)
369    tcsetattr(tty, TCSADRAIN, &tio);
370#else /* not USE_TERMIOS */
371    ioctl(tty, TIOCSETP, &sg);
372#endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
373
374    if (argc == 2) {
375        char *tmpbuf = TypeMallocN(char,
376                                   strlen(setsize[emu]) +
377                                   strlen(argv[0]) +
378                                   strlen(argv[1]) +
379                                   1);
380        if (tmpbuf == 0) {
381            fprintf(stderr, "%s: Cannot query size\n", myname);
382            onintr(0);
383        }
384        sprintf(tmpbuf, setsize[emu], argv[0], argv[1]);
385        write(tty, tmpbuf, strlen(tmpbuf));
386        free(tmpbuf);
387    }
388    write(tty, getsize[emu], strlen(getsize[emu]));
389    readstring(ttyfp, buf, size[emu]);
390    if (sscanf(buf, size[emu], &rows, &cols) != 2) {
391        fprintf(stderr, "%s: Can't get rows and columns\r\n", myname);
392        onintr(0);
393    }
394    if (restore[emu])
395        write(tty, restore[emu], strlen(restore[emu]));
396#if defined(USE_STRUCT_TTYSIZE)
397    /* finally, set the tty's window size */
398    if (ioctl(tty, TIOCGSIZE, &ts) != -1) {
399        TTYSIZE_ROWS(ts) = rows;
400        TTYSIZE_COLS(ts) = cols;
401        SET_TTYSIZE(tty, ts);
402    }
403#elif defined(USE_STRUCT_WINSIZE)
404    /* finally, set the tty's window size */
405    if (getwsize[emu]) {
406        /* get the window size in pixels */
407        write(tty, getwsize[emu], strlen(getwsize[emu]));
408        readstring(ttyfp, buf, wsize[emu]);
409        if (sscanf(buf, wsize[emu], &ts.ws_xpixel, &ts.ws_ypixel) != 2) {
410            fprintf(stderr, "%s: Can't get window size\r\n", myname);
411            onintr(0);
412        }
413        TTYSIZE_ROWS(ts) = rows;
414        TTYSIZE_COLS(ts) = cols;
415        SET_TTYSIZE(tty, ts);
416    } else if (ioctl(tty, TIOCGWINSZ, &ts) != -1) {
417        /* we don't have any way of directly finding out
418           the current height & width of the window in pixels.  We try
419           our best by computing the font height and width from the "old"
420           window-size values, and multiplying by these ratios... */
421        if (TTYSIZE_COLS(ts) != 0)
422            ts.ws_xpixel = cols * (ts.ws_xpixel / TTYSIZE_COLS(ts));
423        if (TTYSIZE_ROWS(ts) != 0)
424            ts.ws_ypixel = rows * (ts.ws_ypixel / TTYSIZE_ROWS(ts));
425        TTYSIZE_ROWS(ts) = rows;
426        TTYSIZE_COLS(ts) = cols;
427        SET_TTYSIZE(tty, ts);
428    }
429#endif /* USE_STRUCT_{TTYSIZE|WINSIZE} */
430
431#ifdef USE_ANY_SYSV_TERMIO
432    ioctl(tty, TCSETAW, &tioorig);
433#elif defined(USE_TERMIOS)
434    tcsetattr(tty, TCSADRAIN, &tioorig);
435#else /* not USE_TERMIOS */
436    ioctl(tty, TIOCSETP, &sgorig);
437#endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
438    signal(SIGINT, SIG_DFL);
439    signal(SIGQUIT, SIG_DFL);
440    signal(SIGTERM, SIG_DFL);
441
442#ifdef USE_TERMCAP
443    if (ok_tcap) {
444        /* update termcap string */
445        /* first do columns */
446        if ((ptr = x_strindex(termcap, "co#")) == NULL) {
447            fprintf(stderr, "%s: No `co#'\n", myname);
448            exit(1);
449        }
450
451        i = ptr - termcap + 3;
452        strncpy(newtc, termcap, (unsigned) i);
453        sprintf(newtc + i, "%d", cols);
454        ptr = strchr(ptr, ':');
455        strcat(newtc, ptr);
456
457        /* now do lines */
458        if ((ptr = x_strindex(newtc, "li#")) == NULL) {
459            fprintf(stderr, "%s: No `li#'\n", myname);
460            exit(1);
461        }
462
463        i = ptr - newtc + 3;
464        strncpy(termcap, newtc, (unsigned) i);
465        sprintf(termcap + i, "%d", rows);
466        ptr = strchr(ptr, ':');
467        strcat(termcap, ptr);
468    }
469#endif /* USE_TERMCAP */
470
471    if (SHELL_BOURNE == shell_type) {
472
473#ifdef USE_TERMCAP
474        if (ok_tcap) {
475            printf("%sTERMCAP=", setname);
476            print_termcap(termcap);
477            printf(";\nexport TERMCAP;\n");
478        }
479#endif /* USE_TERMCAP */
480#ifdef USE_TERMINFO
481        printf("%sCOLUMNS=%d;\nLINES=%d;\nexport COLUMNS LINES;\n",
482               setname, cols, rows);
483#endif /* USE_TERMINFO */
484
485    } else {                    /* not Bourne shell */
486
487#ifdef USE_TERMCAP
488        if (ok_tcap) {
489            printf("set noglob;\n%ssetenv TERMCAP ", setname);
490            print_termcap(termcap);
491            printf(";\nunset noglob;\n");
492        }
493#endif /* USE_TERMCAP */
494#ifdef USE_TERMINFO
495        printf("set noglob;\n%ssetenv COLUMNS '%d';\nsetenv LINES '%d';\nunset noglob;\n",
496               setname, cols, rows);
497#endif /* USE_TERMINFO */
498    }
499    exit(0);
500}
501
502static int
503checkdigits(register char *str)
504{
505    while (*str) {
506        if (!isdigit(CharOf(*str)))
507            return (0);
508        str++;
509    }
510    return (1);
511}
512
513static void
514readstring(register FILE *fp, register char *buf, char *str)
515{
516    register int last, c;
517#if !defined(USG) && !defined(__UNIXOS2__)
518    /* What is the advantage of setitimer() over alarm()? */
519    struct itimerval it;
520#endif
521
522    signal(SIGALRM, resize_timeout);
523#if defined(USG) || defined(__UNIXOS2__)
524    alarm(TIMEOUT);
525#else
526    bzero((char *) &it, sizeof(struct itimerval));
527    it.it_value.tv_sec = TIMEOUT;
528    setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL);
529#endif
530    if ((c = getc(fp)) == 0233) {       /* meta-escape, CSI */
531        *buf++ = c = ESCAPE("")[0];
532        *buf++ = '[';
533    } else {
534        *buf++ = c;
535    }
536    if (c != *str) {
537        fprintf(stderr, "%s: unknown character, exiting.\r\n", myname);
538        onintr(0);
539    }
540    last = str[strlen(str) - 1];
541    while ((*buf++ = getc(fp)) != last) ;
542#if defined(USG) || defined(__UNIXOS2__)
543    alarm(0);
544#else
545    bzero((char *) &it, sizeof(struct itimerval));
546    setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL);
547#endif
548    *buf = 0;
549}
550
551static void
552Usage(void)
553{
554    fprintf(stderr, strcmp(myname, sunname) == 0 ?
555            "Usage: %s [rows cols]\n" :
556            "Usage: %s [-u] [-c] [-s [rows cols]]\n", myname);
557    exit(1);
558}
559
560static SIGNAL_T
561resize_timeout(int sig)
562{
563    fprintf(stderr, "\n%s: Time out occurred\r\n", myname);
564    onintr(sig);
565}
566
567/* ARGSUSED */
568static SIGNAL_T
569onintr(int sig GCC_UNUSED)
570{
571#ifdef USE_ANY_SYSV_TERMIO
572    ioctl(tty, TCSETAW, &tioorig);
573#elif defined(USE_TERMIOS)
574    tcsetattr(tty, TCSADRAIN, &tioorig);
575#else /* not USE_TERMIOS */
576    ioctl(tty, TIOCSETP, &sgorig);
577#endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
578    exit(1);
579}
Note: See TracBrowser for help on using the browser.