Add new functions to convert iso time strings.
authorWerner Koch <wk@gnupg.org>
Tue, 1 Mar 2011 13:22:41 +0000 (14:22 +0100)
committerWerner Koch <wk@gnupg.org>
Tue, 1 Mar 2011 13:22:41 +0000 (14:22 +0100)
common/ChangeLog
common/gettime.c
common/gettime.h
common/t-gettime.c
common/tlv.c
common/tlv.h

index f6380c6..cebc0ec 100644 (file)
@@ -1,3 +1,11 @@
+2011-02-27  Werner Koch  <wk@g10code.com>
+
+       * gettime.c (isotime2epoch): Factor check code out to ..
+       (isotime_p): .. new.
+       (isotime_human_p): New.
+       (string2isotime): New.
+       * t-gettime.c (test_string2isotime): New.
+
 2011-02-11  Andrey Jivsov <openpgp@brainhub.org>
 
        * openpgp-oid.c (openpgp_oid_to_str): Use unsigned int for
index 27dc845..e5462a7 100644 (file)
@@ -1,5 +1,5 @@
 /* gettime.c - Wrapper for time functions
- *     Copyright (C) 1998, 2002, 2007 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 2002, 2007, 2011 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -179,29 +179,162 @@ scan_isodatestr( const char *string )
     return stamp;
 }
 
-/* Scan am ISO timestamp and return an Epoch based timestamp.  The only
-   supported format is "yyyymmddThhmmss" delimited by white space, nul, a
-   colon or a comma.  Returns (time_t)(-1) for an invalid string.  */
-time_t
-isotime2epoch (const char *string)
+
+int
+isotime_p (const char *string)
 {
   const char *s;
-  int year, month, day, hour, minu, sec;
-  struct tm tmbuf;
   int i;
 
   if (!*string)
-    return (time_t)(-1);
+    return 0;
   for (s=string, i=0; i < 8; i++, s++)
     if (!digitp (s))
-      return (time_t)(-1);
+      return 0;
   if (*s != 'T')
-      return (time_t)(-1);
+      return 0;
   for (s++, i=9; i < 15; i++, s++)
     if (!digitp (s))
-      return (time_t)(-1);
+      return 0;
   if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ','))
