Mercurial > ecos-v2_0-branch
changeset 543:598fea7813df
Add strptime() function.
| author | gthomas |
|---|---|
| date | Mon, 27 Jan 2003 22:10:15 +0000 |
| parents | 2cb18c83f75c |
| children | 716d0be04750 |
| files | packages/language/c/libc/time/current/ChangeLog packages/language/c/libc/time/current/cdl/time.cdl packages/language/c/libc/time/current/include/time.h packages/language/c/libc/time/current/src/strptime.cxx packages/language/c/libc/time/current/tests/strptime.c |
| diffstat | 5 files changed, 578 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/packages/language/c/libc/time/current/ChangeLog +++ b/packages/language/c/libc/time/current/ChangeLog @@ -1,3 +1,10 @@ +2003-01-27 Gary Thomas <gary@mlbassoc.com> + + * tests/strptime.c: + * src/strptime.cxx: + * include/time.h: + * cdl/time.cdl: Add support for strptime(). + 2002-05-14 Jesper Skov <jskov@redhat.com> * cdl/time.cdl: Added -Wno-format to the compiler flags. This is
--- a/packages/language/c/libc/time/current/cdl/time.cdl +++ b/packages/language/c/libc/time/current/cdl/time.cdl @@ -65,11 +65,12 @@ cdl_package CYGPKG_LIBC_TIME { requires CYGINT_ISO_DIV requires CYGINT_ISO_ABS - compile asctime.cxx asctime_r.cxx clock.cxx \ - ctime.cxx ctime_r.cxx difftime.cxx \ - gmtime.cxx gmtime_r.cxx localtime.cxx \ - localtime_r.cxx mktime.cxx settime.cxx \ - strftime.cxx time.cxx timeutil.cxx + compile asctime.cxx clock.cxx \ + ctime.cxx difftime.cxx \ + gmtime.cxx localtime.cxx \ + mktime.cxx settime.cxx \ + strftime.cxx time.cxx \ + timeutil.cxx # ==================================================================== @@ -114,10 +115,13 @@ cdl_package CYGPKG_LIBC_TIME { cdl_option CYGFUN_LIBC_TIME_POSIX { display "POSIX time functions" default_value 1 + requires CYGFUN_LIBC_STRING_BSD_FUNCS + compile asctime_r.cxx ctime_r.cxx gmtime_r.cxx \ + localtime_r.cxx strptime.cxx description " Enabling this option allows the use of the following functions defined in POSIX 1003.1: - asctime_r(), ctime_r(), gmtime_r(), and + asctime_r(), ctime_r(), gmtime_r(), strptime(), and localtime_r()." } @@ -316,7 +320,10 @@ cdl_package CYGPKG_LIBC_TIME { display "C library time and date function tests" flavor data no_define - calculated { "tests/asctime tests/clock tests/ctime tests/gmtime tests/localtime tests/mktime tests/strftime tests/time" } + calculated { + "tests/asctime tests/clock tests/ctime tests/gmtime tests/localtime tests/mktime tests/strftime tests/time " + . (CYGSEM_LIBC_TIME_POSIX_TIME_ROUTINES ? "tests/strptime" : "") + } description " This option specifies the set of tests for the C library time and date functions."
--- a/packages/language/c/libc/time/current/include/time.h +++ b/packages/language/c/libc/time/current/include/time.h @@ -11,6 +11,7 @@ // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2003 Gary Thomas // // eCos 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 @@ -144,6 +145,17 @@ gmtime_r( const time_t *__timer, struct extern struct tm * localtime_r( const time_t *__timer, struct tm *__result ); +///////////////////////////////////////////////////////// +// strptime() - +///////////////////////////////////////////////////////// +// +// Parse a time string into a struct tm +// + +extern char * +strptime( const char *__s, const char *__format, + struct tm *__timeptr); //__attribute__ ((format (strftime, 2))); + #endif // ifdef CYGFUN_LIBC_TIME_POSIX
new file mode 100644 --- /dev/null +++ b/packages/language/c/libc/time/current/src/strptime.cxx @@ -0,0 +1,427 @@ +// +// Adapted for use in eCos by Gary Thomas +// Copyright (C) 2003 Gary Thomas +// + +/* + * Copyright (c) 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#include <stddef.h> +#include <stdlib.h> +#include <ctype.h> +#include <time.h> + +static const char *weekdays[] = { + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + NULL +}; + +static const char *month[] = { + "January", + "February", + "Mars", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + NULL, +}; + +static const char *ampm[] = { + "am", + "pm", + NULL +}; + +/* + * Try to match `*buf' to one of the strings in `strs'. Return the + * index of the matching string (or -1 if none). Also advance buf. + */ + +static int +match_string (const char **buf, const char **strs, int ablen) +{ + int i = 0; + + for (i = 0; strs[i] != NULL; ++i) { + int len = ablen > 0 ? ablen : strlen (strs[i]); + + if (strncasecmp (*buf, strs[i], len) == 0) { + *buf += len; + return i; + } + } + return -1; +} + +/* + * tm_year is relative this year + */ + +const int tm_year_base = 1900; + +/* + * Return TRUE iff `year' was a leap year. + */ + +static int +is_leap_year (int year) +{ + return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0); +} + +/* + * Return the weekday [0,6] (0 = Sunday) of the first day of `year' + */ + +static int +first_day (int year) +{ + int ret = 4; // Jan 1, 1970 was on Thursday + + for (; year > 1970; --year) + ret = (ret + 365 + is_leap_year (year) ? 1 : 0) % 7; + return ret; +} + +/* + * Set `timeptr' given `wnum' (week number [0, 53]) + */ + +static void +set_week_number_sun (struct tm *timeptr, int wnum) +{ + int fday = first_day (timeptr->tm_year + tm_year_base); + + timeptr->tm_yday = wnum * 7 + timeptr->tm_wday - fday; + if (timeptr->tm_yday < 0) { + timeptr->tm_wday = fday; + timeptr->tm_yday = 0; + } +} + +/* + * Set `timeptr' given `wnum' (week number [0, 53]) + */ + +static void +set_week_number_mon (struct tm *timeptr, int wnum) +{ + int fday = (first_day (timeptr->tm_year + tm_year_base) + 6) % 7; + + timeptr->tm_yday = wnum * 7 + (timeptr->tm_wday + 6) % 7 - fday; + if (timeptr->tm_yday < 0) { + timeptr->tm_wday = (fday + 1) % 7; + timeptr->tm_yday = 0; + } +} + +/* + * Set `timeptr' given `wnum' (week number [0, 53]) + */ + +static void +set_week_number_mon4 (struct tm *timeptr, int wnum) +{ + int fday = (first_day (timeptr->tm_year + tm_year_base) + 6) % 7; + int offset = 0; + + if (fday < 4) + offset += 7; + + timeptr->tm_yday = offset + (wnum - 1) * 7 + timeptr->tm_wday - fday; + if (timeptr->tm_yday < 0) { + timeptr->tm_wday = fday; + timeptr->tm_yday = 0; + } +} + +/* + * + */ + +char * +strptime (const char *buf, const char *format, struct tm *timeptr) +{ + char c; + + timeptr->tm_yday = 1; // So it's always valid + timeptr->tm_isdst = 0; + + for (; (c = *format) != '\0'; ++format) { + char *s; + int ret; + + if (isspace (c)) { + while (isspace (*buf)) + ++buf; + } else if (c == '%' && format[1] != '\0') { + c = *++format; + if (c == 'E' || c == 'O') + c = *++format; + switch (c) { + case 'A' : + ret = match_string (&buf, weekdays, 0); + if (ret < 0) + return NULL; + timeptr->tm_wday = ret; + break; + case 'a' : + ret = match_string (&buf, weekdays, 3); + if (ret < 0) + return NULL; + timeptr->tm_wday = ret; + break; + case 'B' : + ret = match_string (&buf, month, 0); + if (ret < 0) + return NULL; + timeptr->tm_mon = ret; + break; + case 'b' : + case 'h' : + ret = match_string (&buf, month, 3); + if (ret < 0) + return NULL; + timeptr->tm_mon = ret; + break; + case 'C' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_year = (ret * 100) - tm_year_base; + buf = s; + break; + case 'c' : + // Date and Time in the current locale - unsupported + return NULL; + case 'D' : /* %m/%d/%y */ + s = strptime (buf, "%m/%d/%y", timeptr); + if (s == NULL) + return NULL; + buf = s; + break; + case 'd' : + case 'e' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_mday = ret; + buf = s; + break; + case 'H' : + case 'k' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_hour = ret; + buf = s; + break; + case 'I' : + case 'l' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + if (ret == 12) + timeptr->tm_hour = 0; + else + timeptr->tm_hour = ret; + buf = s; + break; + case 'j' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_yday = ret - 1; + buf = s; + break; + case 'm' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_mon = ret - 1; + buf = s; + break; + case 'M' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_min = ret; + buf = s; + break; + case 'n' : + if (*buf == '\n') + ++buf; + else + return NULL; + break; + case 'p' : + ret = match_string (&buf, ampm, 0); + if (ret < 0) + return NULL; + if (timeptr->tm_hour == 0) { + if (ret == 1) + timeptr->tm_hour = 12; + } else + timeptr->tm_hour += 12; + break; + case 'r' : /* %I:%M:%S %p */ + s = strptime (buf, "%I:%M:%S %p", timeptr); + if (s == NULL) + return NULL; + buf = s; + break; + case 'R' : /* %H:%M */ + s = strptime (buf, "%H:%M", timeptr); + if (s == NULL) + return NULL; + buf = s; + break; + case 'S' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_sec = ret; + buf = s; + break; + case 't' : + if (*buf == '\t') + ++buf; + else + return NULL; + break; + case 'T' : /* %H:%M:%S */ + case 'X' : + s = strptime (buf, "%H:%M:%S", timeptr); + if (s == NULL) + return NULL; + buf = s; + break; + case 'u' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_wday = ret - 1; + buf = s; + break; + case 'w' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_wday = ret; + buf = s; + break; + case 'U' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + set_week_number_sun (timeptr, ret); + buf = s; + break; + case 'V' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + set_week_number_mon4 (timeptr, ret); + buf = s; + break; + case 'W' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + set_week_number_mon (timeptr, ret); + buf = s; + break; + case 'x' : + s = strptime (buf, "%Y:%m:%d", timeptr); + if (s == NULL) + return NULL; + buf = s; + break; + case 'y' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + if (ret < 70) + timeptr->tm_year = 100 + ret; + else + timeptr->tm_year = ret; + buf = s; + break; + case 'Y' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_year = ret - tm_year_base; + buf = s; + break; + case 'Z' : + // Timezone spec not handled + return NULL; + case '\0' : + --format; + /* FALLTHROUGH */ + case '%' : + if (*buf == '%') + ++buf; + else + return NULL; + break; + default : + if (*buf == '%' || *++buf == c) + ++buf; + else + return NULL; + break; + } + } else { + if (*buf == c) + ++buf; + else + return NULL; + } + } + return (char *)buf; +} + +// strptime.cxx
new file mode 100644 --- /dev/null +++ b/packages/language/c/libc/time/current/tests/strptime.c @@ -0,0 +1,118 @@ +//================================================================= +// +// strptime.c +// +// Testcase for C library strptime() function +// +//================================================================= +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2003 Gary Thomas +// +// eCos 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 or (at your option) any later version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. +// at http://sources.redhat.com/ecos/ecos-license/ +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): jlarmour +// Contributors: gthomas +// Date: 1999-03-05 +// Description: Contains testcode for C library strptime() function +// +// +//####DESCRIPTIONEND#### + +// CONFIGURATION + +#include <pkgconf/libc_time.h> // C library configuration + +// INCLUDES + +#include <time.h> +#include <cyg/infra/testcase.h> + +// HOW TO START TESTS + +# define START_TEST( test ) test(0) + +// FUNCTIONS + +static int my_strcmp(const char *s1, const char *s2) +{ + for ( ; *s1 == *s2 ; s1++,s2++ ) + { + if ( *s1 == '\0' ) + break; + } // for + + return (*s1 - *s2); +} // my_strcmp() + +static void +test( CYG_ADDRWORD data ) +{ + struct tm tm1; + char s[1000], *sp, *dp, *fp; + size_t size; + + dp = "Fri Jan 24 08:33:14 2003"; + fp = "%a %b %d %H:%M:%S %Y"; + sp = strptime(dp, fp, &tm1); + CYG_TEST_PASS_FAIL(((sp!=NULL) && (*sp=='\0')), "strptime test #1"); + size = strftime(s, sizeof(s), fp, &tm1); + CYG_TEST_PASS_FAIL(((size==strlen(dp)) && (my_strcmp(s, dp) == 0)), "strptime test #2"); + + dp = "Friday January 24 08:33:14 2003"; + fp = "%A %B %d %H:%M:%S %Y"; + sp = strptime(dp, fp, &tm1); + CYG_TEST_PASS_FAIL(((sp!=NULL) && (*sp=='\0')), "strptime test #3"); + size = strftime(s, sizeof(s), fp, &tm1); + CYG_TEST_PASS_FAIL(((size==strlen(dp)) && (my_strcmp(s, dp) == 0)), "strptime test #4"); + + CYG_TEST_FINISH("Finished tests from testcase " __FILE__ " for C library " + "strptime() function"); +} // test() + + +int +main(int argc, char *argv[]) +{ + CYG_TEST_INIT(); + + CYG_TEST_INFO("Starting tests from testcase " __FILE__ " for C library " + "strptime() function"); + + START_TEST( test ); + + CYG_TEST_NA("Testing is not applicable to this configuration"); + +} // main() + +// EOF strptime.c
