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