ttyio.c
资源名称:unzip540.zip [点击查看]
上传用户:andy_li
上传日期:2007-01-06
资源大小:1019k
文件大小:18k
源码类别:
压缩解压
开发平台:
MultiPlatform
- /*---------------------------------------------------------------------------
- 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)
- screenlines() (Unix only)
- zgetch() (Unix and non-Unix versions)
- getp() ("PC," Unix/Atari/Be, VMS/VMCMS/MVS)
- ---------------------------------------------------------------------------*/
- #define __TTYIO_C /* identifies this source module */
- #include "zip.h"
- #include "crypt.h"
- #if (CRYPT || (defined(UNZIP) && !defined(FUNZIP)))
- /* Non-echo console/keyboard input is needed for (en/de)cryption's password
- * 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 /* used in Amiga system headers, maybe others too */
- # undef GLOBAL
- # endif
- # define GLOBAL(g) g
- #else
- # define GLOBAL(g) G.g
- #endif
- #ifdef __BEOS__ /* why yes, we do */
- # define HAVE_TERMIOS_H
- #endif
- #ifdef _POSIX_VERSION
- # ifndef USE_POSIX_TERMIOS
- # define USE_POSIX_TERMIOS /* use POSIX style termio (termios) */
- # endif
- # ifndef HAVE_TERMIOS_H
- # define HAVE_TERMIOS_H /* POSIX termios.h */
- # endif
- #endif /* _POSIX_VERSION */
- #ifdef UNZIP /* Zip handles this with the unix/configure script */
- # 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 /* !COHERENT */
- # ifdef HAVE_TERMIO_H
- # undef HAVE_TERMIO_H
- # endif
- # ifndef HAVE_SYS_TERMIO_H
- # define HAVE_SYS_TERMIO_H
- # endif
- # endif /* ?COHERENT */
- # endif /* (SYSV || CRAY) && !__MINT__ */
- # endif /* !_POSIX_VERSION */
- # if !(defined(BSD4_4) || defined(SYSV) || defined(__convexc__))
- # ifndef NO_FCNTL_H
- # define NO_FCNTL_H
- # endif
- # endif /* !(BSD4_4 || SYSV || __convexc__) */
- #endif /* UNZIP */
- #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
- /* include system support for switching of console echo */
- # ifdef VMS
- # include <descrip.h>
- # include <iodef.h>
- # include <ttdef.h>
- # include <starlet.h>
- # include <ssdef.h>
- # else /* !VMS */
- # 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 /* !HAVE_TERMIOS_H */
- # ifdef USE_SYSV_TERMIO /* Amdahl, Cray, all SysV? */
- # 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 /* !USE_SYSV_TERMIO */
- # 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 /* !CMS_MVS */
- # endif /* ?USE_SYSV_TERMIO */
- # endif /* ?HAVE_TERMIOS_H */
- # ifndef NO_FCNTL_H
- # ifndef UNZIP
- # include <fcntl.h>
- # endif
- # else
- char *ttyname OF((int));
- # endif
- # endif /* ?VMS */
- #endif /* !HAVE_WORKING_GETCH */
- #ifndef HAVE_WORKING_GETCH
- #ifdef VMS
- /*
- * 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
- */
- /* SKM: make global? */
- static struct dsc$descriptor_s DevDesc =
- {11, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$COMMAND"};
- /* {dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer}; */
- static short DevChan, iosb[4];
- static long status;
- static unsigned long oldmode[2], newmode[2]; /* each = 8 bytes */
- /* assign a channel to standard input */
- status = sys$assign(&DevDesc, &DevChan, 0, 0);
- if (!(status & 1))
- return status;
- /* use sys$qio and the IO$_SENSEMODE function to determine the current
- * 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,
- oldmode, 8, 0, 0, 0, 0);
- if (!(status & 1))
- return status;
- status = iosb[0];
- if (!(status & 1))
- return status;
- /* copy old mode into new-mode buffer, then modify to be either NOECHO or
- * ECHO (depending on function argument opt)
- */
- newmode[0] = oldmode[0];
- newmode[1] = oldmode[1];
- if (opt == 0) /* off */
- newmode[1] |= TT$M_NOECHO; /* set NOECHO bit */
- else
- newmode[1] &= ~((unsigned long) TT$M_NOECHO); /* clear NOECHO bit */
- /* use the IO$_SETMODE function to change the tty status */
- status = sys$qiow(0, DevChan, IO$_SETMODE, &iosb, 0, 0,
- newmode, 8, 0, 0, 0, 0);
- if (!(status & 1))
- return status;
- status = iosb[0];
- if (!(status & 1))
- return status;
- /* deassign the sys$input channel by way of clean-up */
- status = sys$dassgn(DevChan);
- if (!(status & 1))
- return status;
- return SS$_NORMAL; /* we be happy */
- } /* end function echo() */
- #else /* !VMS: basically Unix */
- /* For VM/CMS and MVS, non-echo terminal input is not (yet?) supported. */
- #ifndef CMS_MVS
- #ifdef ZIP /* moved to globals.h for UnZip */
- static int echofd=(-1); /* file descriptor whose echo is off */
- #endif
- /*
- * Turn echo off for file descriptor f. Assumes that f is a tty device.
- */
- void Echoff(__G__ f)
- __GDEF
- int f; /* file descriptor for which to turn echo off */
- {
- struct sgttyb sg; /* tty device structure */
- GLOBAL(echofd) = f;
- GTTY(f, &sg); /* get settings */
- sg.sg_flags &= ~ECHO; /* turn echo off */
- STTY(f, &sg);
- }
- /*
- * Turn echo back on for file descriptor echofd.
- */
- void Echon(__G)
- __GDEF
- {
- struct sgttyb sg; /* tty device structure */
- if (GLOBAL(echofd) != -1) {
- GTTY(GLOBAL(echofd), &sg); /* get settings */
- sg.sg_flags |= ECHO; /* turn echo on */
- STTY(GLOBAL(echofd), &sg);
- GLOBAL(echofd) = -1;
- }
- }
- #endif /* !CMS_MVS */
- #endif /* ?VMS */
- #if (defined(UNZIP) && !defined(FUNZIP))
- #if (defined(UNIX) || defined(__BEOS__))
- #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 screenlines()
- {
- struct winsize wsz;
- #ifdef DEBUG_WINSZ
- static int firsttime = TRUE;
- #endif
- /* see termio(4) under, e.g., SunOS */
- if (ioctl(1, TIOCGWINSZ, &wsz) == 0) {
- #ifdef DEBUG_WINSZ
- if (firsttime) {
- firsttime = FALSE;
- fprintf(stderr, "ttyio.c screenlines(): ws_row = %dn",
- wsz.ws_row);
- }
- #endif
- /* number of columns = ws_col */
- return (wsz.ws_row > 0)? wsz.ws_row : 24; /* number of rows */
- } else { /* this happens when piping to more(1), for example */
- #ifdef DEBUG_WINSZ
- if (firsttime) {
- firsttime = FALSE;
- fprintf(stderr,
- "ttyio.c screenlines(): ioctl(TIOCGWINSZ) failedn"));
- }
- #endif
- return 24; /* VT-100 assumed to be minimal hardware */
- }
- }
- #else /* !TIOCGWINSZ: service not available, fall back to semi-bogus method */
- int screenlines()
- {
- char *envptr, *getenv();
- int n;
- /* GRR: this is overly simplistic, but don't have access to stty/gtty
- * system anymore
- */
- envptr = getenv("LINES");
- if (envptr == (char *)NULL || (n = atoi(envptr)) < 5)
- return 24; /* VT-100 assumed to be minimal hardware */
- else
- return n;
- }
- #endif /* ?(TIOCGWINSZ && !M_UNIX) */
- #endif /* MORE */
- /*
- * Get a character from the given file descriptor without echo or newline.
- */
- int zgetch(__G__ f)
- __GDEF
- int f; /* file descriptor from which to read */
- {
- #if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
- char oldmin, oldtim;
- #endif
- char c;
- struct sgttyb sg; /* tty device structure */
- GTTY(f, &sg); /* get settings */
- #if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
- oldmin = sg.c_cc[VMIN]; /* save old values */
- oldtim = sg.c_cc[VTIME];
- sg.c_cc[VMIN] = 1; /* need only one char to return read() */
- sg.c_cc[VTIME] = 0; /* no timeout */
- sg.sg_flags &= ~ICANON; /* canonical mode off */
- #else
- sg.sg_flags |= CBREAK; /* cbreak mode on */
- #endif
- sg.sg_flags &= ~ECHO; /* turn echo off, too */
- STTY(f, &sg); /* set cbreak mode */
- GLOBAL(echofd) = f; /* in case ^C hit (not perfect: still CBREAK) */
- read(f, &c, 1); /* read our character */
- #if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
- sg.c_cc[VMIN] = oldmin; /* restore old values */
- sg.c_cc[VTIME] = oldtim;
- sg.sg_flags |= ICANON; /* canonical mode on */
- #else
- sg.sg_flags &= ~CBREAK; /* cbreak mode off */
- #endif
- sg.sg_flags |= ECHO; /* turn echo on */
- STTY(f, &sg); /* restore canonical mode */
- GLOBAL(echofd) = -1;
- return (int)c;
- }
- #else /* !UNIX && !__BEOS__ */
- int zgetch(__G__ f)
- __GDEF
- int f; /* file descriptor from which to read (must be open already) */
- {
- 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); /* throw away all other chars up thru newline */
- } while (c2 != 'n');
- echon();
- return (int)c;
- }
- #endif /* ?(UNIX || __BEOS__) */
- #endif /* UNZIP && !FUNZIP */
- #endif /* !HAVE_WORKING_GETCH */
- #if CRYPT /* getp() is only used with full encryption */
- /*
- * 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 /* WINDLL does not support a console interface */
- #ifndef QDOS /* QDOS supplies a variant of this function */
- /* This is the getp() function for all systems (with TTY type user interface)
- * that supply a working `non-echo' getch() function for "raw" console input.
- */
- char *getp(__G__ m, p, n)
- __GDEF
- ZCONST char *m; /* prompt for password */
- char *p; /* return value: line input */
- int n; /* bytes available in p[] */
- {
- char c; /* one-byte buffer for read() to use */
- int i; /* number of characters input */
- char *w; /* warning on retry */
- /* get password */
- w = "";
- do {
- fputs(w, stderr); /* warning if back again */
- fputs(m, stderr); /* display prompt and flush */
- fflush(stderr);
- i = 0;
- do { /* read line, keeping first n characters */
- if ((c = (char)getch()) == 'r')
- c = 'n'; /* until user hits CR */
- if (c == 8 || c == 127) {
- if (i > 0) i--; /* the `backspace' and `del' keys works */
- }
- else if (i < n)
- p[i++] = c; /* truncate past n */
- } while (c != 'n');
- PUTC('n', stderr); fflush(stderr);
- w = "(line too long--try again)n";
- } while (p[i-1] != 'n');
- p[i-1] = 0; /* terminate at newline */
- return p; /* return pointer to password */
- } /* end function getp() */
- #endif /* !QDOS */
- #endif /* !WINDLL */
- #else /* !HAVE_WORKING_GETCH */
- #if (defined(UNIX) || defined(__MINT__) || defined(__BEOS__))
- #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; /* prompt for password */
- char *p; /* return value: line input */
- int n; /* bytes available in p[] */
- {
- char c; /* one-byte buffer for read() to use */
- int i; /* number of characters input */
- char *w; /* warning on retry */
- int f; /* file descriptor for tty device */
- #ifdef PASSWD_FROM_STDIN
- /* Read from stdin. This is unsafe if the password is stored on disk. */
- f = 0;
- #else
- /* turn off echo on tty */
- if ((f = open(_PATH_TTY, 0)) == -1)
- return NULL;
- #endif
- /* get password */
- w = "";
- do {
- fputs(w, stderr); /* warning if back again */
- fputs(m, stderr); /* prompt */
- fflush(stderr);
- i = 0;
- echoff(f);
- do { /* read line, keeping n */
- 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; /* terminate at newline */
- #ifndef PASSWD_FROM_STDIN
- close(f);
- #endif
- return p; /* return pointer to password */
- } /* end function getp() */
- #endif /* UNIX || __MINT__ || __BEOS__ */
- #if (defined(VMS) || defined(CMS_MVS))
- char *getp(__G__ m, p, n)
- __GDEF
- ZCONST char *m; /* prompt for password */
- char *p; /* return value: line input */
- int n; /* bytes available in p[] */
- {
- char c; /* one-byte buffer for read() to use */
- int i; /* number of characters input */
- char *w; /* warning on retry */
- FILE *f; /* file structure for SYS$COMMAND device */
- #ifdef PASSWD_FROM_STDIN
- f = stdin;
- #else
- if ((f = fopen(ctermid(NULL), "r")) == NULL)
- return NULL;
- #endif
- /* get password */
- fflush(stdout);
- w = "";
- do {
- if (*w) /* bug: VMS apparently adds n to NULL fputs */
- fputs(w, stderr); /* warning if back again */
- fputs(m, stderr); /* prompt */
- fflush(stderr);
- i = 0;
- echoff(f);
- do { /* read line, keeping n */
- 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; /* terminate at newline */
- #ifndef PASSWD_FROM_STDIN
- fclose(f);
- #endif
- return p; /* return pointer to password */
- } /* end function getp() */
- #endif /* VMS || CMS_MVS */
- #endif /* ?HAVE_WORKING_GETCH */
- #endif /* CRYPT */
- #endif /* CRYPT || (UNZIP && !FUNZIP) */