"Fossies" - the Fresh Open Source Software Archive 
Member "xterm-379/resize.c" (26 Jan 2023, 16700 Bytes) of package /linux/misc/xterm-379.tgz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "resize.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
377_vs_379.
1 /* $XTermId: resize.c,v 1.149 2023/01/26 00:43:18 tom Exp $ */
2
3 /*
4 * Copyright 2003-2022,2023 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 #include <xterm.h>
61 #include <version.h>
62 #include <xstrings.h>
63 #include <xtermcap.h>
64 #include <xterm_io.h>
65
66 #ifndef USE_TERMINFO /* avoid conflict with configure script */
67 #if defined(__QNX__) || defined(__SCO__) || defined(linux) || defined(__OpenBSD__) || defined(__UNIXWARE__)
68 #define USE_TERMINFO
69 #endif
70 #endif
71
72 #if defined(__QNX__)
73 #include <unix.h>
74 #endif
75
76 /*
77 * Some OS's may want to use both, like SCO for example. We catch here anyone
78 * who hasn't decided what they want.
79 */
80 #if !defined(USE_TERMCAP) && !defined(USE_TERMINFO)
81 #define USE_TERMINFO
82 #endif
83
84 #include <signal.h>
85 #include <pwd.h>
86
87 #ifdef USE_IGNORE_RC
88 int ignore_unused;
89 #endif
90
91 #ifdef __MVS__
92 #define ESCAPE(string) "\047" string
93 #else
94 #define ESCAPE(string) "\033" string
95 #endif
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 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 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 0,
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, "%s: unknown character %#x, exiting.\r\n", myname, c);
283 onintr(0);
284 }
285
286 static void
287 readstring(FILE *fp, char *buf, const char *str)
288 {
289 int last, c;
290 #if HAVE_SETITIMER
291 struct itimerval it;
292 #endif
293 int limit = (BUFSIZ - 3);
294
295 signal(SIGALRM, resize_timeout);
296 #if HAVE_SETITIMER
297 memset((char *) &it, 0, sizeof(struct itimerval));
298 it.it_value.tv_sec = TIMEOUT;
299 setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL);
300 #else
301 alarm(TIMEOUT);
302 #endif
303 if ((c = getc(fp)) == 0233) { /* meta-escape, CSI */
304 c = ESCAPE("")[0];
305 *buf++ = (char) c;
306 *buf++ = '[';
307 } else {
308 *buf++ = (char) c;
309 }
310 if (c != *str) {
311 unexpected_char(c);
312 }
313 last = str[strlen(str) - 1];
314 while ((c = getc(fp)) != EOF) {
315 if (--limit <= 0) {
316 fprintf(stderr, "%s: unexpected response\n", myname);
317 onintr(0);
318 }
319 if (c < 32 || c > 126) {
320 unexpected_char(c);
321 }
322 *buf++ = (char) c;
323 if (c == last)
324 break;
325 }
326 #if HAVE_SETITIMER
327 memset((char *) &it, 0, sizeof(struct itimerval));
328 setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL);
329 #else
330 alarm(0);
331 #endif
332 *buf = 0;
333 }
334
335 /*
336 resets termcap string to reflect current screen size
337 */
338 int
339 main(int argc, char **argv ENVP_ARG)
340 {
341 #ifdef USE_TERMCAP
342 char *env;
343 #endif
344 char *ptr;
345 int emu = VT100;
346 char *shell;
347 int i;
348 int rc;
349 int rows, cols;
350 #ifdef USE_ANY_SYSV_TERMIO
351 struct termio tio;
352 #elif defined(USE_TERMIOS)
353 struct termios tio;
354 #else
355 struct sgttyb sg;
356 #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
357 #ifdef USE_TERMCAP
358 int ok_tcap = 1;
359 char termcap[TERMCAP_SIZE];
360 char newtc[TERMCAP_SIZE];
361 #endif /* USE_TERMCAP */
362 char buf[BUFSIZ];
363 #ifdef TTYSIZE_STRUCT
364 TTYSIZE_STRUCT ts;
365 #endif
366 char *name_of_tty;
367 #ifdef CANT_OPEN_DEV_TTY
368 extern char *ttyname();
369 #endif
370 const char *setname = "";
371
372 myname = x_basename(argv[0]);
373 if (strcmp(myname, sunname) == 0)
374 emu = SUN;
375 for (argv++, argc--; argc > 0 && **argv == '-'; argv++, argc--) {
376 switch ((*argv)[1]) {
377 case 's': /* Sun emulation */
378 if (emu == SUN)
379 Usage(); /* Never returns */
380 emu = SUN;
381 break;
382 case 'u': /* Bourne (Unix) shell */
383 shell_type = SHELL_BOURNE;
384 break;
385 case 'c': /* C shell */
386 shell_type = SHELL_C;
387 break;
388 case 'v':
389 printf("%s\n", xtermVersion());
390 exit(EXIT_SUCCESS);
391 default:
392 Usage(); /* Never returns */
393 }
394 }
395
396 if (SHELL_UNKNOWN == shell_type) {
397 /* Find out what kind of shell this user is running.
398 * This is the same algorithm that xterm uses.
399 */
400 if ((ptr = x_getenv("SHELL")) == NULL) {
401 uid_t uid = getuid();
402 struct passwd pw;
403
404 if (x_getpwuid(uid, &pw)) {
405 (void) x_getlogin(uid, &pw);
406 }
407 if (!OkPasswd(&pw)
408 || *(ptr = pw.pw_shell) == 0) {
409 /* this is the same default that xterm uses */
410 ptr = x_strdup("/bin/sh");
411 }
412 }
413
414 shell = x_basename(ptr);
415
416 /* now that we know, what kind is it? */
417 for (i = 0; shell_list[i].name; i++) {
418 if (!strcmp(shell_list[i].name, shell)) {
419 break;
420 }
421 }
422 shell_type = shell_list[i].type;
423 }
424
425 if (argc == 2) {
426 if (!setsize[emu]) {
427 fprintf(stderr,
428 "%s: Can't set window size under %s emulation\n",
429 myname, emuname[emu]);
430 exit(EXIT_FAILURE);
431 }
432 if (!checkdigits(argv[0]) || !checkdigits(argv[1])) {
433 Usage(); /* Never returns */
434 }
435 } else if (argc != 0) {
436 Usage(); /* Never returns */
437 }
438 #ifdef CANT_OPEN_DEV_TTY
439 if ((name_of_tty = ttyname(fileno(stderr))) == NULL)
440 #endif
441 name_of_tty = x_strdup("/dev/tty");
442
443 if ((ttyfp = fopen(name_of_tty, "r+")) == NULL) {
444 fprintf(stderr, "%s: can't open terminal %s\n",
445 myname, name_of_tty);
446 exit(EXIT_FAILURE);
447 }
448 tty = fileno(ttyfp);
449 #ifdef USE_TERMCAP
450 if ((env = x_getenv("TERM")) == 0) {
451 env = x_strdup(DFT_TERMTYPE);
452 if (SHELL_BOURNE == shell_type) {
453 setname = "TERM=" DFT_TERMTYPE ";\nexport TERM;\n";
454 } else {
455 setname = "setenv TERM " DFT_TERMTYPE ";\n";
456 }
457 }
458 termcap[0] = 0; /* ...just in case we've accidentally gotten terminfo */
459 if (tgetent(termcap, env) <= 0 || termcap[0] == 0) {
460 ok_tcap = 0;
461 }
462 #endif /* USE_TERMCAP */
463 #ifdef USE_TERMINFO
464 if (x_getenv("TERM") == 0) {
465 if (SHELL_BOURNE == shell_type) {
466 setname = "TERM=" DFT_TERMTYPE ";\nexport TERM;\n";
467 } else {
468 setname = "setenv TERM " DFT_TERMTYPE ";\n";
469 }
470 }
471 #endif /* USE_TERMINFO */
472
473 #ifdef USE_ANY_SYSV_TERMIO
474 rc = ioctl(tty, TCGETA, &tioorig);
475 tio = tioorig;
476 UIntClr(tio.c_iflag, (ICRNL | IUCLC));
477 UIntClr(tio.c_lflag, (ICANON | ECHO));
478 tio.c_cflag |= CS8;
479 tio.c_cc[VMIN] = 6;
480 tio.c_cc[VTIME] = 1;
481 #elif defined(USE_TERMIOS)
482 rc = tcgetattr(tty, &tioorig);
483 tio = tioorig;
484 UIntClr(tio.c_iflag, ICRNL);
485 UIntClr(tio.c_lflag, (ICANON | ECHO));
486 tio.c_cflag |= CS8;
487 tio.c_cc[VMIN] = 6;
488 tio.c_cc[VTIME] = 1;
489 #else /* not USE_TERMIOS */
490 rc = ioctl(tty, TIOCGETP, &sgorig);
491 sg = sgorig;
492 sg.sg_flags |= RAW;
493 UIntClr(sg.sg_flags, ECHO);
494 #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
495 if (rc != 0)
496 failed("get tty settings");
497
498 signal(SIGINT, onintr);
499 signal(SIGQUIT, onintr);
500 signal(SIGTERM, onintr);
501
502 #ifdef USE_ANY_SYSV_TERMIO
503 rc = ioctl(tty, TCSETAW, &tio);
504 #elif defined(USE_TERMIOS)
505 rc = tcsetattr(tty, TCSADRAIN, &tio);
506 #else /* not USE_TERMIOS */
507 rc = ioctl(tty, TIOCSETP, &sg);
508 #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
509 if (rc != 0)
510 failed("set tty settings");
511
512 if (argc == 2) { /* look for optional parameters of "-s" */
513 char *tmpbuf = TypeMallocN(char,
514 strlen(setsize[emu]) +
515 strlen(argv[0]) +
516 strlen(argv[1]) +
517 1);
518 if (tmpbuf == 0) {
519 fprintf(stderr, "%s: Cannot query size\n", myname);
520 onintr(0);
521 } else {
522 sprintf(tmpbuf, setsize[emu], argv[0], argv[1]);
523 IGNORE_RC(write(tty, tmpbuf, strlen(tmpbuf)));
524 free(tmpbuf);
525 }
526 }
527 if (getattr[emu]) {
528 timeout_message = "Terminal is not VT100-compatible";
529 IGNORE_RC(write(tty, getattr[emu], strlen(getattr[emu])));
530 readstring(ttyfp, buf, reply_attr[emu]);
531 }
532 timeout_message = "Time out occurred";
533 IGNORE_RC(write(tty, getsize[emu], strlen(getsize[emu])));
534 readstring(ttyfp, buf, reply_size[emu]);
535 if (sscanf(buf, reply_size[emu], &rows, &cols) != 2) {
536 fprintf(stderr, "%s: Can't get rows and columns\r\n", myname);
537 onintr(0);
538 }
539 if (restore[emu])
540 IGNORE_RC(write(tty, restore[emu], strlen(restore[emu])));
541 #if defined(USE_STRUCT_WINSIZE)
542 /* finally, set the tty's window size */
543 if (getwsize[emu]) {
544 /* get the window size in pixels */
545 IGNORE_RC(write(tty, getwsize[emu], strlen(getwsize[emu])));
546 readstring(ttyfp, buf, wsize[emu]);
547 if (sscanf(buf, wsize[emu], &ts.ws_xpixel, &ts.ws_ypixel) != 2) {
548 fprintf(stderr, "%s: Can't get window size\r\n", myname);
549 onintr(0);
550 }
551 setup_winsize(ts, rows, cols, 0, 0);
552 SET_TTYSIZE(tty, ts);
553 } else if (ioctl(tty, TIOCGWINSZ, &ts) != -1) {
554 /* we don't have any way of directly finding out
555 the current height & width of the window in pixels. We try
556 our best by computing the font height and width from the "old"
557 window-size values, and multiplying by these ratios... */
558 #define scaled(old,new,len) (old)?((unsigned)(new)*(len)/(old)):(len)
559 setup_winsize(ts, rows, cols,
560 scaled(TTYSIZE_ROWS(ts), rows, ts.ws_ypixel),
561 scaled(TTYSIZE_COLS(ts), cols, ts.ws_xpixel));
562 SET_TTYSIZE(tty, ts);
563 }
564 #endif /* USE_STRUCT_WINSIZE */
565
566 #ifdef USE_ANY_SYSV_TERMIO
567 rc = ioctl(tty, TCSETAW, &tioorig);
568 #elif defined(USE_TERMIOS)
569 rc = tcsetattr(tty, TCSADRAIN, &tioorig);
570 #else /* not USE_TERMIOS */
571 rc = ioctl(tty, TIOCSETP, &sgorig);
572 #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
573 if (rc != 0)
574 failed("set tty settings");
575
576 signal(SIGINT, SIG_DFL);
577 signal(SIGQUIT, SIG_DFL);
578 signal(SIGTERM, SIG_DFL);
579
580 #ifdef USE_TERMCAP
581 if (ok_tcap) {
582 /* update termcap string */
583 /* first do columns */
584 if ((ptr = x_strindex(termcap, "co#")) == NULL) {
585 fprintf(stderr, "%s: No `co#'\n", myname);
586 exit(EXIT_FAILURE);
587 }
588
589 i = (int) (ptr - termcap) + 3;
590 strncpy(newtc, termcap, (size_t) i);
591 sprintf(newtc + i, "%d", cols);
592 if ((ptr = strchr(ptr, ':')) != 0)
593 strcat(newtc, ptr);
594
595 /* now do lines */
596 if ((ptr = x_strindex(newtc, "li#")) == NULL) {
597 fprintf(stderr, "%s: No `li#'\n", myname);
598 exit(EXIT_FAILURE);
599 }
600
601 i = (int) (ptr - newtc) + 3;
602 strncpy(termcap, newtc, (size_t) i);
603 sprintf(termcap + i, "%d", rows);
604 if ((ptr = strchr(ptr, ':')) != 0)
605 strcat(termcap, ptr);
606 }
607 #endif /* USE_TERMCAP */
608
609 if (SHELL_BOURNE == shell_type) {
610
611 #ifdef USE_TERMCAP
612 if (ok_tcap) {
613 printf("%sTERMCAP=", setname);
614 print_termcap(termcap);
615 printf(";\nexport TERMCAP;\n");
616 }
617 #endif /* USE_TERMCAP */
618 #ifdef USE_TERMINFO
619 printf("%sCOLUMNS=%d;\nLINES=%d;\nexport COLUMNS LINES;\n",
620 setname, cols, rows);
621 #endif /* USE_TERMINFO */
622
623 } else { /* not Bourne shell */
624
625 #ifdef USE_TERMCAP
626 if (ok_tcap) {
627 printf("set noglob;\n%ssetenv TERMCAP ", setname);
628 print_termcap(termcap);
629 printf(";\nunset noglob;\n");
630 }
631 #endif /* USE_TERMCAP */
632 #ifdef USE_TERMINFO
633 printf("set noglob;\n%ssetenv COLUMNS '%d';\nsetenv LINES '%d';\nunset noglob;\n",
634 setname, cols, rows);
635 #endif /* USE_TERMINFO */
636 }
637 exit(EXIT_SUCCESS);
638 }