ttyio.c
上传用户:andy_li
上传日期:2007-01-06
资源大小:1019k
文件大小:18k
源码类别:

压缩解压

开发平台:

MultiPlatform

  1. /*---------------------------------------------------------------------------
  2.   ttyio.c
  3.   This file contains routines for doing console input/output, including code
  4.   for non-echoing input.  It is used by the encryption/decryption code but
  5.   does not contain any restricted code itself.  This file is shared between
  6.   Info-ZIP's Zip and UnZip.
  7.   Contains:  echo()         (VMS only)
  8.              Echon()        (Unix only)
  9.              Echoff()       (Unix only)
  10.              screenlines()  (Unix only)
  11.              zgetch()       (Unix and non-Unix versions)
  12.              getp()         ("PC," Unix/Atari/Be, VMS/VMCMS/MVS)
  13.   ---------------------------------------------------------------------------*/
  14. #define __TTYIO_C       /* identifies this source module */
  15. #include "zip.h"
  16. #include "crypt.h"
  17. #if (CRYPT || (defined(UNZIP) && !defined(FUNZIP)))
  18. /* Non-echo console/keyboard input is needed for (en/de)cryption's password
  19.  * entry, and for UnZip(SFX)'s MORE and Pause features.
  20.  * (The corresponding #endif is found at the end of this module.)
  21.  */
  22. #include "ttyio.h"
  23. #ifndef PUTC
  24. #  define PUTC putc
  25. #endif
  26. #ifdef ZIP
  27. #  ifdef GLOBAL          /* used in Amiga system headers, maybe others too */
  28. #    undef GLOBAL
  29. #  endif
  30. #  define GLOBAL(g) g
  31. #else
  32. #  define GLOBAL(g) G.g
  33. #endif
  34. #ifdef __BEOS__                /* why yes, we do */
  35. #  define HAVE_TERMIOS_H
  36. #endif
  37. #ifdef _POSIX_VERSION
  38. #  ifndef USE_POSIX_TERMIOS
  39. #    define USE_POSIX_TERMIOS  /* use POSIX style termio (termios) */
  40. #  endif
  41. #  ifndef HAVE_TERMIOS_H
  42. #    define HAVE_TERMIOS_H     /* POSIX termios.h */
  43. #  endif
  44. #endif /* _POSIX_VERSION */
  45. #ifdef UNZIP            /* Zip handles this with the unix/configure script */
  46. #  ifndef _POSIX_VERSION
  47. #    if (defined(SYSV) || defined(CRAY)) &&  !defined(__MINT__)
  48. #      ifndef USE_SYSV_TERMIO
  49. #        define USE_SYSV_TERMIO
  50. #      endif
  51. #      ifdef COHERENT
  52. #        ifndef HAVE_TERMIO_H
  53. #          define HAVE_TERMIO_H
  54. #        endif
  55. #        ifdef HAVE_SYS_TERMIO_H
  56. #          undef HAVE_SYS_TERMIO_H
  57. #        endif
  58. #      else /* !COHERENT */
  59. #        ifdef HAVE_TERMIO_H
  60. #          undef HAVE_TERMIO_H
  61. #        endif
  62. #        ifndef HAVE_SYS_TERMIO_H
  63. #           define HAVE_SYS_TERMIO_H
  64. #        endif
  65. #      endif /* ?COHERENT */
  66. #    endif /* (SYSV || CRAY) && !__MINT__ */
  67. #  endif /* !_POSIX_VERSION */
  68. #  if !(defined(BSD4_4) || defined(SYSV) || defined(__convexc__))
  69. #    ifndef NO_FCNTL_H
  70. #      define NO_FCNTL_H
  71. #    endif
  72. #  endif /* !(BSD4_4 || SYSV || __convexc__) */
  73. #endif /* UNZIP */
  74. #ifdef HAVE_TERMIOS_H
  75. #  ifndef USE_POSIX_TERMIOS
  76. #    define USE_POSIX_TERMIOS
  77. #  endif
  78. #endif
  79. #if (defined(HAVE_TERMIO_H) || defined(HAVE_SYS_TERMIO_H))
  80. #  ifndef USE_SYSV_TERMIO
  81. #    define USE_SYSV_TERMIO
  82. #  endif
  83. #endif
  84. #if (defined(UNZIP) && !defined(FUNZIP) && defined(UNIX) && defined(MORE))
  85. #  include <sys/ioctl.h>
  86. #  define GOT_IOCTL_H
  87.    /* int ioctl OF((int, int, zvoid *));   GRR: may need for some systems */
  88. #endif
  89. #ifndef HAVE_WORKING_GETCH
  90.    /* include system support for switching of console echo */
  91. #  ifdef VMS
  92. #    include <descrip.h>
  93. #    include <iodef.h>
  94. #    include <ttdef.h>
  95. #    include <starlet.h>
  96. #    include <ssdef.h>
  97. #  else /* !VMS */
  98. #    ifdef HAVE_TERMIOS_H
  99. #      include <termios.h>
  100. #      define sgttyb termios
  101. #      define sg_flags c_lflag
  102. #      define GTTY(f, s) tcgetattr(f, (zvoid *) s)
  103. #      define STTY(f, s) tcsetattr(f, TCSAFLUSH, (zvoid *) s)
  104. #    else /* !HAVE_TERMIOS_H */
  105. #      ifdef USE_SYSV_TERMIO           /* Amdahl, Cray, all SysV? */
  106. #        ifdef HAVE_TERMIO_H
  107. #          include <termio.h>
  108. #        endif
  109. #        ifdef HAVE_SYS_TERMIO_H
  110. #          include <sys/termio.h>
  111. #        endif
  112. #        ifdef NEED_PTEM
  113. #          include <sys/stream.h>
  114. #          include <sys/ptem.h>
  115. #        endif
  116. #        define sgttyb termio
  117. #        define sg_flags c_lflag
  118. #        define GTTY(f,s) ioctl(f,TCGETA,(zvoid *)s)
  119. #        define STTY(f,s) ioctl(f,TCSETAW,(zvoid *)s)
  120. #      else /* !USE_SYSV_TERMIO */
  121. #        ifndef CMS_MVS
  122. #          if (!defined(MINIX) && !defined(GOT_IOCTL_H))
  123. #            include <sys/ioctl.h>
  124. #          endif
  125. #          include <sgtty.h>
  126. #          define GTTY gtty
  127. #          define STTY stty
  128. #          ifdef UNZIP
  129.              /*
  130.               * XXX : Are these declarations needed at all ????
  131.               */
  132.              /*
  133.               * GRR: let's find out...   Hmmm, appears not...
  134.              int gtty OF((int, struct sgttyb *));
  135.              int stty OF((int, struct sgttyb *));
  136.               */
  137. #          endif
  138. #        endif /* !CMS_MVS */
  139. #      endif /* ?USE_SYSV_TERMIO */
  140. #    endif /* ?HAVE_TERMIOS_H */
  141. #    ifndef NO_FCNTL_H
  142. #      ifndef UNZIP
  143. #        include <fcntl.h>
  144. #      endif
  145. #    else
  146.        char *ttyname OF((int));
  147. #    endif
  148. #  endif /* ?VMS */
  149. #endif /* !HAVE_WORKING_GETCH */
  150. #ifndef HAVE_WORKING_GETCH
  151. #ifdef VMS
  152. /*
  153.  * Turn keyboard echoing on or off (VMS).  Loosely based on VMSmunch.c
  154.  * and hence on Joe Meadows' file.c code.
  155.  */
  156. int echo(opt)
  157.     int opt;
  158. {
  159.     /*
  160.      * For VMS v5.x:
  161.      *   IO$_SENSEMODE/SETMODE info:  Programming, Vol. 7A, System Programming,
  162.      *     I/O User's: Part I, sec. 8.4.1.1, 8.4.3, 8.4.5, 8.6
  163.      *   sys$assign(), sys$qio() info:  Programming, Vol. 4B, System Services,
  164.      *     System Services Reference Manual, pp. sys-23, sys-379
  165.      *   fixed-length descriptor info:  Programming, Vol. 3, System Services,
  166.      *     Intro to System Routines, sec. 2.9.2
  167.      * Greg Roelofs, 15 Aug 91
  168.      */
  169.     /* SKM: make global? */
  170.     static struct dsc$descriptor_s DevDesc =
  171.         {11, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$COMMAND"};
  172.      /* {dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer}; */
  173.     static short           DevChan, iosb[4];
  174.     static long            status;
  175.     static unsigned long   oldmode[2], newmode[2];   /* each = 8 bytes */
  176.     /* assign a channel to standard input */
  177.     status = sys$assign(&DevDesc, &DevChan, 0, 0);
  178.     if (!(status & 1))
  179.         return status;
  180.     /* use sys$qio and the IO$_SENSEMODE function to determine the current
  181.      * tty status (for password reading, could use IO$_READVBLK function
  182.      * instead, but echo on/off will be more general)
  183.      */
  184.     status = sys$qiow(0, DevChan, IO$_SENSEMODE, &iosb, 0, 0,
  185.                      oldmode, 8, 0, 0, 0, 0);
  186.     if (!(status & 1))
  187.         return status;
  188.     status = iosb[0];
  189.     if (!(status & 1))
  190.         return status;
  191.     /* copy old mode into new-mode buffer, then modify to be either NOECHO or
  192.      * ECHO (depending on function argument opt)
  193.      */
  194.     newmode[0] = oldmode[0];
  195.     newmode[1] = oldmode[1];
  196.     if (opt == 0)   /* off */
  197.         newmode[1] |= TT$M_NOECHO;                      /* set NOECHO bit */
  198.     else
  199.         newmode[1] &= ~((unsigned long) TT$M_NOECHO);   /* clear NOECHO bit */
  200.     /* use the IO$_SETMODE function to change the tty status */
  201.     status = sys$qiow(0, DevChan, IO$_SETMODE, &iosb, 0, 0,
  202.                      newmode, 8, 0, 0, 0, 0);
  203.     if (!(status & 1))
  204.         return status;
  205.     status = iosb[0];
  206.     if (!(status & 1))
  207.         return status;
  208.     /* deassign the sys$input channel by way of clean-up */
  209.     status = sys$dassgn(DevChan);
  210.     if (!(status & 1))
  211.         return status;
  212.     return SS$_NORMAL;   /* we be happy */
  213. } /* end function echo() */
  214. #else /* !VMS:  basically Unix */
  215. /* For VM/CMS and MVS, non-echo terminal input is not (yet?) supported. */
  216. #ifndef CMS_MVS
  217. #ifdef ZIP                      /* moved to globals.h for UnZip */
  218.    static int echofd=(-1);      /* file descriptor whose echo is off */
  219. #endif
  220. /*
  221.  * Turn echo off for file descriptor f.  Assumes that f is a tty device.
  222.  */
  223. void Echoff(__G__ f)
  224.     __GDEF
  225.     int f;                    /* file descriptor for which to turn echo off */
  226. {
  227.     struct sgttyb sg;         /* tty device structure */
  228.     GLOBAL(echofd) = f;
  229.     GTTY(f, &sg);             /* get settings */
  230.     sg.sg_flags &= ~ECHO;     /* turn echo off */
  231.     STTY(f, &sg);
  232. }
  233. /*
  234.  * Turn echo back on for file descriptor echofd.
  235.  */
  236. void Echon(__G)
  237.     __GDEF
  238. {
  239.     struct sgttyb sg;         /* tty device structure */
  240.     if (GLOBAL(echofd) != -1) {
  241.         GTTY(GLOBAL(echofd), &sg);    /* get settings */
  242.         sg.sg_flags |= ECHO;  /* turn echo on */
  243.         STTY(GLOBAL(echofd), &sg);
  244.         GLOBAL(echofd) = -1;
  245.     }
  246. }
  247. #endif /* !CMS_MVS */
  248. #endif /* ?VMS */
  249. #if (defined(UNZIP) && !defined(FUNZIP))
  250. #if (defined(UNIX) || defined(__BEOS__))
  251. #ifdef MORE
  252. /*
  253.  * Get the number of lines on the output terminal.  SCO Unix apparently
  254.  * defines TIOCGWINSZ but doesn't support it (!M_UNIX).
  255.  *
  256.  * GRR:  will need to know width of terminal someday, too, to account for
  257.  *       line-wrapping.
  258.  */
  259. #if (defined(TIOCGWINSZ) && !defined(M_UNIX))
  260. int screenlines()
  261. {
  262.     struct winsize wsz;
  263. #ifdef DEBUG_WINSZ
  264.     static int firsttime = TRUE;
  265. #endif
  266.     /* see termio(4) under, e.g., SunOS */
  267.     if (ioctl(1, TIOCGWINSZ, &wsz) == 0) {
  268. #ifdef DEBUG_WINSZ
  269.         if (firsttime) {
  270.             firsttime = FALSE;
  271.             fprintf(stderr, "ttyio.c screenlines():  ws_row = %dn",
  272.               wsz.ws_row);
  273.         }
  274. #endif
  275.         /* number of columns = ws_col */
  276.         return (wsz.ws_row > 0)? wsz.ws_row : 24;   /* number of rows */
  277.     } else {         /* this happens when piping to more(1), for example */
  278. #ifdef DEBUG_WINSZ
  279.         if (firsttime) {
  280.             firsttime = FALSE;
  281.             fprintf(stderr,
  282.               "ttyio.c screenlines():  ioctl(TIOCGWINSZ) failedn"));
  283.         }
  284. #endif
  285.         return 24;   /* VT-100 assumed to be minimal hardware */
  286.     }
  287. }
  288. #else /* !TIOCGWINSZ: service not available, fall back to semi-bogus method */
  289. int screenlines()
  290. {
  291.     char *envptr, *getenv();
  292.     int n;
  293.     /* GRR:  this is overly simplistic, but don't have access to stty/gtty
  294.      * system anymore
  295.      */
  296.     envptr = getenv("LINES");
  297.     if (envptr == (char *)NULL || (n = atoi(envptr)) < 5)
  298.         return 24;   /* VT-100 assumed to be minimal hardware */
  299.     else
  300.         return n;
  301. }
  302. #endif /* ?(TIOCGWINSZ && !M_UNIX) */
  303. #endif /* MORE */
  304. /*
  305.  * Get a character from the given file descriptor without echo or newline.
  306.  */
  307. int zgetch(__G__ f)
  308.     __GDEF
  309.     int f;                      /* file descriptor from which to read */
  310. {
  311. #if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
  312.     char oldmin, oldtim;
  313. #endif
  314.     char c;
  315.     struct sgttyb sg;           /* tty device structure */
  316.     GTTY(f, &sg);               /* get settings */
  317. #if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
  318.     oldmin = sg.c_cc[VMIN];     /* save old values */
  319.     oldtim = sg.c_cc[VTIME];
  320.     sg.c_cc[VMIN] = 1;          /* need only one char to return read() */
  321.     sg.c_cc[VTIME] = 0;         /* no timeout */
  322.     sg.sg_flags &= ~ICANON;     /* canonical mode off */
  323. #else
  324.     sg.sg_flags |= CBREAK;      /* cbreak mode on */
  325. #endif
  326.     sg.sg_flags &= ~ECHO;       /* turn echo off, too */
  327.     STTY(f, &sg);               /* set cbreak mode */
  328.     GLOBAL(echofd) = f;         /* in case ^C hit (not perfect: still CBREAK) */
  329.     read(f, &c, 1);             /* read our character */
  330. #if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
  331.     sg.c_cc[VMIN] = oldmin;     /* restore old values */
  332.     sg.c_cc[VTIME] = oldtim;
  333.     sg.sg_flags |= ICANON;      /* canonical mode on */
  334. #else
  335.     sg.sg_flags &= ~CBREAK;     /* cbreak mode off */
  336. #endif
  337.     sg.sg_flags |= ECHO;        /* turn echo on */
  338.     STTY(f, &sg);               /* restore canonical mode */
  339.     GLOBAL(echofd) = -1;
  340.     return (int)c;
  341. }
  342. #else /* !UNIX && !__BEOS__ */
  343. int zgetch(__G__ f)
  344.     __GDEF
  345.     int f;    /* file descriptor from which to read (must be open already) */
  346. {
  347.     char c, c2;
  348. /*---------------------------------------------------------------------------
  349.     Get a character from the given file descriptor without echo; can't fake
  350.     CBREAK mode (i.e., newline required), but can get rid of all chars up to
  351.     and including newline.
  352.   ---------------------------------------------------------------------------*/
  353.     echoff(f);
  354.     read(f, &c, 1);
  355.     if (c != 'n')
  356.         do {
  357.             read(f, &c2, 1);   /* throw away all other chars up thru newline */
  358.         } while (c2 != 'n');
  359.     echon();
  360.     return (int)c;
  361. }
  362. #endif /* ?(UNIX || __BEOS__) */
  363. #endif /* UNZIP && !FUNZIP */
  364. #endif /* !HAVE_WORKING_GETCH */
  365. #if CRYPT                       /* getp() is only used with full encryption */
  366. /*
  367.  * Simple compile-time check for source compatibility between
  368.  * zcrypt and ttyio:
  369.  */
  370. #if (!defined(CR_MAJORVER) || (CR_MAJORVER < 2) || (CR_MINORVER < 7))
  371.    error:  This Info-ZIP tool requires zcrypt 2.7 or later.
  372. #endif
  373. /*
  374.  * Get a password of length n-1 or less into *p using the prompt *m.
  375.  * The entered password is not echoed.
  376.  */
  377. #ifdef HAVE_WORKING_GETCH
  378. /*
  379.  * For the AMIGA, getch() is defined as Agetch(), which is in
  380.  * amiga/filedate.c; SAS/C 6.x provides a getch(), but since Agetch()
  381.  * uses the infrastructure that is already in place in filedate.c, it is
  382.  * smaller.  With this function, echoff() and echon() are not needed.
  383.  *
  384.  * For the MAC, a non-echo macgetch() function is defined in the MacOS
  385.  * specific sources which uses the event handling mechanism of the
  386.  * desktop window manager to get a character from the keyboard.
  387.  *
  388.  * For the other systems in this section, a non-echo getch() function
  389.  * is either contained the C runtime library (conio package), or getch()
  390.  * is defined as an alias for a similar system specific RTL function.
  391.  */
  392. #ifndef WINDLL   /* WINDLL does not support a console interface */
  393. #ifndef QDOS     /* QDOS supplies a variant of this function */
  394. /* This is the getp() function for all systems (with TTY type user interface)
  395.  * that supply a working `non-echo' getch() function for "raw" console input.
  396.  */
  397. char *getp(__G__ m, p, n)
  398.     __GDEF
  399.     ZCONST char *m;             /* prompt for password */
  400.     char *p;                    /* return value: line input */
  401.     int n;                      /* bytes available in p[] */
  402. {
  403.     char c;                     /* one-byte buffer for read() to use */
  404.     int i;                      /* number of characters input */
  405.     char *w;                    /* warning on retry */
  406.     /* get password */
  407.     w = "";
  408.     do {
  409.         fputs(w, stderr);       /* warning if back again */
  410.         fputs(m, stderr);       /* display prompt and flush */
  411.         fflush(stderr);
  412.         i = 0;
  413.         do {                    /* read line, keeping first n characters */
  414.             if ((c = (char)getch()) == 'r')
  415.                 c = 'n';       /* until user hits CR */
  416.             if (c == 8 || c == 127) {
  417.                 if (i > 0) i--; /* the `backspace' and `del' keys works */
  418.             }
  419.             else if (i < n)
  420.                 p[i++] = c;     /* truncate past n */
  421.         } while (c != 'n');
  422.         PUTC('n', stderr);  fflush(stderr);
  423.         w = "(line too long--try again)n";
  424.     } while (p[i-1] != 'n');
  425.     p[i-1] = 0;                 /* terminate at newline */
  426.     return p;                   /* return pointer to password */
  427. } /* end function getp() */
  428. #endif /* !QDOS */
  429. #endif /* !WINDLL */
  430. #else /* !HAVE_WORKING_GETCH */
  431. #if (defined(UNIX) || defined(__MINT__) || defined(__BEOS__))
  432. #ifndef _PATH_TTY
  433. #  ifdef __MINT__
  434. #    define _PATH_TTY ttyname(2)
  435. #  else
  436. #    define _PATH_TTY "/dev/tty"
  437. #  endif
  438. #endif
  439. char *getp(__G__ m, p, n)
  440.     __GDEF
  441.     ZCONST char *m;             /* prompt for password */
  442.     char *p;                    /* return value: line input */
  443.     int n;                      /* bytes available in p[] */
  444. {
  445.     char c;                     /* one-byte buffer for read() to use */
  446.     int i;                      /* number of characters input */
  447.     char *w;                    /* warning on retry */
  448.     int f;                      /* file descriptor for tty device */
  449. #ifdef PASSWD_FROM_STDIN
  450.     /* Read from stdin. This is unsafe if the password is stored on disk. */
  451.     f = 0;
  452. #else
  453.     /* turn off echo on tty */
  454.     if ((f = open(_PATH_TTY, 0)) == -1)
  455.         return NULL;
  456. #endif
  457.     /* get password */
  458.     w = "";
  459.     do {
  460.         fputs(w, stderr);       /* warning if back again */
  461.         fputs(m, stderr);       /* prompt */
  462.         fflush(stderr);
  463.         i = 0;
  464.         echoff(f);
  465.         do {                    /* read line, keeping n */
  466.             read(f, &c, 1);
  467.             if (i < n)
  468.                 p[i++] = c;
  469.         } while (c != 'n');
  470.         echon();
  471.         PUTC('n', stderr);  fflush(stderr);
  472.         w = "(line too long--try again)n";
  473.     } while (p[i-1] != 'n');
  474.     p[i-1] = 0;                 /* terminate at newline */
  475. #ifndef PASSWD_FROM_STDIN
  476.     close(f);
  477. #endif
  478.     return p;                   /* return pointer to password */
  479. } /* end function getp() */
  480. #endif /* UNIX || __MINT__ || __BEOS__ */
  481. #if (defined(VMS) || defined(CMS_MVS))
  482. char *getp(__G__ m, p, n)
  483.     __GDEF
  484.     ZCONST char *m;             /* prompt for password */
  485.     char *p;                    /* return value: line input */
  486.     int n;                      /* bytes available in p[] */
  487. {
  488.     char c;                     /* one-byte buffer for read() to use */
  489.     int i;                      /* number of characters input */
  490.     char *w;                    /* warning on retry */
  491.     FILE *f;                    /* file structure for SYS$COMMAND device */
  492. #ifdef PASSWD_FROM_STDIN
  493.     f = stdin;
  494. #else
  495.     if ((f = fopen(ctermid(NULL), "r")) == NULL)
  496.         return NULL;
  497. #endif
  498.     /* get password */
  499.     fflush(stdout);
  500.     w = "";
  501.     do {
  502.         if (*w)                 /* bug: VMS apparently adds n to NULL fputs */
  503.             fputs(w, stderr);   /* warning if back again */
  504.         fputs(m, stderr);       /* prompt */
  505.         fflush(stderr);
  506.         i = 0;
  507.         echoff(f);
  508.         do {                    /* read line, keeping n */
  509.             if ((c = (char)getc(f)) == 'r')
  510.                 c = 'n';
  511.             if (i < n)
  512.                 p[i++] = c;
  513.         } while (c != 'n');
  514.         echon();
  515.         PUTC('n', stderr);  fflush(stderr);
  516.         w = "(line too long--try again)n";
  517.     } while (p[i-1] != 'n');
  518.     p[i-1] = 0;                 /* terminate at newline */
  519. #ifndef PASSWD_FROM_STDIN
  520.     fclose(f);
  521. #endif
  522.     return p;                   /* return pointer to password */
  523. } /* end function getp() */
  524. #endif /* VMS || CMS_MVS */
  525. #endif /* ?HAVE_WORKING_GETCH */
  526. #endif /* CRYPT */
  527. #endif /* CRYPT || (UNZIP && !FUNZIP) */