X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=lib%2Fsh%2Fstrftime.c;h=0ababc144f1dce652249599f2d16145cdc37777e;hb=ac50fbac377e32b98d2de396f016ea81e8ee9961;hp=aa3fc850ec25b8b2dc1f1526e23d7d7ddc9392ba;hpb=4539d736f1aff232857a854fd2a68df0c98d9f34;p=platform%2Fupstream%2Fbash.git diff --git a/lib/sh/strftime.c b/lib/sh/strftime.c index aa3fc85..0ababc1 100644 --- a/lib/sh/strftime.c +++ b/lib/sh/strftime.c @@ -38,6 +38,7 @@ * Updated September, 2000 * Updated December, 2001 * Updated January, 2011 + * Updated April, 2012 * * Fixes from ado@elsie.nci.nih.gov, * February 1991, May 1992 @@ -75,6 +76,7 @@ #define VMS_EXT 1 /* include %v for VMS date format */ #define HPUX_EXT 1 /* non-conflicting stuff in HP-UX date */ #define POSIX_SEMANTICS 1 /* call tzset() if TZ changes */ +#define POSIX_2008 1 /* flag and fw for C, F, G, Y formats */ #undef strchr /* avoid AIX weirdness */ @@ -96,27 +98,25 @@ static int iso8601wknum(const struct tm *timeptr); #define range(low, item, hi) max(low, min(item, hi)) -#if !defined(OS2) && !defined(MSDOS) && defined(HAVE_TZNAME) +/* Whew! This stuff is a mess. */ +#if !defined(OS2) && !defined(MSDOS) && !defined(__CYGWIN__) && defined(HAVE_TZNAME) extern char *tzname[2]; extern int daylight; #if defined(SOLARIS) || defined(mips) || defined (M_UNIX) extern long int timezone, altzone; #else -# if defined (HPUX) +# if defined (HPUX) || defined(__hpux) extern long int timezone; # else +# if !defined(__CYGWIN__) extern int timezone, altzone; -# endif /* !HPUX */ -#endif /* !SOLARIS && !mips && !M_UNIX */ +# endif +# endif +#endif #endif #undef min /* just in case */ -/* format for %+ -- currently unused */ -#ifndef NATIONAL_FORMAT -#define NATIONAL_FORMAT "%a %b %e %H:%M:%S %Z %Y" -#endif - /* min --- return minimum of two numbers */ static inline int @@ -135,6 +135,34 @@ max(int a, int b) return (a > b ? a : b); } +#ifdef POSIX_2008 +/* iso_8601_2000_year --- format a year per ISO 8601:2000 as in 1003.1 */ + +static void +iso_8601_2000_year(char *buf, int year, size_t fw) +{ + int extra; + char sign = '\0'; + + if (year >= -9999 && year <= 9999) { + sprintf(buf, "%0*d", (int) fw, year); + return; + } + + /* now things get weird */ + if (year > 9999) { + sign = '+'; + } else { + sign = '-'; + year = -year; + } + + extra = year / 10000; + year %= 10000; + sprintf(buf, "%c_%04d_%d", sign, extra, year); +} +#endif /* POSIX_2008 */ + /* strftime --- produce formatted time */ size_t @@ -155,12 +183,19 @@ strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr) #ifndef HAVE_TM_ZONE #ifndef HAVE_TM_NAME #ifndef HAVE_TZNAME +#ifndef __CYGWIN__ extern char *timezone(); struct timeval tv; struct timezone zone; +#endif /* __CYGWIN__ */ #endif /* HAVE_TZNAME */ #endif /* HAVE_TM_NAME */ #endif /* HAVE_TM_ZONE */ +#ifdef POSIX_2008 + int pad; + size_t fw; + char flag; +#endif /* POSIX_2008 */ /* various tables, useful in North America */ static const char *days_a[] = { @@ -234,6 +269,40 @@ strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr) *s++ = *format; continue; } +#ifdef POSIX_2008 + pad = '\0'; + fw = 0; + flag = '\0'; + switch (*++format) { + case '+': + flag = '+'; + /* fall through */ + case '0': + pad = '0'; + format++; + break; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + break; + + default: + format--; + goto again; + } + for (; isdigit(*format); format++) { + fw = fw * 10 + (*format - '0'); + } + format--; +#endif /* POSIX_2008 */ + again: switch (*++format) { case '\0': @@ -285,8 +354,19 @@ strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr) break; case 'C': +#ifdef POSIX_2008 + if (pad != '\0' && fw > 0) { + size_t min_fw = (flag ? 3 : 2); + + fw = max(fw, min_fw); + sprintf(tbuf, flag + ? "%+0*ld" + : "%0*ld", (int) fw, + (timeptr->tm_year + 1900L) / 100); + } else +#endif /* POSIX_2008 */ century: - sprintf(tbuf, "%02ld", (timeptr->tm_year + 1900L) / 100); + sprintf(tbuf, "%02ld", (timeptr->tm_year + 1900L) / 100); break; case 'd': /* day of the month, 01 - 31 */ @@ -307,7 +387,30 @@ strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr) goto again; case 'F': /* ISO 8601 date representation */ + { +#ifdef POSIX_2008 + /* + * Field width for %F is for the whole thing. + * It must be at least 10. + */ + char m_d[10]; + strftime(m_d, sizeof m_d, "-%m-%d", timeptr); + size_t min_fw = 10; + + if (pad != '\0' && fw > 0) { + fw = max(fw, min_fw); + } else { + fw = min_fw; + } + + fw -= 6; /* -XX-XX at end are invariant */ + + iso_8601_2000_year(tbuf, timeptr->tm_year + 1900, fw); + strcat(tbuf, m_d); +#else strftime(tbuf, sizeof tbuf, "%Y-%m-%d", timeptr); +#endif /* POSIX_2008 */ + } break; case 'g': @@ -329,8 +432,20 @@ strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr) else y = 1900L + timeptr->tm_year; - if (*format == 'G') - sprintf(tbuf, "%ld", y); + if (*format == 'G') { +#ifdef POSIX_2008 + if (pad != '\0' && fw > 0) { + size_t min_fw = 4; + + fw = max(fw, min_fw); + sprintf(tbuf, flag + ? "%+0*ld" + : "%0*ld", (int) fw, + y); + } else +#endif /* POSIX_2008 */ + sprintf(tbuf, "%ld", y); + } else sprintf(tbuf, "%02ld", y % 100); break; @@ -455,7 +570,17 @@ strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr) break; case 'Y': /* year with century */ - fullyear: +#ifdef POSIX_2008 + if (pad != '\0' && fw > 0) { + size_t min_fw = 4; + + fw = max(fw, min_fw); + sprintf(tbuf, flag + ? "%+0*ld" + : "%0*ld", (int) fw, + 1900L + timeptr->tm_year); + } else +#endif /* POSIX_2008 */ sprintf(tbuf, "%ld", 1900L + timeptr->tm_year); break; @@ -496,12 +621,12 @@ strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr) * Systems with tzname[] probably have timezone as * secs west of GMT. Convert to mins east of GMT. */ -# ifdef HPUX +# if defined(__hpux) || defined (HPUX) || defined(__CYGWIN__) off = -timezone / 60; # else /* ADR: 4 August 2001, fixed this per gazelle@interaccess.com */ off = -(daylight ? altzone : timezone) / 60; -# endif /* !HPUX */ +# endif #else /* !HAVE_TZNAME */ gettimeofday(& tv, & zone); off = -zone.tz_minuteswest;