Add new functions to convert iso time strings.

This commit is contained in:
Werner Koch 2011-03-01 14:22:41 +01:00
parent cf8878cb18
commit dfdda3b344
6 changed files with 255 additions and 26 deletions

View 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> 2011-02-11 Andrey Jivsov <openpgp@brainhub.org>
* openpgp-oid.c (openpgp_oid_to_str): Use unsigned int for * openpgp-oid.c (openpgp_oid_to_str): Use unsigned int for

View File

@ -1,5 +1,5 @@
/* gettime.c - Wrapper for time functions /* 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. * This file is part of GnuPG.
* *
@ -179,29 +179,162 @@ scan_isodatestr( const char *string )
return stamp; return stamp;
} }
/* Scan am ISO timestamp and return an Epoch based timestamp. The only
int
isotime_p (const char *string)
{
const char *s;
int i;
if (!*string)
return 0;
for (s=string, i=0; i < 8; i++, s++)
if (!digitp (s))
return 0;
if (*s != 'T')
return 0;
for (s++, i=9; i < 15; i++, s++)
if (!digitp (s))
return 0;
if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ','))
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 supported format is "yyyymmddThhmmss" delimited by white space, nul, a
colon or a comma. Returns (time_t)(-1) for an invalid string. */ colon or a comma. Returns (time_t)(-1) for an invalid string. */
time_t time_t
isotime2epoch (const char *string) isotime2epoch (const char *string)
{ {
const char *s;
int year, month, day, hour, minu, sec; int year, month, day, hour, minu, sec;
struct tm tmbuf; struct tm tmbuf;
int i;
if (!*string) if (!isotime_p (string))
return (time_t)(-1); return (time_t)(-1);
for (s=string, i=0; i < 8; i++, s++)
if (!digitp (s))
return (time_t)(-1);
if (*s != 'T')
return (time_t)(-1);
for (s++, i=9; i < 15; i++, s++)
if (!digitp (s))
return (time_t)(-1);
if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ','))
return (time_t)(-1); /* Wrong delimiter. */
year = atoi_4 (string); year = atoi_4 (string);
month = atoi_2 (string + 4); month = atoi_2 (string + 4);

View File

@ -34,6 +34,9 @@ void gnupg_set_time (time_t newtime, int freeze);
int gnupg_faked_time_p (void); int gnupg_faked_time_p (void);
u32 make_timestamp (void); u32 make_timestamp (void);
u32 scan_isodatestr (const char *string); 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); time_t isotime2epoch (const char *string);
void epoch2isotime (gnupg_isotime_t timebuf, time_t atime); void epoch2isotime (gnupg_isotime_t timebuf, time_t atime);
u32 add_days_to_timestamp (u32 stamp, u16 days); u32 add_days_to_timestamp (u32 stamp, u16 days);

View File

@ -1,5 +1,5 @@
/* t-gettime.c - Module test for gettime.c /* 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. * 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 int
main (int argc, char **argv) main (int argc, char **argv)
@ -97,6 +181,7 @@ main (int argc, char **argv)
verbose = 1; verbose = 1;
test_isotime2epoch (); test_isotime2epoch ();
test_string2isotime ();
return !!errcount; return !!errcount;
} }

View 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 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 length of this S-expression (used to validate the syntax). Both
are updated to reflect the new position. The token itself is 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. 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 TOKLEN is checked to be within the bounds. On error an error code
is returned and all pointers should are not guaranteed to point to is returned and no pointer is not guaranteed to point to
a meanigful value. DEPTH should be initialized to 0 and will a meaningful value. DEPTH should be initialized to 0 and will
reflect on return the actual depth of the tree. To detect the end 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 of the S-expression it is advisable to check DEPTH after a
successful return: successful return.
depth = 0; depth = 0;
while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))

View File

@ -90,15 +90,15 @@ gpg_error_t _parse_ber_header (unsigned char const **buffer, size_t *size,
GPG_ERR_SOURCE_DEFAULT) 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 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 length of this S-expression (used to validate the syntax). Both
are updated to reflect the new position. The token itself is 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. 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 TOKLEN is checked to be within the bounds. On error an error code
is returned and all pointers should are not guaranteed to point to is returned and no pointer is not guaranteed to point to
a meanigful value. DEPTH should be initialized to 0 and will a meaningful value. DEPTH should be initialized to 0 and will
reflect on return the actual depth of the tree. To detect the end 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 of the S-expression it is advisable to check DEPTH after a
successful return. */ successful return. */