Remove support for RISCOS from dotlock.c
[gnupg.git] / common / ttyio.c
index fd74800..fb0fd5e 100644 (file)
@@ -1,11 +1,12 @@
 /* ttyio.c -  tty i/O functions
- * Copyright (C) 1998,1999,2000,2001,2002,2003 Free Software Foundation, Inc.
+ * Copyright (C) 1998,1999,2000,2001,2002,2003,2004,2006,2007,
+ *               2009, 2010 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -14,8 +15,7 @@
  * 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
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <string.h>
 #include <stdarg.h>
 #include <unistd.h>
+
+#if defined(HAVE_W32_SYSTEM) && !defined(HAVE_W32CE_SYSTEM)
+# define USE_W32_CONSOLE 1
+#endif
+
 #ifdef HAVE_TCGETATTR
 #include <termios.h>
 #else
 #define HAVE_TCGETATTR
 #endif
 #endif
-#ifdef __MINGW32__ /* use the odd Win32 functions */
-#include <windows.h>
-#ifdef HAVE_TCGETATTR
-#error mingw32 and termios
-#endif
+#ifdef USE_W32_CONSOLE
+# include <windows.h>
+# ifdef HAVE_TCGETATTR
+#  error mingw32 and termios
+# endif
 #endif
 #include <errno.h>
 #include <ctype.h>
+
 #include "util.h"
-#include "memory.h"
 #include "ttyio.h"
+#include "common-defs.h"
 
 #define CONTROL_D ('D' - 'A' + 1)
 
-#ifdef __MINGW32__ /* use the odd Win32 functions */
+
+#ifdef USE_W32_CONSOLE
 static struct {
     HANDLE in, out;
 } con;
@@ -74,6 +81,13 @@ static int no_terminal;
     static int restore_termios;
 #endif
 
+/* Hooks set by gpgrlhelp.c if required. */
+static void (*my_rl_set_completer) (rl_completion_func_t *);
+static void (*my_rl_inhibit_completion) (int);
+static void (*my_rl_cleanup_after_signal) (void);
+static void (*my_rl_init_stream) (FILE *);
+static char *(*my_rl_readline) (const char*);
+static void (*my_rl_add_history) (const char*);
 
 
 /* This is a wrapper around ttyname so that we can use it even when
@@ -93,14 +107,22 @@ tty_get_ttyname (void)
   if (!got_name)
     {
       const char *s;
+      /* Note that despite our checks for these macros the function is
+         not necessarily thread save.  We mainly do this for
+         portability reasons, in case L_ctermid is not defined. */
+# if defined(_POSIX_THREAD_SAFE_FUNCTIONS) || defined(_POSIX_TRHEADS)
+      char buffer[L_ctermid];
+      s = ctermid (buffer);
+# else
       s = ctermid (NULL);
+# endif
       if (s)
         name = strdup (s);
       got_name = 1;
     }
-#endif
-  /* Assume the staandrd tty on memory error or when tehre is no
-     certmid. */
+#endif /*HAVE_CTERMID*/
+  /* Assume the standard tty on memory error or when tehre is no
+     ctermid. */
   return name? name : "/dev/tty";
 }
 
@@ -124,7 +146,7 @@ init_ttyfp(void)
     if( initialized )
        return;
 
-#if defined(__MINGW32__)
+#if defined(USE_W32_CONSOLE)
     {
        SECURITY_ATTRIBUTES sa;
 
@@ -150,6 +172,10 @@ init_ttyfp(void)
 
 #elif defined(__EMX__)
     ttyfp = stdout; /* Fixme: replace by the real functions: see wklib */
+    if (my_rl_init_stream)
+      my_rl_init_stream (ttyfp);
+#elif defined (HAVE_W32CE_SYSTEM)
+    ttyfp = stderr;
 #else
     ttyfp = batchmode? stderr : fopen (tty_get_ttyname (), "r+");
     if( !ttyfp ) {
@@ -157,7 +183,11 @@ init_ttyfp(void)
                   strerror(errno) );
        exit(2);
     }
+    if (my_rl_init_stream)
+      my_rl_init_stream (ttyfp);
 #endif
+
+
 #ifdef HAVE_TCGETATTR
     atexit( cleanup );
 #endif
@@ -194,8 +224,8 @@ tty_printf( const char *fmt, ... )
        init_ttyfp();
 
     va_start( arg_ptr, fmt ) ;
