Update install docs
[carla.git] / data / windows / unzipfx-carla-control / ttyio.c
bloba1a13b1853e4085062b209164af5e96f599299cb
1 /*
2 Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
4 See the accompanying file LICENSE, version 2000-Apr-09 or later
5 (the contents of which are also included in zip.h) for terms of use.
6 If, for some reason, all these files are missing, the Info-ZIP license
7 also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
8 */
9 /*---------------------------------------------------------------------------
11 ttyio.c
13 This file contains routines for doing console input/output, including code
14 for non-echoing input. It is used by the encryption/decryption code but
15 does not contain any restricted code itself. This file is shared between
16 Info-ZIP's Zip and UnZip.
18 Contains: echo() (VMS only)
19 Echon() (Unix only)
20 Echoff() (Unix only)
21 screensize() (Unix only)
22 zgetch() (Unix, VMS, and non-Unix/VMS versions)
23 getp() ("PC," Unix/Atari/Be, VMS/VMCMS/MVS)
25 ---------------------------------------------------------------------------*/
27 #define __TTYIO_C /* identifies this source module */
29 #include "zip.h"
30 #include "crypt.h"
32 #if (CRYPT || (defined(UNZIP) && !defined(FUNZIP)))
33 /* Non-echo console/keyboard input is needed for (en/de)cryption's password
34 * entry, and for UnZip(SFX)'s MORE and Pause features.
35 * (The corresponding #endif is found at the end of this module.)
38 #include "ttyio.h"
40 #ifndef PUTC
41 # define PUTC putc
42 #endif
44 #ifdef ZIP
45 # ifdef GLOBAL /* used in Amiga system headers, maybe others too */
46 # undef GLOBAL
47 # endif
48 # define GLOBAL(g) g
49 #else
50 # define GLOBAL(g) G.g
51 #endif
53 #if (defined(__ATHEOS__) || defined(__BEOS__)) /* why yes, we do */
54 # define HAVE_TERMIOS_H
55 #endif
57 #ifdef _POSIX_VERSION
58 # ifndef USE_POSIX_TERMIOS
59 # define USE_POSIX_TERMIOS /* use POSIX style termio (termios) */
60 # endif
61 # ifndef HAVE_TERMIOS_H
62 # define HAVE_TERMIOS_H /* POSIX termios.h */
63 # endif
64 #endif /* _POSIX_VERSION */
66 #ifdef UNZIP /* Zip handles this with the unix/configure script */
67 # ifndef _POSIX_VERSION
68 # if (defined(SYSV) || defined(CRAY)) && !defined(__MINT__)
69 # ifndef USE_SYSV_TERMIO
70 # define USE_SYSV_TERMIO
71 # endif
72 # ifdef COHERENT
73 # ifndef HAVE_TERMIO_H
74 # define HAVE_TERMIO_H
75 # endif
76 # ifdef HAVE_SYS_TERMIO_H
77 # undef HAVE_SYS_TERMIO_H
78 # endif
79 # else /* !COHERENT */
80 # ifdef HAVE_TERMIO_H
81 # undef HAVE_TERMIO_H
82 # endif
83 # ifndef HAVE_SYS_TERMIO_H
84 # define HAVE_SYS_TERMIO_H
85 # endif
86 # endif /* ?COHERENT */
87 # endif /* (SYSV || CRAY) && !__MINT__ */
88 # endif /* !_POSIX_VERSION */
89 # if !(defined(BSD4_4) || defined(SYSV) || defined(__convexc__))
90 # ifndef NO_FCNTL_H
91 # define NO_FCNTL_H
92 # endif
93 # endif /* !(BSD4_4 || SYSV || __convexc__) */
94 #endif /* UNZIP */
96 #ifdef HAVE_TERMIOS_H
97 # ifndef USE_POSIX_TERMIOS
98 # define USE_POSIX_TERMIOS
99 # endif
100 #endif
102 #if (defined(HAVE_TERMIO_H) || defined(HAVE_SYS_TERMIO_H))
103 # ifndef USE_SYSV_TERMIO
104 # define USE_SYSV_TERMIO
105 # endif
106 #endif
108 #if (defined(UNZIP) && !defined(FUNZIP) && defined(UNIX) && defined(MORE))
109 # include <sys/ioctl.h>
110 # define GOT_IOCTL_H
111 /* int ioctl OF((int, int, zvoid *)); GRR: may need for some systems */
112 #endif
114 #ifndef HAVE_WORKING_GETCH
115 /* include system support for switching of console echo */
116 # ifdef VMS
117 # include <descrip.h>
118 # include <iodef.h>
119 # include <ttdef.h>
120 /* Workaround for broken header files of older DECC distributions
121 * that are incompatible with the /NAMES=AS_IS qualifier. */
122 # define sys$assign SYS$ASSIGN
123 # define sys$dassgn SYS$DASSGN
124 # define sys$qiow SYS$QIOW
125 # include <starlet.h>
126 # include <ssdef.h>
127 # else /* !VMS */
128 # ifdef HAVE_TERMIOS_H
129 # include <termios.h>
130 # define sgttyb termios
131 # define sg_flags c_lflag
132 # define GTTY(f, s) tcgetattr(f, (zvoid *) s)
133 # define STTY(f, s) tcsetattr(f, TCSAFLUSH, (zvoid *) s)
134 # else /* !HAVE_TERMIOS_H */
135 # ifdef USE_SYSV_TERMIO /* Amdahl, Cray, all SysV? */
136 # ifdef HAVE_TERMIO_H
137 # include <termio.h>
138 # endif
139 # ifdef HAVE_SYS_TERMIO_H
140 # include <sys/termio.h>
141 # endif
142 # ifdef NEED_PTEM
143 # include <sys/stream.h>
144 # include <sys/ptem.h>
145 # endif
146 # define sgttyb termio
147 # define sg_flags c_lflag
148 # define GTTY(f,s) ioctl(f,TCGETA,(zvoid *)s)
149 # define STTY(f,s) ioctl(f,TCSETAW,(zvoid *)s)
150 # else /* !USE_SYSV_TERMIO */
151 # ifndef CMS_MVS
152 # if (!defined(MINIX) && !defined(GOT_IOCTL_H))
153 # include <sys/ioctl.h>
154 # endif
155 # include <sgtty.h>
156 # define GTTY gtty
157 # define STTY stty
158 # ifdef UNZIP
160 * XXX : Are these declarations needed at all ????
163 * GRR: let's find out... Hmmm, appears not...
164 int gtty OF((int, struct sgttyb *));
165 int stty OF((int, struct sgttyb *));
167 # endif
168 # endif /* !CMS_MVS */
169 # endif /* ?USE_SYSV_TERMIO */
170 # endif /* ?HAVE_TERMIOS_H */
171 # ifndef NO_FCNTL_H
172 # ifndef UNZIP
173 # include <fcntl.h>
174 # endif
175 # else
176 char *ttyname OF((int));
177 # endif
178 # endif /* ?VMS */
179 #endif /* !HAVE_WORKING_GETCH */
183 #ifndef HAVE_WORKING_GETCH
184 #ifdef VMS
186 static struct dsc$descriptor_s DevDesc =
187 {11, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$COMMAND"};
188 /* {dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer}; */
191 * Turn keyboard echoing on or off (VMS). Loosely based on VMSmunch.c
192 * and hence on Joe Meadows' file.c code.
194 int echo(opt)
195 int opt;
198 * For VMS v5.x:
199 * IO$_SENSEMODE/SETMODE info: Programming, Vol. 7A, System Programming,
200 * I/O User's: Part I, sec. 8.4.1.1, 8.4.3, 8.4.5, 8.6
201 * sys$assign(), sys$qio() info: Programming, Vol. 4B, System Services,
202 * System Services Reference Manual, pp. sys-23, sys-379
203 * fixed-length descriptor info: Programming, Vol. 3, System Services,
204 * Intro to System Routines, sec. 2.9.2
205 * Greg Roelofs, 15 Aug 91
208 short DevChan, iosb[4];
209 long status;
210 unsigned long ttmode[2]; /* space for 8 bytes */
213 /* assign a channel to standard input */
214 status = sys$assign(&DevDesc, &DevChan, 0, 0);
215 if (!(status & 1))
216 return status;
218 /* use sys$qio and the IO$_SENSEMODE function to determine the current
219 * tty status (for password reading, could use IO$_READVBLK function
220 * instead, but echo on/off will be more general)
222 status = sys$qiow(0, DevChan, IO$_SENSEMODE, &iosb, 0, 0,
223 ttmode, 8, 0, 0, 0, 0);
224 if (!(status & 1))
225 return status;
226 status = iosb[0];
227 if (!(status & 1))
228 return status;
230 /* modify mode buffer to be either NOECHO or ECHO
231 * (depending on function argument opt)
233 if (opt == 0) /* off */
234 ttmode[1] |= TT$M_NOECHO; /* set NOECHO bit */
235 else
236 ttmode[1] &= ~((unsigned long) TT$M_NOECHO); /* clear NOECHO bit */
238 /* use the IO$_SETMODE function to change the tty status */
239 status = sys$qiow(0, DevChan, IO$_SETMODE, &iosb, 0, 0,
240 ttmode, 8, 0, 0, 0, 0);
241 if (!(status & 1))
242 return status;
243 status = iosb[0];
244 if (!(status & 1))
245 return status;
247 /* deassign the sys$input channel by way of clean-up */
248 status = sys$dassgn(DevChan);
249 if (!(status & 1))
250 return status;
252 return SS$_NORMAL; /* we be happy */
254 } /* end function echo() */
258 * Read a single character from keyboard in non-echoing mode (VMS).
259 * (returns EOF in case of errors)
261 int tt_getch()
263 short DevChan, iosb[4];
264 long status;
265 char kbbuf[16]; /* input buffer with - some - excess length */
267 /* assign a channel to standard input */
268 status = sys$assign(&DevDesc, &DevChan, 0, 0);
269 if (!(status & 1))
270 return EOF;
272 /* read a single character from SYS$COMMAND (no-echo) and
273 * wait for completion
275 status = sys$qiow(0,DevChan,
276 IO$_READVBLK|IO$M_NOECHO|IO$M_NOFILTR,
277 &iosb, 0, 0,
278 &kbbuf, 1, 0, 0, 0, 0);
279 if ((status&1) == 1)
280 status = iosb[0];
282 /* deassign the sys$input channel by way of clean-up
283 * (for this step, we do not need to check the completion status)
285 sys$dassgn(DevChan);
287 /* return the first char read, or EOF in case the read request failed */
288 return (int)(((status&1) == 1) ? (uch)kbbuf[0] : EOF);
290 } /* end function tt_getch() */
293 #else /* !VMS: basically Unix */
296 /* For VM/CMS and MVS, non-echo terminal input is not (yet?) supported. */
297 #ifndef CMS_MVS
299 #ifdef ZIP /* moved to globals.h for UnZip */
300 static int echofd=(-1); /* file descriptor whose echo is off */
301 #endif
304 * Turn echo off for file descriptor f. Assumes that f is a tty device.
306 void Echoff(__G__ f)
307 __GDEF
308 int f; /* file descriptor for which to turn echo off */
310 struct sgttyb sg; /* tty device structure */
312 GLOBAL(echofd) = f;
313 GTTY(f, &sg); /* get settings */
314 sg.sg_flags &= ~ECHO; /* turn echo off */
315 STTY(f, &sg);
319 * Turn echo back on for file descriptor echofd.
321 void Echon(__G)
322 __GDEF
324 struct sgttyb sg; /* tty device structure */
326 if (GLOBAL(echofd) != -1) {
327 GTTY(GLOBAL(echofd), &sg); /* get settings */
328 sg.sg_flags |= ECHO; /* turn echo on */
329 STTY(GLOBAL(echofd), &sg);
330 GLOBAL(echofd) = -1;
334 #endif /* !CMS_MVS */
335 #endif /* ?VMS */
338 #if (defined(UNZIP) && !defined(FUNZIP))
340 #ifdef ATH_BEO_UNX
341 #ifdef MORE
344 * Get the number of lines on the output terminal. SCO Unix apparently
345 * defines TIOCGWINSZ but doesn't support it (!M_UNIX).
347 * GRR: will need to know width of terminal someday, too, to account for
348 * line-wrapping.
351 #if (defined(TIOCGWINSZ) && !defined(M_UNIX))
353 int screensize(tt_rows, tt_cols)
354 int *tt_rows;
355 int *tt_cols;
357 struct winsize wsz;
358 #ifdef DEBUG_WINSZ
359 static int firsttime = TRUE;
360 #endif
362 /* see termio(4) under, e.g., SunOS */
363 if (ioctl(1, TIOCGWINSZ, &wsz) == 0) {
364 #ifdef DEBUG_WINSZ
365 if (firsttime) {
366 firsttime = FALSE;
367 fprintf(stderr, "ttyio.c screensize(): ws_row = %d\n",
368 wsz.ws_row);
369 fprintf(stderr, "ttyio.c screensize(): ws_col = %d\n",
370 wsz.ws_col);
372 #endif
373 /* number of rows */
374 if (tt_rows != NULL)
375 *tt_rows = (int)((wsz.ws_row > 0) ? wsz.ws_row : 24);
376 /* number of columns */
377 if (tt_cols != NULL)
378 *tt_cols = (int)((wsz.ws_col > 0) ? wsz.ws_col : 80);
379 return 0; /* signal success */
380 } else { /* this happens when piping to more(1), for example */
381 #ifdef DEBUG_WINSZ
382 if (firsttime) {
383 firsttime = FALSE;
384 fprintf(stderr,
385 "ttyio.c screensize(): ioctl(TIOCGWINSZ) failed\n"));
387 #endif
388 /* VT-100 assumed to be minimal hardware */
389 if (tt_rows != NULL)
390 *tt_rows = 24;
391 if (tt_cols != NULL)
392 *tt_cols = 80;
393 return 1; /* signal failure */
397 #else /* !TIOCGWINSZ: service not available, fall back to semi-bogus method */
399 int screensize(tt_rows, tt_cols)
400 int *tt_rows;
401 int *tt_cols;
403 char *envptr, *getenv();
404 int n;
405 int errstat = 0;
407 /* GRR: this is overly simplistic, but don't have access to stty/gtty
408 * system anymore
410 if (tt_rows != NULL) {
411 envptr = getenv("LINES");
412 if (envptr == (char *)NULL || (n = atoi(envptr)) < 5) {
413 /* VT-100 assumed to be minimal hardware */
414 *tt_rows = 24;
415 errstat = 1; /* signal failure */
416 } else {
417 *tt_rows = n;
420 if (tt_cols != NULL) {
421 envptr = getenv("COLUMNS");
422 if (envptr == (char *)NULL || (n = atoi(envptr)) < 5) {
423 *tt_cols = 80;
424 errstat = 1; /* signal failure */
425 } else {
426 *tt_cols = n;
429 return errstat;
432 #endif /* ?(TIOCGWINSZ && !M_UNIX) */
433 #endif /* MORE */
437 * Get a character from the given file descriptor without echo or newline.
439 int zgetch(__G__ f)
440 __GDEF
441 int f; /* file descriptor from which to read */
443 #if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
444 char oldmin, oldtim;
445 #endif
446 char c;
447 struct sgttyb sg; /* tty device structure */
449 GTTY(f, &sg); /* get settings */
450 #if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
451 oldmin = sg.c_cc[VMIN]; /* save old values */
452 oldtim = sg.c_cc[VTIME];
453 sg.c_cc[VMIN] = 1; /* need only one char to return read() */
454 sg.c_cc[VTIME] = 0; /* no timeout */
455 sg.sg_flags &= ~ICANON; /* canonical mode off */
456 #else
457 sg.sg_flags |= CBREAK; /* cbreak mode on */
458 #endif
459 sg.sg_flags &= ~ECHO; /* turn echo off, too */
460 STTY(f, &sg); /* set cbreak mode */
461 GLOBAL(echofd) = f; /* in case ^C hit (not perfect: still CBREAK) */
463 read(f, &c, 1); /* read our character */
465 #if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
466 sg.c_cc[VMIN] = oldmin; /* restore old values */
467 sg.c_cc[VTIME] = oldtim;
468 sg.sg_flags |= ICANON; /* canonical mode on */
469 #else
470 sg.sg_flags &= ~CBREAK; /* cbreak mode off */
471 #endif
472 sg.sg_flags |= ECHO; /* turn echo on */
473 STTY(f, &sg); /* restore canonical mode */
474 GLOBAL(echofd) = -1;
476 return (int)(uch)c;
480 #else /* !ATH_BEO_UNX */
481 #ifndef VMS /* VMS supplies its own variant of getch() */
484 int zgetch(__G__ f)
485 __GDEF
486 int f; /* file descriptor from which to read (must be open already) */
488 char c, c2;
490 /*---------------------------------------------------------------------------
491 Get a character from the given file descriptor without echo; can't fake
492 CBREAK mode (i.e., newline required), but can get rid of all chars up to
493 and including newline.
494 ---------------------------------------------------------------------------*/
496 echoff(f);
497 read(f, &c, 1);
498 if (c != '\n')
499 do {
500 read(f, &c2, 1); /* throw away all other chars up thru newline */
501 } while (c2 != '\n');
502 echon();
503 return (int)c;
506 #endif /* !VMS */
507 #endif /* ?ATH_BEO_UNX */
509 #endif /* UNZIP && !FUNZIP */
510 #endif /* !HAVE_WORKING_GETCH */
513 #if CRYPT /* getp() is only used with full encryption */
516 * Simple compile-time check for source compatibility between
517 * zcrypt and ttyio:
519 #if (!defined(CR_MAJORVER) || (CR_MAJORVER < 2) || (CR_MINORVER < 7))
520 error: This Info-ZIP tool requires zcrypt 2.7 or later.
521 #endif
524 * Get a password of length n-1 or less into *p using the prompt *m.
525 * The entered password is not echoed.
528 #ifdef HAVE_WORKING_GETCH
530 * For the AMIGA, getch() is defined as Agetch(), which is in
531 * amiga/filedate.c; SAS/C 6.x provides a getch(), but since Agetch()
532 * uses the infrastructure that is already in place in filedate.c, it is
533 * smaller. With this function, echoff() and echon() are not needed.
535 * For the MAC, a non-echo macgetch() function is defined in the MacOS
536 * specific sources which uses the event handling mechanism of the
537 * desktop window manager to get a character from the keyboard.
539 * For the other systems in this section, a non-echo getch() function
540 * is either contained the C runtime library (conio package), or getch()
541 * is defined as an alias for a similar system specific RTL function.
544 #ifndef WINDLL /* WINDLL does not support a console interface */
545 #ifndef QDOS /* QDOS supplies a variant of this function */
547 /* This is the getp() function for all systems (with TTY type user interface)
548 * that supply a working `non-echo' getch() function for "raw" console input.
550 char *getp(__G__ m, p, n)
551 __GDEF
552 ZCONST char *m; /* prompt for password */
553 char *p; /* return value: line input */
554 int n; /* bytes available in p[] */
556 char c; /* one-byte buffer for read() to use */
557 int i; /* number of characters input */
558 char *w; /* warning on retry */
560 /* get password */
561 w = "";
562 do {
563 fputs(w, stderr); /* warning if back again */
564 fputs(m, stderr); /* display prompt and flush */
565 fflush(stderr);
566 i = 0;
567 do { /* read line, keeping first n characters */
568 if ((c = (char)getch()) == '\r')
569 c = '\n'; /* until user hits CR */
570 if (c == 8 || c == 127) {
571 if (i > 0) i--; /* the `backspace' and `del' keys works */
573 else if (i < n)
574 p[i++] = c; /* truncate past n */
575 } while (c != '\n');
576 PUTC('\n', stderr); fflush(stderr);
577 w = "(line too long--try again)\n";
578 } while (p[i-1] != '\n');
579 p[i-1] = 0; /* terminate at newline */
581 return p; /* return pointer to password */
583 } /* end function getp() */
585 #endif /* !QDOS */
586 #endif /* !WINDLL */
589 #else /* !HAVE_WORKING_GETCH */
592 #if (defined(ATH_BEO_UNX) || defined(__MINT__))
594 #ifndef _PATH_TTY
595 # ifdef __MINT__
596 # define _PATH_TTY ttyname(2)
597 # else
598 # define _PATH_TTY "/dev/tty"
599 # endif
600 #endif
602 char *getp(__G__ m, p, n)
603 __GDEF
604 ZCONST char *m; /* prompt for password */
605 char *p; /* return value: line input */
606 int n; /* bytes available in p[] */
608 char c; /* one-byte buffer for read() to use */
609 int i; /* number of characters input */
610 char *w; /* warning on retry */
611 int f; /* file descriptor for tty device */
613 #ifdef PASSWD_FROM_STDIN
614 /* Read from stdin. This is unsafe if the password is stored on disk. */
615 f = 0;
616 #else
617 /* turn off echo on tty */
619 if ((f = open(_PATH_TTY, 0)) == -1)
620 return NULL;
621 #endif
622 /* get password */
623 w = "";
624 do {
625 fputs(w, stderr); /* warning if back again */
626 fputs(m, stderr); /* prompt */
627 fflush(stderr);
628 i = 0;
629 echoff(f);
630 do { /* read line, keeping n */
631 read(f, &c, 1);
632 if (i < n)
633 p[i++] = c;
634 } while (c != '\n');
635 echon();
636 PUTC('\n', stderr); fflush(stderr);
637 w = "(line too long--try again)\n";
638 } while (p[i-1] != '\n');
639 p[i-1] = 0; /* terminate at newline */
641 #ifndef PASSWD_FROM_STDIN
642 close(f);
643 #endif
645 return p; /* return pointer to password */
647 } /* end function getp() */
649 #endif /* ATH_BEO_UNX || __MINT__ */
653 #if (defined(VMS) || defined(CMS_MVS))
655 char *getp(__G__ m, p, n)
656 __GDEF
657 ZCONST char *m; /* prompt for password */
658 char *p; /* return value: line input */
659 int n; /* bytes available in p[] */
661 char c; /* one-byte buffer for read() to use */
662 int i; /* number of characters input */
663 char *w; /* warning on retry */
664 FILE *f; /* file structure for SYS$COMMAND device */
666 #ifdef PASSWD_FROM_STDIN
667 f = stdin;
668 #else
669 if ((f = fopen(ctermid(NULL), "r")) == NULL)
670 return NULL;
671 #endif
673 /* get password */
674 fflush(stdout);
675 w = "";
676 do {
677 if (*w) /* bug: VMS apparently adds \n to NULL fputs */
678 fputs(w, stderr); /* warning if back again */
679 fputs(m, stderr); /* prompt */
680 fflush(stderr);
681 i = 0;
682 echoff(f);
683 do { /* read line, keeping n */
684 if ((c = (char)getc(f)) == '\r')
685 c = '\n';
686 if (i < n)
687 p[i++] = c;
688 } while (c != '\n');
689 echon();
690 PUTC('\n', stderr); fflush(stderr);
691 w = "(line too long--try again)\n";
692 } while (p[i-1] != '\n');
693 p[i-1] = 0; /* terminate at newline */
694 #ifndef PASSWD_FROM_STDIN
695 fclose(f);
696 #endif
698 return p; /* return pointer to password */
700 } /* end function getp() */
702 #endif /* VMS || CMS_MVS */
703 #endif /* ?HAVE_WORKING_GETCH */
704 #endif /* CRYPT */
705 #endif /* CRYPT || (UNZIP && !FUNZIP) */