2 Copyright (c) 1990-2001 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
9 /*---------------------------------------------------------------------------
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)
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 */
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.)
45 # ifdef GLOBAL /* used in Amiga system headers, maybe others too */
50 # define GLOBAL(g) G.g
53 #if (defined(__BEOS__) || defined(__HAIKU__)) /* why yes, we do */
54 # define HAVE_TERMIOS_H
58 # ifndef USE_POSIX_TERMIOS
59 # define USE_POSIX_TERMIOS /* use POSIX style termio (termios) */
61 # ifndef HAVE_TERMIOS_H
62 # define HAVE_TERMIOS_H /* POSIX termios.h */
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
73 # ifndef HAVE_TERMIO_H
74 # define HAVE_TERMIO_H
76 # ifdef HAVE_SYS_TERMIO_H
77 # undef HAVE_SYS_TERMIO_H
79 # else /* !COHERENT */
83 # ifndef HAVE_SYS_TERMIO_H
84 # define HAVE_SYS_TERMIO_H
86 # endif /* ?COHERENT */
87 # endif /* (SYSV || CRAY) && !__MINT__ */
88 # endif /* !_POSIX_VERSION */
89 # if !(defined(BSD4_4) || defined(SYSV) || defined(__convexc__))
93 # endif /* !(BSD4_4 || SYSV || __convexc__) */
97 # ifndef USE_POSIX_TERMIOS
98 # define USE_POSIX_TERMIOS
102 #if (defined(HAVE_TERMIO_H) || defined(HAVE_SYS_TERMIO_H))
103 # ifndef USE_SYSV_TERMIO
104 # define USE_SYSV_TERMIO
108 #if (defined(UNZIP) && !defined(FUNZIP) && defined(UNIX) && defined(MORE))
109 # include <sys/ioctl.h>
111 /* int ioctl OF((int, int, zvoid *)); GRR: may need for some systems */
114 #ifndef HAVE_WORKING_GETCH
115 /* include system support for switching of console echo */
117 # include <descrip.h>
120 # include <starlet.h>
123 # ifdef HAVE_TERMIOS_H
124 # include <termios.h>
125 # define sgttyb termios
126 # define sg_flags c_lflag
127 # define GTTY(f, s) tcgetattr(f, (zvoid *) s)
128 # define STTY(f, s) tcsetattr(f, TCSAFLUSH, (zvoid *) s)
129 # else /* !HAVE_TERMIOS_H */
130 # ifdef USE_SYSV_TERMIO /* Amdahl, Cray, all SysV? */
131 # ifdef HAVE_TERMIO_H
134 # ifdef HAVE_SYS_TERMIO_H
135 # include <sys/termio.h>
138 # include <sys/stream.h>
139 # include <sys/ptem.h>
141 # define sgttyb termio
142 # define sg_flags c_lflag
143 # define GTTY(f,s) ioctl(f,TCGETA,(zvoid *)s)
144 # define STTY(f,s) ioctl(f,TCSETAW,(zvoid *)s)
145 # else /* !USE_SYSV_TERMIO */
147 # if (!defined(MINIX) && !defined(GOT_IOCTL_H))
148 # include <sys/ioctl.h>
155 * XXX : Are these declarations needed at all ????
158 * GRR: let's find out... Hmmm, appears not...
159 int gtty OF((int, struct sgttyb *));
160 int stty OF((int, struct sgttyb *));
163 # endif /* !CMS_MVS */
164 # endif /* ?USE_SYSV_TERMIO */
165 # endif /* ?HAVE_TERMIOS_H */
171 char *ttyname
OF((int));
174 #endif /* !HAVE_WORKING_GETCH */
178 #ifndef HAVE_WORKING_GETCH
181 static struct dsc$descriptor_s DevDesc
=
182 {11, DSC$K_DTYPE_T
, DSC$K_CLASS_S
, "SYS$COMMAND"};
183 /* {dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer}; */
186 * Turn keyboard echoing on or off (VMS). Loosely based on VMSmunch.c
187 * and hence on Joe Meadows' file.c code.
194 * IO$_SENSEMODE/SETMODE info: Programming, Vol. 7A, System Programming,
195 * I/O User's: Part I, sec. 8.4.1.1, 8.4.3, 8.4.5, 8.6
196 * sys$assign(), sys$qio() info: Programming, Vol. 4B, System Services,
197 * System Services Reference Manual, pp. sys-23, sys-379
198 * fixed-length descriptor info: Programming, Vol. 3, System Services,
199 * Intro to System Routines, sec. 2.9.2
200 * Greg Roelofs, 15 Aug 91
203 short DevChan
, iosb
[4];
205 unsigned long ttmode
[2]; /* space for 8 bytes */
208 /* assign a channel to standard input */
209 status
= sys$
assign(&DevDesc
, &DevChan
, 0, 0);
213 /* use sys$qio and the IO$_SENSEMODE function to determine the current
214 * tty status (for password reading, could use IO$_READVBLK function
215 * instead, but echo on/off will be more general)
217 status
= sys$
qiow(0, DevChan
, IO$_SENSEMODE
, &iosb
, 0, 0,
218 ttmode
, 8, 0, 0, 0, 0);
225 /* modify mode buffer to be either NOECHO or ECHO
226 * (depending on function argument opt)
228 if (opt
== 0) /* off */
229 ttmode
[1] |= TT$M_NOECHO
; /* set NOECHO bit */
231 ttmode
[1] &= ~((unsigned long) TT$M_NOECHO
); /* clear NOECHO bit */
233 /* use the IO$_SETMODE function to change the tty status */
234 status
= sys$
qiow(0, DevChan
, IO$_SETMODE
, &iosb
, 0, 0,
235 ttmode
, 8, 0, 0, 0, 0);
242 /* deassign the sys$input channel by way of clean-up */
243 status
= sys$
dassgn(DevChan
);
247 return SS$_NORMAL
; /* we be happy */
249 } /* end function echo() */
253 * Read a single character from keyboard in non-echoing mode (VMS).
254 * (returns EOF in case of errors)
258 short DevChan
, iosb
[4];
260 char kbbuf
[16]; /* input buffer with - some - excess length */
262 /* assign a channel to standard input */
263 status
= sys$
assign(&DevDesc
, &DevChan
, 0, 0);
267 /* read a single character from SYS$COMMAND (no-echo) and
268 * wait for completion
270 status
= sys$
qiow(0,DevChan
,
271 IO$_READVBLK
|IO$M_NOECHO
|IO$M_NOFILTR
,
273 &kbbuf
, 1, 0, 0, 0, 0);
277 /* deassign the sys$input channel by way of clean-up
278 * (for this step, we do not need to check the completion status)
282 /* return the first char read, or EOF in case the read request failed */
283 return (int)(((status
&1) == 1) ? (uch
)kbbuf
[0] : EOF
);
285 } /* end function tt_getch() */
288 #else /* !VMS: basically Unix */
291 /* For VM/CMS and MVS, non-echo terminal input is not (yet?) supported. */
294 #ifdef ZIP /* moved to globals.h for UnZip */
295 static int echofd
=(-1); /* file descriptor whose echo is off */
299 * Turn echo off for file descriptor f. Assumes that f is a tty device.
303 int f
; /* file descriptor for which to turn echo off */
305 struct sgttyb sg
; /* tty device structure */
308 GTTY(f
, &sg
); /* get settings */
309 sg
.sg_flags
&= ~ECHO
; /* turn echo off */
314 * Turn echo back on for file descriptor echofd.
319 struct sgttyb sg
; /* tty device structure */
321 if (GLOBAL(echofd
) != -1) {
322 GTTY(GLOBAL(echofd
), &sg
); /* get settings */
323 sg
.sg_flags
|= ECHO
; /* turn echo on */
324 STTY(GLOBAL(echofd
), &sg
);
329 #endif /* !CMS_MVS */
333 #if (defined(UNZIP) && !defined(FUNZIP))
335 #if (defined(UNIX) || (defined(__BEOS__) || defined(__HAIKU__)))
339 * Get the number of lines on the output terminal. SCO Unix apparently
340 * defines TIOCGWINSZ but doesn't support it (!M_UNIX).
342 * GRR: will need to know width of terminal someday, too, to account for
346 #if (defined(TIOCGWINSZ) && !defined(M_UNIX))
348 int screensize(tt_rows
, tt_cols
)
354 static int firsttime
= TRUE
;
357 /* see termio(4) under, e.g., SunOS */
358 if (ioctl(1, TIOCGWINSZ
, &wsz
) == 0) {
362 fprintf(stderr
, "ttyio.c screensize(): ws_row = %d\n",
364 fprintf(stderr
, "ttyio.c screensize(): ws_col = %d\n",
370 *tt_rows
= (int)((wsz
.ws_row
> 0) ? wsz
.ws_row
: 24);
371 /* number of columns */
373 *tt_cols
= (int)((wsz
.ws_col
> 0) ? wsz
.ws_col
: 80);
374 return 0; /* signal success */
375 } else { /* this happens when piping to more(1), for example */
380 "ttyio.c screensize(): ioctl(TIOCGWINSZ) failed\n"));
383 /* VT-100 assumed to be minimal hardware */
388 return 1; /* signal failure */
392 #else /* !TIOCGWINSZ: service not available, fall back to semi-bogus method */
394 int screensize(tt_rows
, tt_cols
)
398 char *envptr
, *getenv();
402 /* GRR: this is overly simplistic, but don't have access to stty/gtty
405 if (tt_rows
!= NULL
) {
406 envptr
= getenv("LINES");
407 if (envptr
== (char *)NULL
|| (n
= atoi(envptr
)) < 5) {
408 /* VT-100 assumed to be minimal hardware */
410 errstat
= 1; /* signal failure */
415 if (tt_cols
!= NULL
) {
416 envptr
= getenv("COLUMNS");
417 if (envptr
== (char *)NULL
|| (n
= atoi(envptr
)) < 5) {
419 errstat
= 1; /* signal failure */
427 #endif /* ?(TIOCGWINSZ && !M_UNIX) */
432 * Get a character from the given file descriptor without echo or newline.
436 int f
; /* file descriptor from which to read */
438 #if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
442 struct sgttyb sg
; /* tty device structure */
444 GTTY(f
, &sg
); /* get settings */
445 #if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
446 oldmin
= sg
.c_cc
[VMIN
]; /* save old values */
447 oldtim
= sg
.c_cc
[VTIME
];
448 sg
.c_cc
[VMIN
] = 1; /* need only one char to return read() */
449 sg
.c_cc
[VTIME
] = 0; /* no timeout */
450 sg
.sg_flags
&= ~ICANON
; /* canonical mode off */
452 sg
.sg_flags
|= CBREAK
; /* cbreak mode on */
454 sg
.sg_flags
&= ~ECHO
; /* turn echo off, too */
455 STTY(f
, &sg
); /* set cbreak mode */
456 GLOBAL(echofd
) = f
; /* in case ^C hit (not perfect: still CBREAK) */
458 read(f
, &c
, 1); /* read our character */
460 #if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
461 sg
.c_cc
[VMIN
] = oldmin
; /* restore old values */
462 sg
.c_cc
[VTIME
] = oldtim
;
463 sg
.sg_flags
|= ICANON
; /* canonical mode on */
465 sg
.sg_flags
&= ~CBREAK
; /* cbreak mode off */
467 sg
.sg_flags
|= ECHO
; /* turn echo on */
468 STTY(f
, &sg
); /* restore canonical mode */
475 #else /* !UNIX && !__BEOS__ */
476 #ifndef VMS /* VMS supplies its own variant of getch() */
481 int f
; /* file descriptor from which to read (must be open already) */
485 /*---------------------------------------------------------------------------
486 Get a character from the given file descriptor without echo; can't fake
487 CBREAK mode (i.e., newline required), but can get rid of all chars up to
488 and including newline.
489 ---------------------------------------------------------------------------*/
495 read(f
, &c2
, 1); /* throw away all other chars up thru newline */
496 } while (c2
!= '\n');
502 #endif /* ?(UNIX || __BEOS__) */
504 #endif /* UNZIP && !FUNZIP */
505 #endif /* !HAVE_WORKING_GETCH */
508 #if CRYPT /* getp() is only used with full encryption */
511 * Simple compile-time check for source compatibility between
514 #if (!defined(CR_MAJORVER) || (CR_MAJORVER < 2) || (CR_MINORVER < 7))
515 error
: This Info
-ZIP tool requires zcrypt
2.7 or later
.
519 * Get a password of length n-1 or less into *p using the prompt *m.
520 * The entered password is not echoed.
523 #ifdef HAVE_WORKING_GETCH
525 * For the AMIGA, getch() is defined as Agetch(), which is in
526 * amiga/filedate.c; SAS/C 6.x provides a getch(), but since Agetch()
527 * uses the infrastructure that is already in place in filedate.c, it is
528 * smaller. With this function, echoff() and echon() are not needed.
530 * For the MAC, a non-echo macgetch() function is defined in the MacOS
531 * specific sources which uses the event handling mechanism of the
532 * desktop window manager to get a character from the keyboard.
534 * For the other systems in this section, a non-echo getch() function
535 * is either contained the C runtime library (conio package), or getch()
536 * is defined as an alias for a similar system specific RTL function.
539 #ifndef WINDLL /* WINDLL does not support a console interface */
540 #ifndef QDOS /* QDOS supplies a variant of this function */
542 /* This is the getp() function for all systems (with TTY type user interface)
543 * that supply a working `non-echo' getch() function for "raw" console input.
545 char *getp(__G__ m
, p
, n
)
547 ZCONST
char *m
; /* prompt for password */
548 char *p
; /* return value: line input */
549 int n
; /* bytes available in p[] */
551 char c
; /* one-byte buffer for read() to use */
552 int i
; /* number of characters input */
553 char *w
; /* warning on retry */
558 fputs(w
, stderr
); /* warning if back again */
559 fputs(m
, stderr
); /* display prompt and flush */
562 do { /* read line, keeping first n characters */
563 if ((c
= (char)getch()) == '\r')
564 c
= '\n'; /* until user hits CR */
565 if (c
== 8 || c
== 127) {
566 if (i
> 0) i
--; /* the `backspace' and `del' keys works */
569 p
[i
++] = c
; /* truncate past n */
571 PUTC('\n', stderr
); fflush(stderr
);
572 w
= "(line too long--try again)\n";
573 } while (p
[i
-1] != '\n');
574 p
[i
-1] = 0; /* terminate at newline */
576 return p
; /* return pointer to password */
578 } /* end function getp() */
584 #else /* !HAVE_WORKING_GETCH */
587 #if (defined(UNIX) || defined(__MINT__) || (defined(__BEOS__) || defined(__HAIKU__)))
591 # define _PATH_TTY ttyname(2)
593 # define _PATH_TTY "/dev/tty"
597 char *getp(__G__ m
, p
, n
)
599 ZCONST
char *m
; /* prompt for password */
600 char *p
; /* return value: line input */
601 int n
; /* bytes available in p[] */
603 char c
; /* one-byte buffer for read() to use */
604 int i
; /* number of characters input */
605 char *w
; /* warning on retry */
606 int f
; /* file descriptor for tty device */
608 #ifdef PASSWD_FROM_STDIN
609 /* Read from stdin. This is unsafe if the password is stored on disk. */
612 /* turn off echo on tty */
614 if ((f
= open(_PATH_TTY
, 0)) == -1)
620 fputs(w
, stderr
); /* warning if back again */
621 fputs(m
, stderr
); /* prompt */
625 do { /* read line, keeping n */
631 PUTC('\n', stderr
); fflush(stderr
);
632 w
= "(line too long--try again)\n";
633 } while (p
[i
-1] != '\n');
634 p
[i
-1] = 0; /* terminate at newline */
636 #ifndef PASSWD_FROM_STDIN
640 return p
; /* return pointer to password */
642 } /* end function getp() */
644 #endif /* UNIX || __MINT__ || __BEOS__ */
648 #if (defined(VMS) || defined(CMS_MVS))
650 char *getp(__G__ m
, p
, n
)
652 ZCONST
char *m
; /* prompt for password */
653 char *p
; /* return value: line input */
654 int n
; /* bytes available in p[] */
656 char c
; /* one-byte buffer for read() to use */
657 int i
; /* number of characters input */
658 char *w
; /* warning on retry */
659 FILE *f
; /* file structure for SYS$COMMAND device */
661 #ifdef PASSWD_FROM_STDIN
664 if ((f
= fopen(ctermid(NULL
), "r")) == NULL
)
672 if (*w
) /* bug: VMS apparently adds \n to NULL fputs */
673 fputs(w
, stderr
); /* warning if back again */
674 fputs(m
, stderr
); /* prompt */
678 do { /* read line, keeping n */
679 if ((c
= (char)getc(f
)) == '\r')
685 PUTC('\n', stderr
); fflush(stderr
);
686 w
= "(line too long--try again)\n";
687 } while (p
[i
-1] != '\n');
688 p
[i
-1] = 0; /* terminate at newline */
689 #ifndef PASSWD_FROM_STDIN
693 return p
; /* return pointer to password */
695 } /* end function getp() */
697 #endif /* VMS || CMS_MVS */
698 #endif /* ?HAVE_WORKING_GETCH */
700 #endif /* CRYPT || (UNZIP && !FUNZIP) */