]> git.saurik.com Git - wxWidgets.git/blame - utils/Install/sfxzip/ttyio.c
checked in forgottern parts of MSLU changes
[wxWidgets.git] / utils / Install / sfxzip / ttyio.c
CommitLineData
f6bcfd97
BP
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 */
177int 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 */
259void 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 */
274void 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
306int 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
339int 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 */
361int 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
405int 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 */
470char *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
522char *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
575char *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) */