-#ifdef __MINGW32__
-    {   
+#ifdef USE_W32_CONSOLE
+    {
         char *buf = NULL;
         int n;
        DWORD nwritten;
@@ -203,7 +233,7 @@ tty_printf( const char *fmt, ... )
        n = vasprintf(&buf, fmt, arg_ptr);
        if( !buf )
            log_bug("vasprintf() failed\n");
-        
+
        if( !WriteConsoleA( con.out, buf, n, &nwritten, NULL ) )
            log_fatal("WriteConsole failed: rc=%d", (int)GetLastError() );
        if( n != nwritten )
@@ -219,11 +249,58 @@ tty_printf( const char *fmt, ... )
 }
 
 
+/* Same as tty_printf but if FP is not NULL, behave like a regular
+   fprintf. */
+void
+tty_fprintf (estream_t fp, const char *fmt, ... )
+{
+  va_list arg_ptr;
+
+  if (fp)
+    {
+      va_start (arg_ptr, fmt) ;
+      es_vfprintf (fp, fmt, arg_ptr );
+      va_end (arg_ptr);
+      return;
+    }
+
+  if (no_terminal)
+    return;
+
+  if (!initialized)
+    init_ttyfp ();
+
+  va_start (arg_ptr, fmt);
+#ifdef USE_W32_CONSOLE
+  {
+    char *buf = NULL;
+    int n;
+    DWORD nwritten;
+
+    n = vasprintf(&buf, fmt, arg_ptr);
+    if (!buf)
+      log_bug("vasprintf() failed\n");
+
+    if (!WriteConsoleA( con.out, buf, n, &nwritten, NULL ))
+      log_fatal("WriteConsole failed: rc=%d", (int)GetLastError() );
+    if (n != nwritten)
+      log_fatal("WriteConsole failed: %d != %d\n", n, (int)nwritten );
+    last_prompt_len += n;
+    xfree (buf);
+  }
+#else
+  last_prompt_len += vfprintf(ttyfp,fmt,arg_ptr) ;
+  fflush(ttyfp);
+#endif
+  va_end(arg_ptr);
+}
+
+
 /****************
  * Print a string, but filter all control characters out.
  */
 void
-tty_print_string( byte *p, size_t n )
+tty_print_string ( const byte *p, size_t n )
 {
     if (no_terminal)
        return;
@@ -231,7 +308,7 @@ tty_print_string( byte *p, size_t n )
     if( !initialized )
        init_ttyfp();
 
-#ifdef __MINGW32__
+#ifdef USE_W32_CONSOLE
     /* not so effective, change it if you want */
     for( ; n; n--, p++ )
        if( iscntrl( *p ) ) {
@@ -261,7 +338,7 @@ tty_print_string( byte *p, size_t n )
 }
 
 void
-tty_print_utf8_string2( byte *p, size_t n, size_t max_n )
+tty_print_utf8_string2( const byte *p, size_t n, size_t max_n )
 {
     size_t i;
     char *buf;
@@ -275,7 +352,7 @@ tty_print_utf8_string2( byte *p, size_t n, size_t max_n )
            break;
     }
     if( i < n ) {
-       buf = utf8_to_native( p, n, 0 );
+       buf = utf8_to_native( (const char *)p, n, 0 );
        if( max_n && (strlen( buf ) > max_n )) {
            buf[max_n] = 0;
        }
@@ -292,7 +369,7 @@ tty_print_utf8_string2( byte *p, size_t n, size_t max_n )
 }
 
 void
-tty_print_utf8_string( byte *p, size_t n )
+tty_print_utf8_string( const byte *p, size_t n )
 {
     tty_print_utf8_string2( p, n, 0 );
 }
@@ -325,7 +402,7 @@ do_get( const char *prompt, int hidden )
     buf = xmalloc((n=50));
     i = 0;
 
-#ifdef __MINGW32__ /* windoze version */
+#ifdef USE_W32_CONSOLE
     if( hidden )
        SetConsoleMode(con.in, HID_INPMODE );
 
@@ -359,9 +436,17 @@ do_get( const char *prompt, int hidden )
     if( hidden )
        SetConsoleMode(con.in, DEF_INPMODE );
 
-#elif defined(__riscos__)
+#elif defined(__riscos__) || defined(HAVE_W32CE_SYSTEM)
     do {
+#ifdef HAVE_W32CE_SYSTEM
+      /* Using getchar is not a correct solution but for now it
+         doesn't matter becuase we have no real console at all.  We
+         should rework this as soon as we have switched this entire
+         module to estream.  */
+        c = getchar();
+#else
         c = riscos_getchar();
+#endif
         if (c == 0xa || c == 0xd) { /* Return || Enter */
             c = (int) '\n';
         } else if (c == 0x8 || c == 0x7f) { /* Backspace || Delete */
@@ -399,7 +484,7 @@ do_get( const char *prompt, int hidden )
         }
     } while (c != '\n');
     i = (i>0) ? i-1 : 0;
-#else /* unix version */
+#else /* Other systems. */
     if( hidden ) {
 #ifdef HAVE_TCGETATTR
        struct termios term;
@@ -440,7 +525,6 @@ do_get( const char *prompt, int hidden )
        i = 1;
     }
 
-
     if( hidden ) {
 #ifdef HAVE_TCGETATTR
        if( tcsetattr(fileno(ttyfp), TCSAFLUSH, &termsave) )
@@ -457,9 +541,61 @@ do_get( const char *prompt, int hidden )
 char *
 tty_get( const char *prompt )
 {
-    return do_get( prompt, 0 );
+  if (!batchmode && !no_terminal && my_rl_readline && my_rl_add_history)
+    {
+      char *line;
+      char *buf;
+
+      if (!initialized)
+       init_ttyfp();
+
+      last_prompt_len = 0;
+
+      line = my_rl_readline (prompt?prompt:"");
+
+      /* We need to copy it to memory controlled by our malloc
+         implementations; further we need to convert an EOF to our
+         convention. */
+      buf = xmalloc(line? strlen(line)+1:2);
+      if (line)
+        {
+          strcpy (buf, line);
+          trim_spaces (buf);
+          if (strlen (buf) > 2 )
+            my_rl_add_history (line); /* Note that we test BUF but add LINE. */
+          free (line);
+        }
+      else
+        {
+          buf[0] = CONTROL_D;
+          buf[1] = 0;
+        }
+      return buf;
+    }
+  else
+    return do_get ( prompt, 0 );
+}
+
+/* Variable argument version of tty_get.  The prompt is is actually a
+   format string with arguments.  */
+char *
+tty_getf (const char *promptfmt, ... )
+{
+  va_list arg_ptr;
+  char *prompt;
+  char *answer;
+
+  va_start (arg_ptr, promptfmt);
+  if (estream_vasprintf (&prompt, promptfmt, arg_ptr) < 0)
+    log_fatal ("estream_vasprintf failed: %s\n", strerror (errno));
+  va_end (arg_ptr);
+  answer = tty_get (prompt);
+  xfree (prompt);
+  return answer;
 }
 
+
+
 char *
 tty_get_hidden( const char *prompt )
 {
@@ -480,7 +616,7 @@ tty_kill_prompt()
        last_prompt_len = 0;
     if( !last_prompt_len )
        return;
-#ifdef __MINGW32__
+#ifdef USE_W32_CONSOLE
     tty_printf("\r%*s\r", last_prompt_len, "");
 #else
     {
@@ -506,3 +642,63 @@ tty_get_answer_is_yes( const char *prompt )
     xfree(p);
     return yes;
 }
+
+
+/* Called by gnupg_rl_initialize to setup the readline support. */
+void
+tty_private_set_rl_hooks (void (*init_stream) (FILE *),
+                          void (*set_completer) (rl_completion_func_t*),
+                          void (*inhibit_completion) (int),
+                          void (*cleanup_after_signal) (void),
+                          char *(*readline_fun) (const char*),
+                          void (*add_history_fun) (const char*))
+{
+  my_rl_init_stream = init_stream;
+  my_rl_set_completer = set_completer;
+  my_rl_inhibit_completion = inhibit_completion;
+  my_rl_cleanup_after_signal = cleanup_after_signal;
+  my_rl_readline = readline_fun;
+  my_rl_add_history = add_history_fun;
+}
+
+
+#ifdef HAVE_LIBREADLINE
+void
+tty_enable_completion (rl_completion_func_t *completer)
+{
+  if (no_terminal || !my_rl_set_completer )
+    return;
+
+  if (!initialized)
+    init_ttyfp();
+
+  my_rl_set_completer (completer);
+}
+
+void
+tty_disable_completion (void)
+{
+  if (no_terminal || !my_rl_inhibit_completion)
+    return;
+
+  if (!initialized)
+    init_ttyfp();
+
+  my_rl_inhibit_completion (1);
+}
+#endif
+
+void
+tty_cleanup_after_signal (void)
+{
+#ifdef HAVE_TCGETATTR
+  cleanup ();
+#endif
+}
+
+void
+tty_cleanup_rl_after_signal (void)
+{
+  if (my_rl_cleanup_after_signal)
+    my_rl_cleanup_after_signal ();
+}