(close_ct_reader, close_pcsc_reader): Implemented.
[gnupg.git] / util / miscutil.c
index 2b95d97..e0ea0e7 100644 (file)
@@ -1,5 +1,5 @@
 /* miscutil.c -  miscellaneous utilities
- *     Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -25,7 +25,7 @@
 #include <time.h>
 #include <ctype.h>
 #ifdef HAVE_LANGINFO_H
-  #include <langinfo.h>
+#include <langinfo.h>
 #endif
 #include "types.h"
 #include "util.h"
@@ -56,11 +56,11 @@ scan_isodatestr( const char *string )
     if( strlen(string) != 10 || string[4] != '-' || string[7] != '-' )
        return 0;
     for( i=0; i < 4; i++ )
-       if( !isdigit(string[i]) )
+       if( !digitp(string+i) )
            return 0;
-    if( !isdigit(string[5]) || !isdigit(string[6]) )
+    if( !digitp(string+5) || !digitp(string+6) )
        return 0;
-    if( !isdigit(string[8]) || !isdigit(string[9]) )
+    if( !digitp(string+8) || !digitp(string+9) )
        return 0;
     year = atoi(string);
     month = atoi(string+5);
@@ -124,10 +124,15 @@ strtimestamp( u32 stamp )
     static char buffer[11+5];
     struct tm *tp;
     time_t atime = stamp;
-
-    tp = gmtime( &atime );
-    sprintf(buffer,"%04d-%02d-%02d",
-                   1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
+    
+    if (atime < 0) {
+        strcpy (buffer, "????" "-??" "-??");
+    }
+    else {
+        tp = gmtime( &atime );
+        sprintf(buffer,"%04d-%02d-%02d",
+                1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
+    }
     return buffer;
 }
 
@@ -138,30 +143,35 @@ const char *
 asctimestamp( u32 stamp )
 {
     static char buffer[50];
-    #if defined (HAVE_STRFTIME) && defined (HAVE_NL_LANGINFO)
+#if defined (HAVE_STRFTIME) && defined (HAVE_NL_LANGINFO)
       static char fmt[50];
-    #endif
+#endif
     struct tm *tp;
     time_t atime = stamp;
 
+    if (atime < 0) {
+        strcpy (buffer, "????" "-??" "-??");
+        return buffer;
+    }
+
     tp = localtime( &atime );
-  #ifdef HAVE_STRFTIME
-    #if defined(HAVE_NL_LANGINFO)
-      mem2str( fmt, nl_langinfo(D_T_FMT), DIM(fmt) );
+#ifdef HAVE_STRFTIME
+#if defined(HAVE_NL_LANGINFO)
+      mem2str( fmt, nl_langinfo(D_T_FMT), DIM(fmt)-3 );
       if( strstr( fmt, "%Z" ) == NULL )
        strcat( fmt, " %Z");
       strftime( buffer, DIM(buffer)-1, fmt, tp );
-    #else
+#else
       /* fixme: we should check whether the locale appends a " %Z"
        * These locales from glibc don't put the " %Z":
        * fi_FI hr_HR ja_JP lt_LT lv_LV POSIX ru_RU ru_SU sv_FI sv_SE zh_CN
        */
       strftime( buffer, DIM(buffer)-1, "%c %Z", tp );
-    #endif
+#endif
     buffer[DIM(buffer)-1] = 0;
-  #else
+#else
     mem2str( buffer, asctime(tp), DIM(buffer) );
-  #endif
+#endif
     return buffer;
 }
 
