]> pd.if.org Git - pdclib/commitdiff
Basic implementation of strftime(), untested.
authorMartin Baute <solar@rootdirectory.de>
Tue, 29 Mar 2016 06:21:15 +0000 (08:21 +0200)
committerMartin Baute <solar@rootdirectory.de>
Tue, 29 Mar 2016 06:21:15 +0000 (08:21 +0200)
functions/time/strftime.c
includes/locale.h
platform/example/functions/_PDCLIB/_PDCLIB_stdinit.c

index 715a321adbde1d8e10edcd73972bc766077a2ad1..eb32a167c8eacc9f7e604fda31ba8b4e2de53d3f 100644 (file)
@@ -5,17 +5,20 @@
 */
 
 #include <time.h>
 */
 
 #include <time.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <string.h>
 
 #ifndef REGTEST
 
 
 #ifndef REGTEST
 
+/* TODO: Alternative representations / numerals not supported. */
+
+/* This implementation's code is highly repetitive, but I did not really
+   care for putting it into a number of macros / helper functions.
+*/
+
 size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB_restrict format, const struct tm * _PDCLIB_restrict timeptr )
 {
 size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB_restrict format, const struct tm * _PDCLIB_restrict timeptr )
 {
-    /*
-    If the total number of resulting characters including the terminating null character is not
-    more than maxsize, the strftime function returns the number of characters placed
-    into the array pointed to by s not including the terminating null character.
-    (i.e., < maxsize)
-    */
     size_t rc = 0;
 
     while ( rc < maxsize )
     size_t rc = 0;
 
     while ( rc < maxsize )
@@ -33,12 +36,12 @@ size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB
         }
         else
         {
         }
         else
         {
-            char flag = 0;
+            /* char flag = 0; */
             switch ( *++format )
             {
                 case 'E':
                 case 'O':
             switch ( *++format )
             {
                 case 'E':
                 case 'O':
-                    flag = *format++;
+                    /* flag = *format++; */
                     break;
                 default:
                     /* EMPTY */
                     break;
                 default:
                     /* EMPTY */
@@ -47,133 +50,477 @@ size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB
             switch( *format++ )
             {
                 case 'a':
             switch( *format++ )
             {
                 case 'a':
-                    /* tm_wday abbreviated */
-                    break;
+                    {
+                        /* tm_wday abbreviated */
+                        const char * day = _PDCLIB_lconv.day_name_abbr[ timeptr->tm_wday ];
+                        size_t len = strlen( day );
+                        if ( rc < ( maxsize - len ) )
+                        {
+                            strcpy( s, day );
+                            rc += len;
+                        }
+                        else
+                        {
+                            return 0;
+                        }
+                        break;
+                    }
                 case 'A':
                 case 'A':
-                    /* tm_wday full */
-                    break;
+                    {
+                        /* tm_wday full */
+                        const char * day = _PDCLIB_lconv.day_name_full[ timeptr->tm_wday ];
+                        size_t len = strlen( day );
+                        if ( rc < ( maxsize - len ) )
+                        {
+                            strcpy( s, day );
+                            rc += len;
+                        }
+                        else
+                        {
+                            return 0;
+                        }
+                        break;
+                    }
                 case 'b':
                 case 'h':
                 case 'b':
                 case 'h':
-                    /* tm_mon abbreviated */
-                    break;
+                    {
+                        /* tm_mon abbreviated */
+                        const char * month = _PDCLIB_lconv.month_name_abbr[ timeptr->tm_mon ];
+                        size_t len = strlen( month );
+                        if ( rc < ( maxsize - len ) )
+                        {
+                            strcpy( s, month );
+                            rc += len;
+                        }
+                        else
+                        {
+                            return 0;
+                        }
+                        break;
+                    }
                 case 'B':
                 case 'B':
-                    /* tm_mon full */
-                    break;
+                    {
+                        /* tm_mon full */
+                        const char * month = _PDCLIB_lconv.month_name_full[ timeptr->tm_mon ];
+                        size_t len = strlen( month );
+                        if ( rc < ( maxsize - len ) )
+                        {
+                            strcpy( s, month );
+                            rc += len;
+                        }
+                        else
+                        {
+                            return 0;
+                        }
+                        break;
+                    }
                 case 'c':
                 case 'c':
-                    /* locale's date / time representation, %a %b %e %T %Y for C locale */
-                    /* 'E' for locale's alternative representation */
-                    break;
+                    {
+                        /* locale's date / time representation, %a %b %e %T %Y for C locale */
+                        /* 'E' for locale's alternative representation */
+                        size_t count = strftime( s, maxsize - rc, _PDCLIB_lconv.date_time_format, timeptr );
+                        if ( count == 0 )
+                        {
+                            return 0;
+                        }
+                        else
+                        {
+                            rc += count;
+                        }
+                        break;
+                    }
                 case 'C':
                 case 'C':
-                    /* tm_year divided by 100, truncated to decimal (00-99) */
-                    /* 'E' for base year (period) in locale's alternative representation */
-                    break;
+                    {
+                        /* tm_year divided by 100, truncated to decimal (00-99) */
+                        /* 'E' for base year (period) in locale's alternative representation */
+                        if ( rc < ( maxsize - 2 ) )
+                        {
+                            div_t period = div( ( timeptr->tm_year / 100 ), 10 );
+                            *s++ = '0' + period.quot;
+                            *s++ = '0' + period.rem;
+                            rc += 2;
+                        }
+                        else
+                        {
+                            return 0;
+                        }
+                        break;
+                    }
                 case 'd':
                 case 'd':
-                    /* tm_mday as decimal (01-31) */
-                    /* 'O' for locale's alternative numeric symbols */
-                    break;
+                    {
+                        /* tm_mday as decimal (01-31) */
+                        /* 'O' for locale's alternative numeric symbols */
+                        if ( rc < ( maxsize - 2 ) )
+                        {
+                            div_t day = div( timeptr->tm_mday, 10 );
+                            *s++ = '0' + day.quot;
+                            *s++ = '0' + day.rem;
+                            rc += 2;
+                        }
+                        else
+                        {
+                            return 0;
+                        }
+                        break;
+                    }
                 case 'D':
                 case 'D':
-                    /* %m/%d/%y */
-                    break;
+                    {
+                        /* %m/%d/%y */
+                        size_t count = strftime( s, maxsize - rc, "%m/%d/%y", timeptr );
+                        if ( count == 0 )
+                        {
+                            return 0;
+                        }
+                        else
+                        {
+                            rc += count;
+                        }
+                        break;
+                    }
                 case 'e':
                 case 'e':
-                    /* tm_mday as decimal ( 1-31) */
-                    /* 'O' for locale's alternative numeric symbols */
-                    break;
+                    {
+                        /* tm_mday as decimal ( 1-31) */
+                        /* 'O' for locale's alternative numeric symbols */
+                        if ( rc < ( maxsize - 2 ) )
+                        {
+                            div_t day = div( timeptr->tm_mday, 10 );
+                            *s++ = ( day.quot > 0 ) ? '0' + day.quot : ' ';
+                            *s++ = '0' + day.rem;
+                            rc += 2;
+                        }
+                        else
+                        {
+                            return 0;
+                        }
+                        break;
+                    }
                 case 'F':
                 case 'F':
-                    /* %Y-%m-%d */
-                    break;
+                    {
+                        /* %Y-%m-%d */
+                        size_t count = strftime( s, maxsize - rc, "%Y-%m-%d", timeptr );
+                        if ( count == 0 )
+                        {
+                            return 0;
+                        }
+                        else
+                        {
+                            rc += count;
+                        }
+                        break;
+                    }
                 case 'g':
                 case 'g':
-                    /* last 2 digits of the week-based year as decimal (00-99) */
-                    break;
+                    {
+                        /* last 2 digits of the week-based year as decimal (00-99) */
+                        /* TODO: 'g' */
+                        break;
+                    }
                 case 'G':
                 case 'G':
-                    /* week-based year as decimal (e.g. 1997) */
-                    break;
+                    {
+                        /* week-based year as decimal (e.g. 1997) */
+                        /* TODO: 'G' */
+                        break;
+                    }
                 case 'H':
                 case 'H':
-                    /* tm_hour as 24h decimal (00-23) */
-                    /* 'O' for locale's alternative numeric symbols */
-                    break;
+                    {
+                        /* tm_hour as 24h decimal (00-23) */
+                        /* 'O' for locale's alternative numeric symbols */
+                        if ( rc < ( maxsize - 2 ) )
+                        {
+                            div_t hour = div( timeptr->tm_hour, 10 );
+                            *s++ = '0' + hour.quot;
+                            *s++ = '0' + hour.rem;
+                            rc += 2;
+                        }
+                        else
+                        {
+                            return 0;
+                        }
+                        break;
+                    }
                 case 'I':
                 case 'I':
-                    /* tm_hour as 12h decimal (01-12) */
-                    /* 'O' for locale's alternative numeric symbols */
-                    break;
+                    {
+                        /* tm_hour as 12h decimal (01-12) */
+                        /* 'O' for locale's alternative numeric symbols */
+                        if ( rc < ( maxsize - 2 ) )
+                        {
+                            div_t hour = div( ( timeptr->tm_hour + 1 ) % 12, 10 );
+                            *s++ = '0' + hour.quot;
+                            *s++ = '0' + hour.rem;
+                            rc += 2;
+                        }
+                        else
+                        {
+                            return 0;
+                        }
+                        break;
+                    }
                 case 'j':
                 case 'j':
-                    /* tm_yday as decimal (001-366) */
-                    break;
+                    {
+                        /* tm_yday as decimal (001-366) */
+                        if ( rc < ( maxsize - 3 ) )
+                        {
+                            div_t yday = div( timeptr->tm_yday, 100 );
+                            *s++ = '0' + yday.quot;
+                            *s++ = '0' + yday.rem / 10;
+                            *s++ = '0' + yday.rem % 10;
+                            rc += 3;
+                        }
+                        else
+                        {
+                            return 0;
+                        }
+                        break;
+                    }
                 case 'm':
                 case 'm':
-                    /* tm_mon as decimal (01-12) */
-                    /* 'O' for locale's alternative numeric symbols */
-                    break;
+                    {
+                        /* tm_mon as decimal (01-12) */
+                        /* 'O' for locale's alternative numeric symbols */
+                        if ( rc < ( maxsize - 2 ) )
+                        {
+                            div_t mon = div( timeptr->tm_mon + 1, 10 );
+                            *s++ = '0' + mon.quot;
+                            *s++ = '0' + mon.rem;
+                            rc += 2;
+                        }
+                        else
+                        {
+                            return 0;
+                        }
+                        break;
+                    }
                 case 'M':
                 case 'M':
-                    /* tm_min as decimal (00-59) */
-                    /* 'O' for locale's alternative numeric symbols */
-                    break;
+                    {
+                        /* tm_min as decimal (00-59) */
+                        /* 'O' for locale's alternative numeric symbols */
+                        if ( rc < ( maxsize - 2 ) )
+                        {
+                            div_t min = div( timeptr->tm_min + 1, 10 );
+                            *s++ = '0' + min.quot;
+                            *s++ = '0' + min.rem;
+                            rc += 2;
+                        }
+                        else
+                        {
+                            return 0;
+                        }
+                        break;
+                    }
                 case 'n':
                 case 'n':
-                    /* newline */
-                    break;
+                    {
+                        /* newline */
+                        *s++ = '\n';
+                        ++rc;
+                        break;
+                    }
                 case 'p':
                 case 'p':
-                    /* tm_hour locale's AM/PM designations */
-                    break;
+                    {
+                        /* 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, designation );
+                            rc += len;
+                        }
+                        else
+                        {
+                            return 0;
+                        }
+                        break;
+                    }
                 case 'r':
                 case 'r':
-                    /* tm_hour / tm_min / tm_sec as locale's 12-hour clock time, %I:%M:%S %p for C locale */
-                    break;
+                    {
+                        /* 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, maxsize - rc, _PDCLIB_lconv.time_format_12h, timeptr );
+                        if ( count == 0 )
+                        {
+                            return 0;
+                        }
+                        else
+                        {
+                            rc += count;
+                        }
+                        break;
+                    }
                 case 'R':
                 case 'R':
-                    /* %H:%M */
-                    break;
+                    {
+                        /* %H:%M */
+                        size_t count = strftime( s, maxsize - rc, "%H:%M", timeptr );
+                        if ( count == 0 )
+                        {
+                            return 0;
+                        }
+                        else
+                        {
+                            rc += count;
+                        }
+                        break;
+                    }
                 case 'S':
                 case 'S':
-                    /* tm_sec as decimal (00-60) */
-                    /* 'O' for locale's alternative numeric symbols */
-                    break;
+                    {
+                        /* tm_sec as decimal (00-60) */
+                        /* 'O' for locale's alternative numeric symbols */
+                        if ( rc < ( maxsize - 2 ) )
+                        {
+                            div_t sec = div( timeptr->tm_sec + 1, 10 );
+                            *s++ = '0' + sec.quot;
+                            *s++ = '0' + sec.rem;
+                            rc += 2;
+                        }
+                        else
+                        {
+                            return 0;
+                        }
+                        break;
+                    }
                 case 't':
                 case 't':
-                    /* tabulator */
-                    break;
+                    {
+                        /* tabulator */
+                        *s++ = '\t';
+                        ++rc;
+                        break;
+                    }
                 case 'T':
                 case 'T':
-                    /* %H:%M:%S */
-                    break;
+                    {
+                        /* %H:%M:%S */
+                        size_t count = strftime( s, maxsize - rc, "%H:%M:%S", timeptr );
+                        if ( count == 0 )
+                        {
+                            return 0;
+                        }
+                        else
+                        {
+                            rc += count;
+                        }
+                        break;
+                    }
                 case 'u':
                 case 'u':
-                    /* tm_wday as decimal (1-7) with Monday == 1 */
-                    /* 'O' for locale's alternative numeric symbols */
-                    break;
+                    {
+                        /* tm_wday as decimal (1-7) with Monday == 1 */
+                        /* 'O' for locale's alternative numeric symbols */
+                        *s++ = ( timeptr->tm_wday == 0 ) ? '7' : '0' + timeptr->tm_wday;
+                        ++rc;
+                        break;
+                    }
                 case 'U':
                 case 'U':
-                    /* week number of the year (first Sunday as the first day of week 1) as decimal (00-53) */
-                    /* 'O' for locale's alternative numeric symbols */
-                    break;
+                    {
+                        /* week number of the year (first Sunday as the first day of week 1) as decimal (00-53) */
+                        /* 'O' for locale's alternative numeric symbols */
+                        /* TODO: 'U' */
+                        break;
+                    }
                 case 'V':
                 case 'V':
-                    /* week number as decimal (01-53) */
-                    /* 'O' for locale's alternative numeric symbols */
-                    break;
+                    {
+                        /* week number as decimal (01-53) */
+                        /* 'O' for locale's alternative numeric symbols */
+                        /* TODO: 'V' */
+                        break;
+                    }
                 case 'w':
                 case 'w':
-                    /* tm_wday as decimal number (0-6) with Sunday == 0 */
-                    /* 'O' for locale's alternative numeric symbols */
-                    break;
+                    {
+                        /* tm_wday as decimal number (0-6) with Sunday == 0 */
+                        /* 'O' for locale's alternative numeric symbols */
+                        *s++ = '0' + timeptr->tm_wday;
+                        ++rc;
+                        break;
+                    }
                 case 'W':
                 case 'W':
-                    /* week number of the year (first Monday as the first day of week 1) as decimal (00-53) */
-                    /* 'O' for locale's alternative numeric symbols */
-                    break;
+                    {
+                        /* week number of the year (first Monday as the first day of week 1) as decimal (00-53) */
+                        /* 'O' for locale's alternative numeric symbols */
+                        /* TODO: 'W' */
+                        break;
+                    }
                 case 'x':
                 case 'x':
-                    /* locale's date representation, %m/%d/%y for C locale */
-                    /* 'E' for locale's alternative representation */
-                    break;
+                    {
+                        /* locale's date representation, %m/%d/%y for C locale */
+                        /* 'E' for locale's alternative representation */
+                        size_t count = strftime( s, maxsize - rc, _PDCLIB_lconv.date_format, timeptr );
+                        if ( count == 0 )
+                        {
+                            return 0;
+                        }
+                        else
+                        {
+                            rc += count;
+                        }
+                        break;
+                    }
                 case 'X':
                 case 'X':
-                    /* locale's time representation, %T for C locale */
-                    /* 'E' for locale's alternative representation */
-                    break;
+                    {
+                        /* locale's time representation, %T for C locale */
+                        /* 'E' for locale's alternative representation */
+                        size_t count = strftime( s, maxsize - rc, _PDCLIB_lconv.time_format, timeptr );
+                        if ( count == 0 )
+                        {
+                            return 0;
+                        }
+                        else
+                        {
+                            rc += count;
+                        }
+                        break;
+                    }
                 case 'y':
                 case 'y':
-                    /* last 2 digits of tm_year as decimal (00-99) */
-                    /* 'E' for offset from %EC (year only) in locale's alternative representation */
-                    /* 'O' for locale's alternative numeric symbols */
-                    break;
+                    {
+                        /* last 2 digits of tm_year as decimal (00-99) */
+                        /* 'E' for offset from %EC (year only) in locale's alternative representation */
+                        /* 'O' for locale's alternative numeric symbols */
+                        if ( rc < ( maxsize - 2 ) )
+                        {
+                            div_t year = div( ( timeptr->tm_year % 100 ), 10 );
+                            *s++ = '0' + year.quot;
+                            *s++ = '0' + year.rem;
+                            rc += 2;
+                        }
+                        else
+                        {
+                            return 0;
+                        }
+                        break;
+                    }
                 case 'Y':
                 case 'Y':
-                    /* tm_year as decimal (e.g. 1997) */
-                    /* 'E' for locale's alternative representation */
-                    break;
+                    {
+                        /* tm_year as decimal (e.g. 1997) */
+                        /* 'E' for locale's alternative representation */
+                        if ( rc < ( maxsize - 4 ) )
+                        {
+                            int year = timeptr->tm_year;
+
+                            for ( int i = 3; i >= 0; --i )
+                            {
+                                div_t digit = div( year, 10 );
+                                s[i] = '0' + digit.rem;
+                                year = digit.quot;
+                            }
+
+                            rc += 4;
+                        }
+                        else
+                        {
+                            return 0;
+                        }
+                        break;
+                    }
                 case 'z':
                 case 'z':
-                    /* tm_isdst / UTC offset in ISO8601 format (e.g. -0430 meaning 4 hours 30 minutes behind Greenwich), or no characters */
-                    break;
+                    {
+                        /* tm_isdst / UTC offset in ISO8601 format (e.g. -0430 meaning 4 hours 30 minutes behind Greenwich), or no characters */
+                        /* TODO: 'z' */
+                        break;
+                    }
                 case 'Z':
                 case 'Z':
-                    /* tm_isdst / locale's time zone name or abbreviation, or no characters */
-                    break;
+                    {
+                        /* tm_isdst / locale's time zone name or abbreviation, or no characters */
+                        /* TODO: 'Z' */
+                        break;
+                    }
                 case '%':
                 case '%':
-                    /* '%' character */
-                    break;
+                    {
+                        /* '%' character */
+                        *s++ = '%';
+                        ++rc;
+                        break;
+                    }
             }
         }
     }
             }
         }
     }
index da9138245082ee2995d9471690725893d2b59c9b..e2682ac10bb81a9a132ac8301b343c8b44e10975 100644 (file)
@@ -34,10 +34,15 @@ struct lconv
 {
     struct _PDCLIB_ctype_t * ctype;  /* internal <ctype.h> information        */
     char * _PDCLIB_errno_texts[_PDCLIB_ERRNO_MAX]; /* strerror() / perror()   */
 {
     struct _PDCLIB_ctype_t * ctype;  /* internal <ctype.h> information        */
     char * _PDCLIB_errno_texts[_PDCLIB_ERRNO_MAX]; /* strerror() / perror()   */
-    char * _PDCLIB_month_name_abbr[12]; /* month names, abbreviated           */
-    char * _PDCLIB_month_name_full[12]; /* month names, full                  */
-    char * _PDCLIB_day_name_abbr[7];    /* weekday names, abbreviated         */
-    char * _PDCLIB_day_name_full[7];    /* weekday names, full                */
+    char * month_name_abbr[12]; /* month names, abbreviated                   */
+    char * month_name_full[12]; /* month names, full                          */
+    char * day_name_abbr[7];    /* weekday names, abbreviated                 */
+    char * day_name_full[7];    /* weekday names, full                        */
+    char * date_time_format;    /* date / time format for strftime( "%c" )    */
+    char * time_format_12h;     /* 12-hour time format for strftime( "%r" )   */
+    char * date_format;         /* date format for strftime( "%x" )           */
+    char * time_format;         /* time format for strftime( "%X" )           */
+    char * am_pm[2];            /* AM / PM designation                        */
     char * decimal_point;      /* decimal point character                     */
     char * thousands_sep;      /* character for seperating groups of digits   */
     char * grouping;           /* string indicating the size of digit groups  */
     char * decimal_point;      /* decimal point character                     */
     char * thousands_sep;      /* character for seperating groups of digits   */
     char * grouping;           /* string indicating the size of digit groups  */
index 9bcf4559fd291dc14fd77fa00204e98c1928c98c..f0ac4d3d738e1f83ade77f4b6ca6d962acc06e7a 100644 (file)
@@ -361,6 +361,15 @@ struct lconv _PDCLIB_lconv = {
         (char *)"Friday",
         (char *)"Saturday"
     },
         (char *)"Friday",
         (char *)"Saturday"
     },
+    /* date / time format */ (char *)"%a %b %e %T %Y",
+    /* 12h time format    */ (char *)"%I:%M:%S %p",
+    /* date format        */ (char *)"%m/%d/%y",
+    /* time format        */ (char *)"%T",
+    /* AM / PM designation */
+    {
+        (char *)"AM",
+        (char *)"PM"
+    },
     /* decimal_point      */ (char *)".",
     /* thousands_sep      */ (char *)"",
     /* grouping           */ (char *)"",
     /* decimal_point      */ (char *)".",
     /* thousands_sep      */ (char *)"",
     /* grouping           */ (char *)"",