X-Git-Url: https://pd.if.org/git/?a=blobdiff_plain;f=functions%2Ftime%2Fstrftime.c;h=99a7c51624bb168930ab0da03f505126b0f3d7a2;hb=689f876fb2420ed2ce45aca58dc39f05e1eb5c2d;hp=87ac4ca9d76bd17d6391c5faa3b3e1ca57fc1da6;hpb=8481519337ff8acf46db6b91fb9484777fd89609;p=pdclib diff --git a/functions/time/strftime.c b/functions/time/strftime.c index 87ac4ca..99a7c51 100644 --- a/functions/time/strftime.c +++ b/functions/time/strftime.c @@ -21,25 +21,30 @@ enum wstart_t { E_SUNDAY = 0, - E_MONDAY = 1 + E_MONDAY = 1, + E_ISO_WEEK, + E_ISO_YEAR }; #include -static int weeknr( const struct tm * timeptr, int wstart ) +static int week_calc( const struct tm * timeptr, int wtype ) { - int wday = ( timeptr->tm_wday + 7 - wstart ) % 7; - div_t week = div( timeptr->tm_yday, 7 ); - if ( week.rem >= wday ) + if ( wtype <= E_MONDAY ) { - ++week.quot; + /* Simple -- first week starting with E_SUNDAY / E_MONDAY, + days before that are week 0. + */ + int wday = ( timeptr->tm_wday + 7 - wtype ) % 7; + div_t week = div( timeptr->tm_yday, 7 ); + if ( week.rem >= wday ) + { + ++week.quot; + } + return week.quot; } - return week.quot; -} -static int iso_week( const struct tm * timeptr ) -{ - /* calculations below rely on Sunday == 7 */ + /* calculating ISO week; relies on Sunday == 7 */ int wday = timeptr->tm_wday; if ( wday == 0 ) { @@ -82,24 +87,62 @@ static int iso_week( const struct tm * timeptr ) week = 52; } } - return week; -} + if ( wtype == E_ISO_WEEK ) + { + return week; + } -static int sprints( char * _PDCLIB_restrict dest, const char * _PDCLIB_restrict src, size_t maxsize, size_t * rc ) -{ - size_t len = strlen( src ); - if ( *rc < ( maxsize - len ) ) + /* E_ISO_YEAR -- determine the "week-based year" */ + int bias = 0; + if ( week >= 52 && timeptr->tm_mon == 0 ) { - strcpy( dest + *rc, src ); - *rc += len; - return 1; + --bias; } - else + else if ( week == 1 && timeptr->tm_mon == 11 ) { - return 0; + ++bias; } + return timeptr->tm_year + 1900 + bias; } +/* Assuming presence of s, rc, maxsize. + Checks index for valid range, target buffer for sufficient remaining + capacity, and copies the locale-specific string (or "?" if index out + of range). Returns with zero if buffer capacity insufficient. +*/ +#define SPRINTSTR( array, index, max ) \ + { \ + int ind = (index); \ + const char * str = "?"; \ + if ( ind >= 0 && ind <= max ) \ + { \ + str = array[ ind ]; \ + } \ + size_t len = strlen( str ); \ + if ( rc < ( maxsize - len ) ) \ + { \ + strcpy( s + rc, str ); \ + rc += len; \ + } \ + else \ + { \ + return 0; \ + } \ + } + +#define SPRINTREC( format ) \ + { \ + size_t count = strftime( s + rc, maxsize - rc, format, timeptr ); \ + if ( count == 0 ) \ + { \ + return 0; \ + } \ + else \ + { \ + rc += count; \ + } \ + } + size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB_restrict format, const struct tm * _PDCLIB_restrict timeptr ) { size_t rc = 0; @@ -135,53 +178,33 @@ size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB case 'a': { /* tm_wday abbreviated */ - if ( ! sprints( s, _PDCLIB_lconv.day_name_abbr[ timeptr->tm_wday ], maxsize, &rc ) ) - { - return 0; - } + SPRINTSTR( _PDCLIB_lconv.day_name_abbr, timeptr->tm_wday, 6 ); break; } case 'A': { /* tm_wday full */ - if ( ! sprints( s, _PDCLIB_lconv.day_name_full[ timeptr->tm_wday ], maxsize, &rc ) ) - { - return 0; - } + SPRINTSTR( _PDCLIB_lconv.day_name_full, timeptr->tm_wday, 6 ); break; } case 'b': case 'h': { /* tm_mon abbreviated */ - if ( ! sprints( s, _PDCLIB_lconv.month_name_abbr[ timeptr->tm_mon ], maxsize, &rc ) ) - { - return 0; - } + SPRINTSTR( _PDCLIB_lconv.month_name_abbr, timeptr->tm_mon, 11 ); break; } case 'B': { /* tm_mon full */ - if ( ! sprints( s, _PDCLIB_lconv.month_name_full[ timeptr->tm_mon ], maxsize, &rc ) ) - { - return 0; - } + SPRINTSTR( _PDCLIB_lconv.month_name_full, timeptr->tm_mon, 11 ); break; } case 'c': { /* locale's date / time representation, %a %b %e %T %Y for C locale */ /* 'E' for locale's alternative representation */ - size_t count = strftime( s + rc, maxsize - rc, _PDCLIB_lconv.date_time_format, timeptr ); - if ( count == 0 ) - { - return 0; - } - else - { - rc += count; - } + SPRINTREC( _PDCLIB_lconv.date_time_format ); break; } case 'C': @@ -219,15 +242,7 @@ size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB case 'D': { /* %m/%d/%y */ - size_t count = strftime( s + rc, maxsize - rc, "%m/%d/%y", timeptr ); - if ( count == 0 ) - { - return 0; - } - else - { - rc += count; - } + SPRINTREC( "%m/%d/%y" ); break; } case 'e': @@ -249,15 +264,7 @@ size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB case 'F': { /* %Y-%m-%d */ - size_t count = strftime( s + rc, maxsize - rc, "%Y-%m-%d", timeptr ); - if ( count == 0 ) - { - return 0; - } - else - { - rc += count; - } + SPRINTREC( "%Y-%m-%d" ); break; } case 'g': @@ -265,17 +272,7 @@ size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB /* last 2 digits of the week-based year as decimal (00-99) */ if ( rc < ( maxsize - 2 ) ) { - int week = iso_week( timeptr ); - int bias = 0; - if ( week >= 52 && timeptr->tm_mon == 0 ) - { - --bias; - } - else if ( week == 1 && timeptr->tm_mon == 11 ) - { - ++bias; - } - div_t year = div( timeptr->tm_year % 100 + bias, 10 ); + div_t year = div( week_calc( timeptr, E_ISO_YEAR ) % 100, 10 ); s[rc++] = '0' + year.quot; s[rc++] = '0' + year.rem; } @@ -290,16 +287,7 @@ size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB /* week-based year as decimal (e.g. 1997) */ if ( rc < ( maxsize - 4 ) ) { - int week = iso_week( timeptr ); - int year = timeptr->tm_year + 1900; - if ( week >= 52 && timeptr->tm_mon == 0 ) - { - --year; - } - else if ( week == 1 && timeptr->tm_mon == 11 ) - { - ++year; - } + int year = week_calc( timeptr, E_ISO_YEAR ); for ( int i = 3; i >= 0; --i ) { div_t digit = div( year, 10 ); @@ -404,45 +392,19 @@ size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB case 'p': { /* tm_hour locale's AM/PM designations */ - const char * designation = _PDCLIB_lconv.am_pm[ timeptr->tm_hour > 11 ]; - size_t len = strlen( designation ); - if ( rc < ( maxsize - len ) ) - { - strcpy( s + rc, designation ); - rc += len; - } - else - { - return 0; - } + SPRINTSTR( _PDCLIB_lconv.am_pm, timeptr->tm_hour > 11, 1 ); break; } case 'r': { /* tm_hour / tm_min / tm_sec as locale's 12-hour clock time, %I:%M:%S %p for C locale */ - size_t count = strftime( s + rc, maxsize - rc, _PDCLIB_lconv.time_format_12h, timeptr ); - if ( count == 0 ) - { - return 0; - } - else - { - rc += count; - } + SPRINTREC( _PDCLIB_lconv.time_format_12h ); break; } case 'R': { /* %H:%M */ - size_t count = strftime( s + rc, maxsize - rc, "%H:%M", timeptr ); - if ( count == 0 ) - { - return 0; - } - else - { - rc += count; - } + SPRINTREC( "%H:%M" ); break; } case 'S': @@ -470,15 +432,7 @@ size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB case 'T': { /* %H:%M:%S */ - size_t count = strftime( s + rc, maxsize - rc, "%H:%M:%S", timeptr ); - if ( count == 0 ) - { - return 0; - } - else - { - rc += count; - } + SPRINTREC( "%H:%M:%S" ); break; } case 'u': @@ -494,7 +448,7 @@ size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB /* 'O' for locale's alternative numeric symbols */ if ( rc < ( maxsize - 2 ) ) { - div_t week = div( weeknr( timeptr, E_SUNDAY ), 10 ); + div_t week = div( week_calc( timeptr, E_SUNDAY ), 10 ); s[rc++] = '0' + week.quot; s[rc++] = '0' + week.rem; } @@ -510,7 +464,7 @@ size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB /* 'O' for locale's alternative numeric symbols */ if ( rc < ( maxsize - 2 ) ) { - div_t week = div( iso_week( timeptr ), 10 ); + div_t week = div( week_calc( timeptr, E_ISO_WEEK ), 10 ); s[rc++] = '0' + week.quot; s[rc++] = '0' + week.rem; } @@ -533,7 +487,7 @@ size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB /* 'O' for locale's alternative numeric symbols */ if ( rc < ( maxsize - 2 ) ) { - div_t week = div( weeknr( timeptr, E_MONDAY ), 10 ); + div_t week = div( week_calc( timeptr, E_MONDAY ), 10 ); s[rc++] = '0' + week.quot; s[rc++] = '0' + week.rem; } @@ -547,30 +501,14 @@ size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB { /* locale's date representation, %m/%d/%y for C locale */ /* 'E' for locale's alternative representation */ - size_t count = strftime( s + rc, maxsize - rc, _PDCLIB_lconv.date_format, timeptr ); - if ( count == 0 ) - { - return 0; - } - else - { - rc += count; - } + SPRINTREC( _PDCLIB_lconv.date_format ); break; } case 'X': { /* locale's time representation, %T for C locale */ /* 'E' for locale's alternative representation */ - size_t count = strftime( s + rc, maxsize - rc, _PDCLIB_lconv.time_format, timeptr ); - if ( count == 0 ) - { - return 0; - } - else - { - rc += count; - } + SPRINTREC( _PDCLIB_lconv.time_format ); break; } case 'y':