1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-11-10 21:38:50 +01:00
gnupg/util/ttyio.c

331 lines
7.1 KiB
C
Raw Normal View History

1997-11-18 15:06:00 +01:00
/* ttyio.c - tty i/O functions
1998-02-24 19:50:46 +01:00
* Copyright (C) 1998 Free Software Foundation, Inc.
1997-11-18 15:06:00 +01:00
*
1998-02-24 19:50:46 +01:00
* This file is part of GNUPG.
1997-11-18 15:06:00 +01:00
*
1998-02-24 19:50:46 +01:00
* GNUPG is free software; you can redistribute it and/or modify
1997-11-18 15:06:00 +01:00
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
1998-02-24 19:50:46 +01:00
* GNUPG is distributed in the hope that it will be useful,
1997-11-18 15:06:00 +01:00
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
1998-01-16 22:15:24 +01:00
#include <unistd.h>
1998-01-05 20:13:15 +01:00
#ifdef HAVE_TCGETATTR
#include <termios.h>
#endif
1998-02-24 19:50:46 +01:00
#ifdef __MINGW32__ /* use the odd Win32 functions */
#include <windows.h>
#ifdef HAVE_TCGETATTR
#error mingw32 and termios
#endif
#endif
1997-11-18 15:06:00 +01:00
#include <errno.h>
#include <ctype.h>
#include "util.h"
#include "memory.h"
#include "ttyio.h"
1998-02-24 19:50:46 +01:00
#ifdef __MINGW32__ /* use the odd Win32 functions */
static struct {
HANDLE in, out;
} con;
#define DEF_INPMODE (ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT \
|ENABLE_PROCESSED_INPUT )
#define HID_INPMODE (ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT )
#define DEF_OUTMODE (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT)
#else /* yeah, we have a real OS */
1998-01-02 21:40:10 +01:00
static FILE *ttyfp = NULL;
1998-02-24 19:50:46 +01:00
#endif
static int initialized;
1997-11-18 15:06:00 +01:00
static int last_prompt_len;
1998-02-24 19:50:46 +01:00
1998-01-02 21:40:10 +01:00
static void
init_ttyfp()
1997-11-18 15:06:00 +01:00
{
1998-02-24 19:50:46 +01:00
if( initialized )
1998-01-02 21:40:10 +01:00
return;
1997-12-31 13:32:54 +01:00
1998-01-06 10:17:55 +01:00
#if defined(__MINGW32__)
1998-02-24 19:50:46 +01:00
{
SECURITY_ATTRIBUTES sa;
memset(&sa, 0, sizeof(sa));
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
con.out = CreateFileA( "CONOUT$", GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
&sa, OPEN_EXISTING, 0, 0 );
if( con.out == INVALID_HANDLE_VALUE )
log_fatal("open(CONOUT$) failed: rc=%d", (int)GetLastError() );
memset(&sa, 0, sizeof(sa));
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
con.in = CreateFileA( "CONIN$", GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
&sa, OPEN_EXISTING, 0, 0 );
if( con.in == INVALID_HANDLE_VALUE )
log_fatal("open(CONIN$) failed: rc=%d", (int)GetLastError() );
}
SetConsoleMode(con.in, DEF_INPMODE );
SetConsoleMode(con.out, DEF_OUTMODE );
1998-01-06 10:17:55 +01:00
#else
1998-01-02 21:40:10 +01:00
ttyfp = fopen("/dev/tty", "r+");
if( !ttyfp )
1997-11-18 15:06:00 +01:00
log_fatal("cannot open /dev/tty: %s\n", strerror(errno) );
1998-02-24 19:50:46 +01:00
#endif
initialized = 1;
1997-11-18 15:06:00 +01:00
}
void
tty_printf( const char *fmt, ... )
{
va_list arg_ptr;
1998-02-24 19:50:46 +01:00
if( !initialized )
1998-01-02 21:40:10 +01:00
init_ttyfp();
1997-11-18 15:06:00 +01:00
va_start( arg_ptr, fmt ) ;
1998-02-24 19:50:46 +01:00
#ifdef __MINGW32__
{ static char *buf;
static size_t bufsize;
int n;
DWORD nwritten;
#if 0 /* the dox say, that there is a snprintf, but I didn't found
* it, so we use a static buffer for now */
do {
if( n == -1 || !buf ) {
m_free(buf);
bufsize += 200;
/* better check the new size; (we use M$ functions) */
if( bufsize > 50000 )
log_bug("vsnprintf probably failed\n");
buf = m_alloc( bufsize );
}
n = _vsnprintf(buf, bufsize-1, fmt, arg_ptr);
} while( n == -1 );
#else
if( !buf ) {
bufsize += 1000;
buf = m_alloc( bufsize );
}
n = vsprintf(buf, fmt, arg_ptr);
if( n == -1 )
log_bug("vsprintf() failed\n");
#endif
if( !WriteConsoleA( con.out, buf, n, &nwritten, NULL ) )
log_fatal("WriteConsole failed: rc=%d", (int)GetLastError() );
if( n != nwritten )
log_fatal("WriteConsole failed: %d != %ld\n", n, nwritten );
last_prompt_len += n;
}
#else
1998-01-02 21:40:10 +01:00
last_prompt_len += vfprintf(ttyfp,fmt,arg_ptr) ;
fflush(ttyfp);
1998-02-24 19:50:46 +01:00
#endif
va_end(arg_ptr);
1997-11-18 15:06:00 +01:00
}
1997-12-16 20:15:09 +01:00
/****************
* Print a string, but filter all control characters out.
*/
void
tty_print_string( byte *p, size_t n )
{
1998-02-24 19:50:46 +01:00
if( !initialized )
1998-01-02 21:40:10 +01:00
init_ttyfp();
1998-02-24 19:50:46 +01:00
#ifdef __MINGW32__
/* not so effective, change it if you want */
for( ; n; n--, p++ )
if( iscntrl( *p ) ) {
if( *p == '\n' )
tty_printf("\\n");
else if( !*p )
tty_printf("\\0");
else
tty_printf("\\x%02x", *p);
}
else
tty_printf("%c", *p);
#else
1997-12-16 20:15:09 +01:00
for( ; n; n--, p++ )
if( iscntrl( *p ) ) {
1998-01-02 21:40:10 +01:00
putc('\\', ttyfp);
1997-12-16 20:15:09 +01:00
if( *p == '\n' )
1998-01-02 21:40:10 +01:00
putc('n', ttyfp);
1997-12-16 20:15:09 +01:00
else if( !*p )
1998-01-02 21:40:10 +01:00
putc('0', ttyfp);
1997-12-16 20:15:09 +01:00
else
1998-01-02 21:40:10 +01:00
fprintf(ttyfp, "x%02x", *p );
1997-12-16 20:15:09 +01:00
}
else
1998-01-02 21:40:10 +01:00
putc(*p, ttyfp);
1998-02-24 19:50:46 +01:00
#endif
1997-12-16 20:15:09 +01:00
}
1997-12-31 13:32:54 +01:00
static char *
do_get( const char *prompt, int hidden )
1997-11-18 15:06:00 +01:00
{
char *buf;
1998-01-02 21:40:10 +01:00
byte cbuf[1];
1997-11-18 15:06:00 +01:00
int c, n, i;
1998-01-05 20:13:15 +01:00
#ifdef HAVE_TCGETATTR
1997-12-31 13:32:54 +01:00
struct termios termsave;
1998-01-05 20:13:15 +01:00
#endif
1997-11-18 15:06:00 +01:00
1998-02-24 19:50:46 +01:00
if( !initialized )
1998-01-02 21:40:10 +01:00
init_ttyfp();
1997-11-18 15:06:00 +01:00
last_prompt_len = 0;
tty_printf( prompt );
buf = m_alloc(n=50);
i = 0;
1998-01-02 21:40:10 +01:00
1998-02-24 19:50:46 +01:00
#if __MINGW32__ /* windoze version */
if( hidden )
SetConsoleMode(con.in, HID_INPMODE );
for(;;) {
DWORD nread;
if( !ReadConsoleA( con.in, cbuf, 1, &nread, NULL ) )
log_fatal("ReadConsole failed: rc=%d", (int)GetLastError() );
if( !nread )
continue;
if( *cbuf == '\n' )
break;
if( !hidden )
last_prompt_len++;
c = *cbuf;
if( c == '\t' )
c = ' ';
1998-06-26 11:45:36 +02:00
else if( c > 0xa0 )
; /* we don't allow 0xa0, as this is a protected blank which may
* confuse the user */
1998-02-24 19:50:46 +01:00
else if( iscntrl(c) )
continue;
if( !(i < n-1) ) {
n += 50;
buf = m_realloc( buf, n );
}
buf[i++] = c;
}
if( hidden )
SetConsoleMode(con.in, DEF_INPMODE );
#else /* unix version */
1998-01-02 21:40:10 +01:00
if( hidden ) {
1998-01-05 20:13:15 +01:00
#ifdef HAVE_TCGETATTR
1998-01-02 21:40:10 +01:00
struct termios term;
if( tcgetattr(fileno(ttyfp), &termsave) )
log_fatal("tcgetattr() failed: %s\n", strerror(errno) );
term = termsave;
term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
if( tcsetattr( fileno(ttyfp), TCSAFLUSH, &term ) )
log_fatal("tcsetattr() failed: %s\n", strerror(errno) );
1998-01-05 20:13:15 +01:00
#endif
1998-01-02 21:40:10 +01:00
}
/* fixme: How can we avoid that the \n is echoed w/o disabling
* canonical mode - w/o this kill_prompt can't work */
while( read(fileno(ttyfp), cbuf, 1) == 1 && *cbuf != '\n' ) {
if( !hidden )
last_prompt_len++;
c = *cbuf;
1997-11-18 15:06:00 +01:00
if( c == '\t' )
c = ' ';
1998-06-26 11:45:36 +02:00
else if( c > 0xa0 )
; /* we don't allow 0xa0, as this is a protected blank which may
* confuse the user */
1997-11-18 15:06:00 +01:00
else if( iscntrl(c) )
continue;
if( !(i < n-1) ) {
n += 50;
buf = m_realloc( buf, n );
}
buf[i++] = c;
}
1998-01-02 21:40:10 +01:00
1998-01-05 20:13:15 +01:00
1998-01-02 21:40:10 +01:00
if( hidden ) {
1998-01-05 20:13:15 +01:00
#ifdef HAVE_TCGETATTR
1998-01-02 21:40:10 +01:00
if( tcsetattr(fileno(ttyfp), TCSAFLUSH, &termsave) )
log_error("tcsetattr() failed: %s\n", strerror(errno) );
1998-01-05 20:13:15 +01:00
#endif
1998-01-02 21:40:10 +01:00
}
1998-02-24 19:50:46 +01:00
#endif /* end unix version */
1997-11-18 15:06:00 +01:00
buf[i] = 0;
return buf;
}
1997-12-31 13:32:54 +01:00
char *
tty_get( const char *prompt )
{
return do_get( prompt, 0 );
}
1997-11-18 15:06:00 +01:00
char *
tty_get_hidden( const char *prompt )
{
1997-12-31 13:32:54 +01:00
return do_get( prompt, 1 );
1997-11-18 15:06:00 +01:00
}
void
tty_kill_prompt()
{
1998-01-02 21:40:10 +01:00
1998-02-24 19:50:46 +01:00
if( !initialized )
1998-01-02 21:40:10 +01:00
init_ttyfp();
if( !last_prompt_len )
return;
1998-02-24 19:50:46 +01:00
#if __MINGW32__
tty_printf("\r%*s\r", last_prompt_len, "");
#else
{
int i;
putc('\r', ttyfp);
for(i=0; i < last_prompt_len; i ++ )
putc(' ', ttyfp);
putc('\r', ttyfp);
fflush(ttyfp);
}
#endif
1997-11-18 15:06:00 +01:00
last_prompt_len = 0;
}