Copyright (c) 1990-2001 Info-ZIP. All rights reserved.
See the accompanying file LICENSE, version 2000-Apr-09 or later
(the contents of which are also included in zip.h) for terms of use.
If, for some reason, all these files are missing, the Info-ZIP license
also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
*/
ttyio.c
This file contains routines for doing console input/output, including code
for non-echoing input. It is used by the encryption/decryption code but
does not contain any restricted code itself. This file is shared between
Info-ZIP's Zip and UnZip.
Contains: echo() (VMS only)
Echon() (Unix only)
Echoff() (Unix only)
screensize() (Unix only)
zgetch() (Unix, VMS, and non-Unix/VMS versions)
getp() ("PC," Unix/Atari/Be, VMS/VMCMS/MVS)
---------------------------------------------------------------------------*/
#define __TTYIO_C
#include "zip.h"
#include "crypt.h"
#if (CRYPT || (defined(UNZIP) && !defined(FUNZIP)))
* entry, and for UnZip(SFX)'s MORE and Pause features.
* (The corresponding #endif is found at the end of this module.)
*/
#include "ttyio.h"
#ifndef PUTC
# define PUTC putc
#endif
#ifdef ZIP
# ifdef GLOBAL
# undef GLOBAL
# endif
# define GLOBAL(g) g
#else
# define GLOBAL(g) G.g
#endif
#if (defined(__BEOS__) || defined(__HAIKU__))
# define HAVE_TERMIOS_H
#endif
#ifdef _POSIX_VERSION
# ifndef USE_POSIX_TERMIOS
# define USE_POSIX_TERMIOS
# endif
# ifndef HAVE_TERMIOS_H
# define HAVE_TERMIOS_H
# endif
#endif
#ifdef UNZIP
# ifndef _POSIX_VERSION
# if (defined(SYSV) || defined(CRAY)) && !defined(__MINT__)
# ifndef USE_SYSV_TERMIO
# define USE_SYSV_TERMIO
# endif
# ifdef COHERENT
# ifndef HAVE_TERMIO_H
# define HAVE_TERMIO_H
# endif
# ifdef HAVE_SYS_TERMIO_H
# undef HAVE_SYS_TERMIO_H
# endif
# else
# ifdef HAVE_TERMIO_H
# undef HAVE_TERMIO_H
# endif
# ifndef HAVE_SYS_TERMIO_H
# define HAVE_SYS_TERMIO_H
# endif
# endif
# endif
# endif
# if !(defined(BSD4_4) || defined(SYSV) || defined(__convexc__))
# ifndef NO_FCNTL_H
# define NO_FCNTL_H
# endif
# endif
#endif
#ifdef HAVE_TERMIOS_H
# ifndef USE_POSIX_TERMIOS
# define USE_POSIX_TERMIOS
# endif
#endif
#if (defined(HAVE_TERMIO_H) || defined(HAVE_SYS_TERMIO_H))
# ifndef USE_SYSV_TERMIO
# define USE_SYSV_TERMIO
# endif
#endif
#if (defined(UNZIP) && !defined(FUNZIP) && defined(UNIX) && defined(MORE))
# include <sys/ioctl.h>
# define GOT_IOCTL_H
/* int ioctl OF((int, int, zvoid *)); GRR: may need for some systems */
#endif
#ifndef HAVE_WORKING_GETCH
# ifdef VMS
# include <descrip.h>
# include <iodef.h>
# include <ttdef.h>
# include <starlet.h>
# include <ssdef.h>
# else
# ifdef HAVE_TERMIOS_H
# include <termios.h>
# define sgttyb termios
# define sg_flags c_lflag
# define GTTY(f, s) tcgetattr(f, (zvoid *) s)
# define STTY(f, s) tcsetattr(f, TCSAFLUSH, (zvoid *) s)
# else
# ifdef USE_SYSV_TERMIO
# ifdef HAVE_TERMIO_H
# include <termio.h>
# endif
# ifdef HAVE_SYS_TERMIO_H
# include <sys/termio.h>
# endif
# ifdef NEED_PTEM
# include <sys/stream.h>
# include <sys/ptem.h>
# endif
# define sgttyb termio
# define sg_flags c_lflag
# define GTTY(f,s) ioctl(f,TCGETA,(zvoid *)s)
# define STTY(f,s) ioctl(f,TCSETAW,(zvoid *)s)
# else
# ifndef CMS_MVS
# if (!defined(MINIX) && !defined(GOT_IOCTL_H))
# include <sys/ioctl.h>
# endif
# include <sgtty.h>
# define GTTY gtty
# define STTY stty
# ifdef UNZIP
* XXX : Are these declarations needed at all ????
*/
* GRR: let's find out... Hmmm, appears not...
int gtty OF((int, struct sgttyb *));
int stty OF((int, struct sgttyb *));
*/
# endif
# endif
# endif
# endif
# ifndef NO_FCNTL_H
# ifndef UNZIP
# include <fcntl.h>
# endif
# else
char *ttyname OF((int));
# endif
# endif
#endif
#ifndef HAVE_WORKING_GETCH
#ifdef VMS
static struct dsc$descriptor_s DevDesc =
{11, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$COMMAND"};
* Turn keyboard echoing on or off (VMS). Loosely based on VMSmunch.c
* and hence on Joe Meadows' file.c code.
*/
int echo(opt)
int opt;
{
* For VMS v5.x:
* IO$_SENSEMODE/SETMODE info: Programming, Vol. 7A, System Programming,
* I/O User's: Part I, sec. 8.4.1.1, 8.4.3, 8.4.5, 8.6
* sys$assign(), sys$qio() info: Programming, Vol. 4B, System Services,
* System Services Reference Manual, pp. sys-23, sys-379
* fixed-length descriptor info: Programming, Vol. 3, System Services,
* Intro to System Routines, sec. 2.9.2
* Greg Roelofs, 15 Aug 91
*/
short DevChan, iosb[4];
long status;
unsigned long ttmode[2];
status = sys$assign(&DevDesc, &DevChan, 0, 0);
if (!(status & 1))
return status;
* tty status (for password reading, could use IO$_READVBLK function
* instead, but echo on/off will be more general)
*/
status = sys$qiow(0, DevChan, IO$_SENSEMODE, &iosb, 0, 0,
ttmode, 8, 0, 0, 0, 0);
if (!(status & 1))
return status;
status = iosb[0];
if (!(status & 1))
return status;
* (depending on function argument opt)
*/
if (opt == 0)
ttmode[1] |= TT$M_NOECHO;
else
ttmode[1] &= ~((unsigned long) TT$M_NOECHO);
status = sys$qiow(0, DevChan, IO$_SETMODE, &iosb, 0, 0,
ttmode, 8, 0, 0, 0, 0);
if (!(status & 1))
return status;
status = iosb[0];
if (!(status & 1))
return status;
status = sys$dassgn(DevChan);
if (!(status & 1))
return status;
return SS$_NORMAL;
}
* Read a single character from keyboard in non-echoing mode (VMS).
* (returns EOF in case of errors)
*/
int tt_getch()
{
short DevChan, iosb[4];
long status;
char kbbuf[16];
status = sys$assign(&DevDesc, &DevChan, 0, 0);
if (!(status & 1))
return EOF;
* wait for completion
*/
status = sys$qiow(0,DevChan,
IO$_READVBLK|IO$M_NOECHO|IO$M_NOFILTR,
&iosb, 0, 0,
&kbbuf, 1, 0, 0, 0, 0);
if ((status&1) == 1)
status = iosb[0];
* (for this step, we do not need to check the completion status)
*/
sys$dassgn(DevChan);
return (int)(((status&1) == 1) ? (uch)kbbuf[0] : EOF);
}
#else
#ifndef CMS_MVS
#ifdef ZIP
static int echofd=(-1);
#endif
* Turn echo off for file descriptor f. Assumes that f is a tty device.
*/
void Echoff(__G__ f)
__GDEF
int f;
{
struct sgttyb sg;
GLOBAL(echofd) = f;
GTTY(f, &sg);
sg.sg_flags &= ~ECHO;
STTY(f, &sg);
}
* Turn echo back on for file descriptor echofd.
*/
void Echon(__G)
__GDEF
{
struct sgttyb sg;
if (GLOBAL(echofd) != -1) {
GTTY(GLOBAL(echofd), &sg);
sg.sg_flags |= ECHO;
STTY(GLOBAL(echofd), &sg);
GLOBAL(echofd) = -1;
}
}
#endif
#endif
#if (defined(UNZIP) && !defined(FUNZIP))
#if (defined(UNIX) || (defined(__BEOS__) || defined(__HAIKU__)))
#ifdef MORE
* Get the number of lines on the output terminal. SCO Unix apparently
* defines TIOCGWINSZ but doesn't support it (!M_UNIX).
*
* GRR: will need to know width of terminal someday, too, to account for
* line-wrapping.
*/
#if (defined(TIOCGWINSZ) && !defined(M_UNIX))
int screensize(tt_rows, tt_cols)
int *tt_rows;
int *tt_cols;
{
struct winsize wsz;
#ifdef DEBUG_WINSZ
static int firsttime = TRUE;
#endif
if (ioctl(1, TIOCGWINSZ, &wsz) == 0) {
#ifdef DEBUG_WINSZ
if (firsttime) {
firsttime = FALSE;
fprintf(stderr, "ttyio.c screensize(): ws_row = %d\n",
wsz.ws_row);
fprintf(stderr, "ttyio.c screensize(): ws_col = %d\n",
wsz.ws_col);
}
#endif
if (tt_rows != NULL)
*tt_rows = (int)((wsz.ws_row > 0) ? wsz.ws_row : 24);
if (tt_cols != NULL)
*tt_cols = (int)((wsz.ws_col > 0) ? wsz.ws_col : 80);
return 0;
} else {
#ifdef DEBUG_WINSZ
if (firsttime) {
firsttime = FALSE;
fprintf(stderr,
"ttyio.c screensize(): ioctl(TIOCGWINSZ) failed\n"));
}
#endif
if (tt_rows != NULL)
*tt_rows = 24;
if (tt_cols != NULL)
*tt_cols = 80;
return 1;
}
}
#else
int screensize(tt_rows, tt_cols)
int *tt_rows;
int *tt_cols;
{
char *envptr, *getenv();
int n;
int errstat = 0;
* system anymore
*/
if (tt_rows != NULL) {
envptr = getenv("LINES");
if (envptr == (char *)NULL || (n = atoi(envptr)) < 5) {
*tt_rows = 24;
errstat = 1;
} else {
*tt_rows = n;
}
}
if (tt_cols != NULL) {
envptr = getenv("COLUMNS");
if (envptr == (char *)NULL || (n = atoi(envptr)) < 5) {
*tt_cols = 80;
errstat = 1;
} else {
*tt_cols = n;
}
}
return errstat;
}
#endif
#endif
* Get a character from the given file descriptor without echo or newline.
*/
int zgetch(__G__ f)
__GDEF
int f;
{
#if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
char oldmin, oldtim;
#endif
char c;
struct sgttyb sg;
GTTY(f, &sg);
#if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
oldmin = sg.c_cc[VMIN];
oldtim = sg.c_cc[VTIME];
sg.c_cc[VMIN] = 1;
sg.c_cc[VTIME] = 0;
sg.sg_flags &= ~ICANON;
#else
sg.sg_flags |= CBREAK;
#endif
sg.sg_flags &= ~ECHO;
STTY(f, &sg);
GLOBAL(echofd) = f;
read(f, &c, 1);
#if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
sg.c_cc[VMIN] = oldmin;
sg.c_cc[VTIME] = oldtim;
sg.sg_flags |= ICANON;
#else
sg.sg_flags &= ~CBREAK;
#endif
sg.sg_flags |= ECHO;
STTY(f, &sg);
GLOBAL(echofd) = -1;
return (int)(uch)c;
}
#else
#ifndef VMS
int zgetch(__G__ f)
__GDEF
int f;
{
char c, c2;
Get a character from the given file descriptor without echo; can't fake
CBREAK mode (i.e., newline required), but can get rid of all chars up to
and including newline.
---------------------------------------------------------------------------*/
echoff(f);
read(f, &c, 1);
if (c != '\n')
do {
read(f, &c2, 1);
} while (c2 != '\n');
echon();
return (int)c;
}
#endif
#endif
#endif
#endif
#if CRYPT
* Simple compile-time check for source compatibility between
* zcrypt and ttyio:
*/
#if (!defined(CR_MAJORVER) || (CR_MAJORVER < 2) || (CR_MINORVER < 7))
error: This Info-ZIP tool requires zcrypt 2.7 or later.
#endif
* Get a password of length n-1 or less into *p using the prompt *m.
* The entered password is not echoed.
*/
#ifdef HAVE_WORKING_GETCH
* For the AMIGA, getch() is defined as Agetch(), which is in
* amiga/filedate.c; SAS/C 6.x provides a getch(), but since Agetch()
* uses the infrastructure that is already in place in filedate.c, it is
* smaller. With this function, echoff() and echon() are not needed.
*
* For the MAC, a non-echo macgetch() function is defined in the MacOS
* specific sources which uses the event handling mechanism of the
* desktop window manager to get a character from the keyboard.
*
* For the other systems in this section, a non-echo getch() function
* is either contained the C runtime library (conio package), or getch()
* is defined as an alias for a similar system specific RTL function.
*/
#ifndef WINDLL
#ifndef QDOS
* that supply a working `non-echo' getch() function for "raw" console input.
*/
char *getp(__G__ m, p, n)
__GDEF
ZCONST char *m;
char *p;
int n;
{
char c;
int i;
char *w;
w = "";
do {
fputs(w, stderr);
fputs(m, stderr);
fflush(stderr);
i = 0;
do {
if ((c = (char)getch()) == '\r')
c = '\n';
if (c == 8 || c == 127) {
if (i > 0) i--;
}
else if (i < n)
p[i++] = c;
} while (c != '\n');
PUTC('\n', stderr); fflush(stderr);
w = "(line too long--try again)\n";
} while (p[i-1] != '\n');
p[i-1] = 0;
return p;
}
#endif
#endif
#else
#if (defined(UNIX) || defined(__MINT__) || (defined(__BEOS__) || defined(__HAIKU__)))
#ifndef _PATH_TTY
# ifdef __MINT__
# define _PATH_TTY ttyname(2)
# else
# define _PATH_TTY "/dev/tty"
# endif
#endif
char *getp(__G__ m, p, n)
__GDEF
ZCONST char *m;
char *p;
int n;
{
char c;
int i;
char *w;
int f;
#ifdef PASSWD_FROM_STDIN
f = 0;
#else
if ((f = open(_PATH_TTY, 0)) == -1)
return NULL;
#endif
w = "";
do {
fputs(w, stderr);
fputs(m, stderr);
fflush(stderr);
i = 0;
echoff(f);
do {
read(f, &c, 1);
if (i < n)
p[i++] = c;
} while (c != '\n');
echon();
PUTC('\n', stderr); fflush(stderr);
w = "(line too long--try again)\n";
} while (p[i-1] != '\n');
p[i-1] = 0;
#ifndef PASSWD_FROM_STDIN
close(f);
#endif
return p;
}
#endif
#if (defined(VMS) || defined(CMS_MVS))
char *getp(__G__ m, p, n)
__GDEF
ZCONST char *m;
char *p;
int n;
{
char c;
int i;
char *w;
FILE *f;
#ifdef PASSWD_FROM_STDIN
f = stdin;
#else
if ((f = fopen(ctermid(NULL), "r")) == NULL)
return NULL;
#endif
fflush(stdout);
w = "";
do {
if (*w)
fputs(w, stderr);
fputs(m, stderr);
fflush(stderr);
i = 0;
echoff(f);
do {
if ((c = (char)getc(f)) == '\r')
c = '\n';
if (i < n)
p[i++] = c;
} while (c != '\n');
echon();
PUTC('\n', stderr); fflush(stderr);
w = "(line too long--try again)\n";
} while (p[i-1] != '\n');
p[i-1] = 0;
#ifndef PASSWD_FROM_STDIN
fclose(f);
#endif
return p;
}
#endif
#endif
#endif
#endif