@@ -172,7 +182,8 @@ void
 print_string( FILE *fp, const byte *p, size_t n, int delim )
 {
     for( ; n; n--, p++ )
-       if( iscntrl( *p ) || *p == delim ) {
+       if( *p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim ||
+           (delim && *p=='\\')) {
            putc('\\', fp);
            if( *p == '\n' )
                putc('n', fp);
@@ -194,6 +205,36 @@ print_string( FILE *fp, const byte *p, size_t n, int delim )
 }
 
 /****************
+ * Print an UTF8 string to FP and filter all control characters out.
+ */
+void
+print_utf8_string2 ( FILE *fp, const byte *p, size_t n, int delim )
+{
+    size_t i;
+    char *buf;
+
+    /* we can handle plain ascii simpler, so check for it first */
+    for(i=0; i < n; i++ ) {
+       if( p[i] & 0x80 )
+           break;
+    }
+    if( i < n ) {
+       buf = utf8_to_native ( p, n, delim );
+       /*(utf8 conversion already does the control character quoting)*/
+       fputs( buf, fp );
+       m_free( buf );
+    }
+    else
+       print_string( fp, p, n, delim );
+}
+
+void
+print_utf8_string( FILE *fp, const byte *p, size_t n )
+{
+    print_utf8_string2 (fp, p, n, 0);
+}
+
+/****************
  * This function returns a string which is suitable for printing
  * Caller must release it with m_free()
  */
@@ -206,12 +247,13 @@ make_printable_string( const byte *p, size_t n, int delim )
 
     /* first count length */
     for(save_n = n, save_p = p, buflen=1 ; n; n--, p++ ) {
-       if( iscntrl( *p ) || *p == delim ) {
+       if( *p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim ||
+           (delim && *p=='\\')) {
            if( *p=='\n' || *p=='\r' || *p=='\f'
                || *p=='\v' || *p=='\b' || !*p )
                buflen += 2;
            else
-               buflen += 3;
+               buflen += 4;
        }
        else
            buflen++;
@@ -221,7 +263,8 @@ make_printable_string( const byte *p, size_t n, int delim )
     /* and now make the string */
     d = buffer = m_alloc( buflen );
     for( ; n; n--, p++ ) {
-       if( iscntrl( *p ) || *p == delim ) {
+       if( *p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim ||
+           (delim && *p=='\\')) {
            *d++ = '\\';
            if( *p == '\n' )
                *d++ = 'n';
@@ -247,32 +290,37 @@ make_printable_string( const byte *p, size_t n, int delim )
     return buffer;
 }
 
-
 int
-answer_is_yes( const char *s )
+answer_is_yes_no_default( const char *s, int def_answer )
 {
-    char *long_yes = _("yes");
-    char *short_yes = _("yY");
-    char *long_no = _("no");
-    char *short_no = _("nN");
+    const char *long_yes = _("yes");
+    const char *short_yes = _("yY");
+    const char *long_no = _("no");
+    const char *short_no = _("nN");
 
-    if( !stricmp(s, long_yes ) )
+    /* Note: we have to use the local dependent strcasecmp here */
+    if( !strcasecmp(s, long_yes ) )
        return 1;
-    if( strchr( short_yes, *s ) && !s[1] )
+    if( *s && strchr( short_yes, *s ) && !s[1] )
        return 1;
     /* test for no strings to catch ambiguities for the next test */
-    if( !stricmp(s, long_no ) )
+    if( !strcasecmp(s, long_no ) )
        return 0;
-    if( strchr( short_no, *s ) && !s[1] )
+    if( *s && strchr( short_no, *s ) && !s[1] )
        return 0;
     /* test for the english version (for those who are used to type yes) */
-    if( !stricmp(s, "yes" ) )
+    if( !ascii_strcasecmp(s, "yes" ) )
        return 1;
-    if( strchr( "yY", *s ) && !s[1] )
+    if( *s && strchr( "yY", *s ) && !s[1] )
        return 1;
-    return 0;
+    return def_answer;
 }
 
+int
+answer_is_yes( const char *s )
+{
+  return answer_is_yes_no_default(s,0);
+}
 
 /****************
  * Return 1 for yes, -1 for quit, or 0 for no
@@ -280,34 +328,69 @@ answer_is_yes( const char *s )
 int
 answer_is_yes_no_quit( const char *s )
 {
-    char *long_yes = _("yes");
-    char *long_no = _("no");
-    char *long_quit = _("quit");
-    char *short_yes = _("yY");
-    char *short_no = _("nN");
-    char *short_quit = _("qQ");
+    const char *long_yes = _("yes");
+    const char *long_no = _("no");
+    const char *long_quit = _("quit");
+    const char *short_yes = _("yY");
+    const char *short_no = _("nN");
+    const char *short_quit = _("qQ");
 
-    if( !stricmp(s, long_yes ) )
-       return 1;
-    if( !stricmp(s, long_no ) )
+    /* Note: We have to use the locale dependent strcasecmp */
+    if( !strcasecmp(s, long_no ) )
        return 0;
-    if( !stricmp(s, long_quit ) )
-       return -1;
-    if( strchr( short_yes, *s ) && !s[1] )
+    if( !strcasecmp(s, long_yes ) )
        return 1;
-    if( strchr( short_no, *s ) && !s[1] )
+    if( !strcasecmp(s, long_quit ) )
+       return -1;
+    if( *s && strchr( short_no, *s ) && !s[1] )
        return 0;
-    if( strchr( short_quit, *s ) && !s[1] )
+    if( *s && strchr( short_yes, *s ) && !s[1] )
+       return 1;
+    if( *s && strchr( short_quit, *s ) && !s[1] )
        return -1;
-    if( !stricmp(s, "yes" ) )
+    /* but not here */
+    if( !ascii_strcasecmp(s, "yes" ) )
        return 1;
-    if( !stricmp(s, "quit" ) )
+    if( !ascii_strcasecmp(s, "quit" ) )
        return -1;
-    if( strchr( "yY", *s ) && !s[1] )
+    if( *s && strchr( "yY", *s ) && !s[1] )
        return 1;
-    if( strchr( "qQ", *s ) && !s[1] )
+    if( *s && strchr( "qQ", *s ) && !s[1] )
        return -1;
     return 0;
 }
 
 
+/*
+   Return 1 for okay, 0 for for cancel or DEF_ANSWER for default. 
+ */
+int
+answer_is_okay_cancel (const char *s, int def_answer)
+{
+  const char *long_okay = _("okay");
+  const char *long_cancel = _("cancel");
+  const char *short_okay = _("oO");
+  const char *short_cancel = _("cC");
+  
+  /* Note: We have to use the locale dependent strcasecmp */
+  if ( !strcasecmp(s, long_okay ) )
+    return 1;
+  if ( !strcasecmp(s, long_cancel ) )
+    return 0;
+  if ( *s && strchr( short_okay, *s ) && !s[1] )
+    return 1;
+  if ( *s && strchr( short_cancel, *s ) && !s[1] )
+    return 0;
+  /* Always test for the English values (not locale here) */
+  if ( !ascii_strcasecmp(s, "okay" ) )
+    return 1;
+  if ( !ascii_strcasecmp(s, "ok" ) )
+    return 1;
+  if ( !ascii_strcasecmp(s, "cancel" ) )
+    return 0;
+  if ( *s && strchr( "oO", *s ) && !s[1] )
+    return 1;
+  if ( *s && strchr( "cC", *s ) && !s[1] )
+    return 0;
+  return def_answer;
+}