ttyio.c 20 KB

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