summaryrefslogtreecommitdiff
path: root/util/miscutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/miscutil.c')
-rw-r--r--util/miscutil.c455
1 files changed, 455 insertions, 0 deletions
diff --git a/util/miscutil.c b/util/miscutil.c
new file mode 100644
index 0000000..01241bc
--- /dev/null
+++ b/util/miscutil.c
@@ -0,0 +1,455 @@
+/* miscutil.c - miscellaneous utilities
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003,
+ * 2004, 2005 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
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#ifdef HAVE_LANGINFO_H
+#include <langinfo.h>
+#endif
+#include "types.h"
+#include "util.h"
+#include "i18n.h"
+
+/****************
+ * I know that the OpenPGP protocol has a Y2106 problem ;-)
+ */
+u32
+make_timestamp()
+{
+ return time(NULL);
+}
+
+/****************
+ * Scan a date string and return a timestamp.
+ * The only supported format is "yyyy-mm-dd"
+ * Returns 0 for an invalid date.
+ */
+u32
+scan_isodatestr( const char *string )
+{
+ int year, month, day;
+ struct tm tmbuf;
+ time_t stamp;
+ int i;
+
+ if( strlen(string) != 10 || string[4] != '-' || string[7] != '-' )
+ return 0;
+ for( i=0; i < 4; i++ )
+ if( !digitp(string+i) )
+ return 0;
+ if( !digitp(string+5) || !digitp(string+6) )
+ return 0;
+ if( !digitp(string+8) || !digitp(string+9) )
+ return 0;
+ year = atoi(string);
+ month = atoi(string+5);
+ day = atoi(string+8);
+ /* some basic checks */
+ if( year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 )
+ return 0;
+ memset( &tmbuf, 0, sizeof tmbuf );
+ tmbuf.tm_mday = day;
+ tmbuf.tm_mon = month-1;
+ tmbuf.tm_year = year - 1900;
+ tmbuf.tm_isdst = -1;
+ stamp = mktime( &tmbuf );
+ if( stamp == (time_t)-1 )
+ return 0;
+ return stamp;
+}
+
+
+/****************
+ * Return a string with a time value in the form: x Y, n D, n H
+ */
+
+const char *
+strtimevalue( u32 value )
+{
+ static char buffer[30];
+ unsigned int years, days, hours, minutes;
+
+ value /= 60;
+ minutes = value % 60;
+ value /= 60;
+ hours = value % 24;
+ value /= 24;
+ days = value % 365;
+ value /= 365;
+ years = value;
+
+ sprintf(buffer,"%uy%ud%uh%um", years, days, hours, minutes );
+ if( years )
+ return buffer;
+ if( days )
+ return strchr( buffer, 'y' ) + 1;
+ return strchr( buffer, 'd' ) + 1;
+}
+
+
+/****************
+ * Note: this function returns GMT
+ */
+const char *
+strtimestamp( u32 stamp )
+{
+ static char buffer[11+5];
+ struct tm *tp;
+ time_t atime = stamp;
+
+ 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;
+}
+
+
+/****************
+ * Note: this function returns GMT
+ */
+const char *
+isotimestamp (u32 stamp)
+{
+ static char buffer[25+5];
+ struct tm *tp;
+ time_t atime = stamp;
+
+ if (atime < 0) {
+ strcpy (buffer, "????" "-??" "-??" " " "??" ":" "??" ":" "??");
+ }
+ else {
+ tp = gmtime( &atime );
+ sprintf(buffer,"%04d-%02d-%02d %02d:%02d:%02d",
+ 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
+ tp->tm_hour, tp->tm_min, tp->tm_sec);
+ }
+ return buffer;
+}
+
+/****************
+ * Note: this function returns local time
+ */
+const char *
+asctimestamp( u32 stamp )
+{
+ static char buffer[50];
+#if defined (HAVE_STRFTIME) && defined (HAVE_NL_LANGINFO)
+ static char fmt[50];
+#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)-3 );
+ if( strstr( fmt, "%Z" ) == NULL )
+ strcat( fmt, " %Z");
+ strftime( buffer, DIM(buffer)-1, fmt, tp );
+#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,
+#ifdef HAVE_W32_SYSTEM
+ "%c"
+#else
+ "%c %Z"
+#endif
+ , tp );
+#endif
+ buffer[DIM(buffer)-1] = 0;
+#else
+ mem2str( buffer, asctime(tp), DIM(buffer) );
+#endif
+ return buffer;
+}
+
+
+/****************
+ * Print a string to FP, but filter all control characters out.
+ */
+void
+print_string2( FILE *fp, const byte *p, size_t n, int delim, int delim2 )
+{
+ for( ; n; n--, p++ )
+ if( *p < 0x20 || (*p >= 0x7f && *p < 0xa0)
+ || *p == delim || *p == delim2
+ || ((delim || delim2) && *p=='\\'))
+ {
+ putc('\\', fp);
+ if( *p == '\n' )
+ putc('n', fp);
+ else if( *p == '\r' )
+ putc('r', fp);
+ else if( *p == '\f' )
+ putc('f', fp);
+ else if( *p == '\v' )
+ putc('v', fp);
+ else if( *p == '\b' )
+ putc('b', fp);
+ else if( !*p )
+ putc('0', fp);
+ else
+ fprintf(fp, "x%02x", *p );
+ }
+ else
+ putc(*p, fp);
+}
+
+void
+print_string( FILE *fp, const byte *p, size_t n, int delim )
+{
+ print_string2(fp,p,n,delim,0);
+}
+
+/****************
+ * 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 );
+ xfree( 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 xfree()
+ */
+char *
+make_printable_string( const byte *p, size_t n, int delim )
+{
+ size_t save_n, buflen;
+ const byte *save_p;
+ char *buffer, *d;
+
+ /* first count length */
+ for(save_n = n, save_p = p, buflen=1 ; n; n--, p++ ) {
+ 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 += 4;
+ }
+ else
+ buflen++;
+ }
+ p = save_p;
+ n = save_n;
+ /* and now make the string */
+ d = buffer = xmalloc( buflen );
+ for( ; n; n--, p++ ) {
+ if( *p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim ||
+ (delim && *p=='\\')) {
+ *d++ = '\\';
+ if( *p == '\n' )
+ *d++ = 'n';
+ else if( *p == '\r' )
+ *d++ = 'r';
+ else if( *p == '\f' )
+ *d++ = 'f';
+ else if( *p == '\v' )
+ *d++ = 'v';
+ else if( *p == '\b' )
+ *d++ = 'b';
+ else if( !*p )
+ *d++ = '0';
+ else {
+ sprintf(d, "x%02x", *p );
+ d += 3;
+ }
+ }
+ else
+ *d++ = *p;
+ }
+ *d = 0;
+ return buffer;
+}
+
+int
+answer_is_yes_no_default( const char *s, int def_answer )
+{
+ /* TRANSLATORS: See doc/TRANSLATE about this string. */
+ const char *long_yes = _("yes");
+ const char *short_yes = _("yY");
+ /* TRANSLATORS: See doc/TRANSLATE about this string. */
+ const char *long_no = _("no");
+ const char *short_no = _("nN");
+
+ /* Note: we have to use the local dependent strcasecmp here */
+ if( match_multistr(long_yes,s) )
+ return 1;
+ if( *s && strchr( short_yes, *s ) && !s[1] )
+ return 1;
+ /* test for no strings to catch ambiguities for the next test */
+ if( match_multistr(long_no,s) )
+ return 0;
+ if( *s && strchr( short_no, *s ) && !s[1] )
+ return 0;
+ /* test for the english version (for those who are used to type yes) */
+ if( !ascii_strcasecmp(s, "yes" ) )
+ return 1;
+ if( *s && strchr( "yY", *s ) && !s[1] )
+ return 1;
+ 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
+ */
+int
+answer_is_yes_no_quit( const char *s )
+{
+ /* TRANSLATORS: See doc/TRANSLATE about this string. */
+ const char *long_yes = _("yes");
+ /* TRANSLATORS: See doc/TRANSLATE about this string. */
+ const char *long_no = _("no");
+ /* TRANSLATORS: See doc/TRANSLATE about this string. */
+ const char *long_quit = _("quit");
+ const char *short_yes = _("yY");
+ const char *short_no = _("nN");
+ const char *short_quit = _("qQ");
+
+ if( match_multistr(long_no,s) )
+ return 0;
+ if( match_multistr(long_yes,s) )
+ return 1;
+ if( match_multistr(long_quit,s) )
+ return -1;
+ if( *s && strchr( short_no, *s ) && !s[1] )
+ return 0;
+ if( *s && strchr( short_yes, *s ) && !s[1] )
+ return 1;
+ if( *s && strchr( short_quit, *s ) && !s[1] )
+ return -1;
+ /* but not here */
+ if( !ascii_strcasecmp(s, "yes" ) )
+ return 1;
+ if( !ascii_strcasecmp(s, "quit" ) )
+ return -1;
+ if( *s && strchr( "yY", *s ) && !s[1] )
+ return 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)
+{
+ /* TRANSLATORS: See doc/TRANSLATE about this string. */
+ const char *long_okay = _("okay|okay");
+ /* TRANSLATORS: See doc/TRANSLATE about this string. */
+ const char *long_cancel = _("cancel|cancel");
+ const char *short_okay = _("oO");
+ const char *short_cancel = _("cC");
+
+ /* Note: We have to use the locale dependent strcasecmp */
+ if ( match_multistr(long_okay,s) )
+ return 1;
+ if ( match_multistr(long_cancel,s) )
+ 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;
+}
+
+/* Try match against each substring of multistr, delimited by | */
+int
+match_multistr(const char *multistr,const char *match)
+{
+ do
+ {
+ size_t seglen=strcspn(multistr,"|");
+ if(!seglen)
+ break;
+ /* Using the localized strncasecmp */
+ if(strncasecmp(multistr,match,seglen)==0)
+ return 1;
+ multistr+=seglen;
+ if(*multistr=='|')
+ multistr++;
+ }
+ while(*multistr);
+
+ return 0;
+}