-    return (time_t)(-1);  /* Wrong delimiter.  */
+    return 0;  /* Wrong delimiter.  */
+
+  return 1;
+}
+
+
+/* Scan a string and return true if the string represents the human
+   readable format of an ISO time.  This format is:
+      yyyy-mm-dd[ hh[:mm[:ss]]]
+   Scanning stops at the second space or at a comma.  */
+int
+isotime_human_p (const char *string)
+{
+  const char *s;
+  int i;
+
+  if (!*string)
+    return 0;
+  for (s=string, i=0; i < 4; i++, s++)
+    if (!digitp (s))
+      return 0;
+  if (*s != '-')
+    return 0;
+  s++;
+  if (!digitp (s) || !digitp (s+1) || s[2] != '-')
+    return 0;
+  i = atoi_2 (s);
+  if (i < 1 || i > 12)
+    return 0;
+  s += 3;
+  if (!digitp (s) || !digitp (s+1))
+    return 0;
+  i = atoi_2 (s);
+  if (i < 1 || i > 31)
+    return 0;
+  s += 2;
+  if (!*s || *s == ',')
+    return 1; /* Okay; only date given.  */
+  if (!spacep (s))
+    return 0;
+  s++;
+  if (spacep (s))
+    return 1; /* Okay, second space stops scanning.  */
+  if (!digitp (s) || !digitp (s+1))
+    return 0;
+  i = atoi_2 (s);
+  if (i < 0 || i > 23)
+    return 0;
+  s += 2;
+  if (!*s || *s == ',')
+    return 1; /* Okay; only date and hour given.  */
+  if (*s != ':')
+    return 0;
+  s++;
+  if (!digitp (s) || !digitp (s+1))
+    return 0;
+  i = atoi_2 (s);
+  if (i < 0 || i > 59)
+    return 0;
+  s += 2;
+  if (!*s || *s == ',')
+    return 1; /* Okay; only date, hour and minute given.  */
+  if (*s != ':')
+    return 0;
+  s++;
+  if (!digitp (s) || !digitp (s+1))
+    return 0;
+  i = atoi_2 (s);
+  if (i < 0 || i > 60)
+    return 0;
+  s += 2;
+  if (!*s || *s == ',' || spacep (s))
+    return 1; /* Okay; date, hour and minute and second given.  */
+
+  return 0; /* Unexpected delimiter.  */
+}
+
+/* Convert a standard isotime or a human readable variant into an
+   isotime structure.  The allowed formats are those described by
+   isotime_p and isotime_human_p.  The function returns 0 on failure
+   or the length of the scanned string on success.  */
+size_t
+string2isotime (gnupg_isotime_t atime, const char *string)
+{
+  gnupg_isotime_t dummyatime;
+
+  if (!atime)
+    atime = dummyatime;
+
+  atime[0] = 0;
+  if (isotime_p (string))
+    {
+      memcpy (atime, string, 15);
+      atime[15] = 0;
+      return 15;
+    }
+  if (!isotime_human_p (string))
+    return 0;
+  atime[0] = string[0];
+  atime[1] = string[1];
+  atime[2] = string[2];
+  atime[3] = string[3];
+  atime[4] = string[5];
+  atime[5] = string[6];
+  atime[6] = string[8];
+  atime[7] = string[9];
+  atime[8] = 'T';
+  memset (atime+9, '0', 6);
+  atime[15] = 0;
+  if (!spacep (string+10))
+    return 10;
+  if (spacep (string+11))
+    return 11; /* As per def, second space stops scanning.  */
+  atime[9] = string[11];
+  atime[10] = string[12];
+  if (string[13] != ':')
+    return 13;
+  atime[11] = string[14];
+  atime[12] = string[15];
+  if (string[16] != ':')
+    return 16;
+  atime[13] = string[17];
+  atime[14] = string[18];
+  return 19;
+}
+
+
+/* Scan an ISO timestamp and return an Epoch based timestamp.  The only
+   supported format is "yyyymmddThhmmss" delimited by white space, nul, a
+   colon or a comma.  Returns (time_t)(-1) for an invalid string.  */
+time_t
+isotime2epoch (const char *string)
+{
+  int year, month, day, hour, minu, sec;
+  struct tm tmbuf;
+
+  if (!isotime_p (string))
+    return (time_t)(-1);
 
   year  = atoi_4 (string);
   month = atoi_2 (string + 4);
index 731be56..4199369 100644 (file)
@@ -34,6 +34,9 @@ void   gnupg_set_time (time_t newtime, int freeze);
 int    gnupg_faked_time_p (void);
 u32    make_timestamp (void);
 u32    scan_isodatestr (const char *string);
+int    isotime_p (const char *string);
+int    isotime_human_p (const char *string);
+size_t string2isotime (gnupg_isotime_t atime, const char *string);
 time_t isotime2epoch (const char *string);
 void   epoch2isotime (gnupg_isotime_t timebuf, time_t atime);
 u32    add_days_to_timestamp (u32 stamp, u16 days);
index 1cfde69..79c3d43 100644 (file)
@@ -1,5 +1,5 @@
 /* t-gettime.c - Module test for gettime.c
- *     Copyright (C) 2007 Free Software Foundation, Inc.
+ *     Copyright (C) 2007, 2011 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -89,6 +89,90 @@ test_isotime2epoch (void)
 
 
 
+static void
+test_string2isotime (void)
+{
+  struct {
+    const char *string;
+    size_t result;
+    const char *expected;
+  } array [] = {
+    { "19700101T000001",      15, "19700101T000001" },
+    { "19700101T235959",      15, "19700101T235959" },
+    { "19980815T143712",      15, "19980815T143712" },
+    { "19700101T000000",      15, "19700101T000000" },
+    { "19691231T235959",      15, "19691231T235959" },
+    { "19000101T000000",      15, "19000101T000000" },
+    { "",                      0, ""                },
+    { "19000101T00000",        0, ""                },
+    { "20010101t123456",       0, ""                },
+    { "20010101T123456",      15, "20010101T123456" },
+    { "20070629T160000",      15, "20070629T160000" },
+    { "20070629T160000:",     15, "20070629T160000" },
+    { "20070629T160000,",     15, "20070629T160000" },
+    { "20070629T160000 ",     15, "20070629T160000" },
+    { "20070629T160000\n",    15,"20070629T160000"  },
+    { "20070629T160000.",      0, ""                },
+    { "1066-03-20",           10, "10660320T000000" },
+    { "1066-03-20,",          10, "10660320T000000" },
+    { "1066-03-20:",           0, ""                },
+    { "1066-03-20 00",        13, "10660320T000000" },
+    { "1066-03-20 01",        13, "10660320T010000" },
+    { "1066-03-20 23",        13, "10660320T230000" },
+    { "1066-03-20 24",         0, ""                },
+    { "1066-03-20 00:",        0, ""                },
+    { "1066-03-20 00:3",       0, ""                },
+    { "1066-03-20 00:31",     16, "10660320T003100" },
+    { "1066-03-20 00:31:47",  19, "10660320T003147" },
+    { "1066-03-20 00:31:47 ", 19, "10660320T003147" },
+    { "1066-03-20 00:31:47,", 19, "10660320T003147" },
+    { "1066-03-20 00:31:47:",  0, ""                },
+    { "1-03-20 00:31:47:",     0, ""                },
+    { "10-03-20 00:31:47:",    0, ""                },
+    { "106-03-20 00:31:47:",   0, ""                },
+    { "1066-23-20 00:31:47:",  0, ""                },
+    { "1066-00-20 00:31:47:",  0, ""                },
+    { "1066-0-20 00:31:47:",   0, ""                },
+    { "1066-01-2 00:31:47:",   0, ""                },
+    { "1066-01-2  00:31:47:",  0, ""                },
+    { "1066-01-32 00:31:47:",  0, ""                },
+    { "1066-01-00 00:31:47:",  0, ""                },
+    { "1066-03-20  00:31:47:",11, "10660320T000000" },
+    { "1066-03-2000:31:47:",   0, ""                },
+    { "10666-03-20 00:31:47:", 0, ""                },
+    { NULL, 0 }
+  };
+  int idx;
+  size_t result;
+  gnupg_isotime_t tbuf;
+
+  for (idx=0; array[idx].string; idx++)
+    {
+      result = string2isotime (tbuf, array[idx].string);
+      if (result != array[idx].result)
+        {
+          fail (idx);
+          if (verbose)
+            fprintf (stderr, "string `%s' expected: %d, got: %d\n",
+                     array[idx].string, (int)array[idx].result, (int)result);
+        }
+      else if (result && strlen (tbuf) != 15)
+        {
+          fail (idx);
+          if (verbose)
+            fprintf (stderr, "string `%s' invalid isotime returned\n",
+                     array[idx].string);
+        }
+      else if (result && strcmp (array[idx].expected, tbuf))
+        {
+          fail (idx);
+          if (verbose)
+            fprintf (stderr, "string `%s' bad isotime '%s' returned\n",
+                     array[idx].string, tbuf);
+        }
+    }
+}
+
 
 int
 main (int argc, char **argv)
@@ -97,6 +181,7 @@ main (int argc, char **argv)
     verbose = 1;
 
   test_isotime2epoch ();
+  test_string2isotime ();
 
   return !!errcount;
 }
index 54ef6fc..61f770e 100644 (file)
@@ -238,14 +238,14 @@ _parse_ber_header (unsigned char const **buffer, size_t *size,
    is the pointer to the S-expression and BUFLEN is a pointer to the
    length of this S-expression (used to validate the syntax).  Both
    are updated to reflect the new position.  The token itself is
-   returned as a pointer into the orginal buffer at TOK and TOKLEN.
+   returned as a pointer into the original buffer at TOK and TOKLEN.
    If a parentheses is the next token, TOK will be set to NULL.
-   TOKLEN is checked to be within the bounds.  On error a error code
-   is returned and all pointers should are not guaranteed to point to
-   a meanigful value. DEPTH should be initialized to 0 and will
+   TOKLEN is checked to be within the bounds.  On error an error code
+   is returned and no pointer is not guaranteed to point to
+   a meaningful value.  DEPTH should be initialized to 0 and will
    reflect on return the actual depth of the tree. To detect the end
    of the S-expression it is advisable to check DEPTH after a
-   successful return:
+   successful return.
 
    depth = 0;
    while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
index c7fafd5..fd57e1e 100644 (file)
@@ -90,15 +90,15 @@ gpg_error_t _parse_ber_header (unsigned char const **buffer, size_t *size,
                            GPG_ERR_SOURCE_DEFAULT)
 
 
-/* Return the next token of an canconical encoded S-expression.  BUF
+/* Return the next token of an canonical encoded S-expression.  BUF
    is the pointer to the S-expression and BUFLEN is a pointer to the
    length of this S-expression (used to validate the syntax).  Both
    are updated to reflect the new position.  The token itself is
-   returned as a pointer into the orginal buffer at TOK and TOKLEN.
+   returned as a pointer into the original buffer at TOK and TOKLEN.
    If a parentheses is the next token, TOK will be set to NULL.
-   TOKLEN is checked to be within the bounds.  On error a error code
-   is returned and all pointers should are not guaranteed to point to
-   a meanigful value. DEPTH should be initialized to 0 and will
+   TOKLEN is checked to be within the bounds.  On error an error code
+   is returned and no pointer is not guaranteed to point to
+   a meaningful value.  DEPTH should be initialized to 0 and will
    reflect on return the actual depth of the tree. To detect the end
    of the S-expression it is advisable to check DEPTH after a
    successful return. */