home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip540.zip / ttyio.c < prev    next >
C/C++ Source or Header  |  1998-10-27  |  19KB  |  626 lines

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