remove LFS64 programming interfaces (macro-only) from _GNU_SOURCE
[musl] / src / time / strptime.c
index d1d141e..c54a0d8 100644 (file)
@@ -8,9 +8,10 @@
 
 char *strptime(const char *restrict s, const char *restrict f, struct tm *restrict tm)
 {
-       int i, w, neg, adj, min, range, *dest;
+       int i, w, neg, adj, min, range, *dest, dummy;
        const char *ex;
        size_t len;
+       int want_century = 0, century = 0, relyear = 0;
        while (*f) {
                if (*f != '%') {
                        if (isspace(*f)) for (; *s && isspace(*s); s++);
@@ -21,8 +22,13 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri
                }
                f++;
                if (*f == '+') f++;
-               if (isdigit(*f)) w=strtoul(f, (void *)&f, 10);
-               else w=-1;
+               if (isdigit(*f)) {
+                       char *new_f;
+                       w=strtoul(f, &new_f, 10);
+                       f = new_f;
+               } else {
+                       w=-1;
+               }
                adj=0;
                switch (*f++) {
                case 'a': case 'A':
@@ -40,6 +46,10 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri
                        if (!s) return 0;
                        break;
                case 'C':
+                       dest = &century;
+                       if (w<0) w=2;
+                       want_century |= 2;
+                       goto numeric_digits;
                case 'd': case 'e':
                        dest = &tm->tm_mday;
                        min = 1;
@@ -63,6 +73,7 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri
                        dest = &tm->tm_yday;
                        min = 1;
                        range = 366;
+                       adj = 1;
                        goto numeric_range;
                case 'm':
                        dest = &tm->tm_mon;
@@ -83,6 +94,7 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri
                        len = strlen(ex);
                        if (!strncasecmp(s, ex, len)) {
                                tm->tm_hour %= 12;
+                               s += len;
                                break;
                        }
                        ex = nl_langinfo(PM_STR);
@@ -90,6 +102,7 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri
                        if (!strncasecmp(s, ex, len)) {
                                tm->tm_hour %= 12;
                                tm->tm_hour += 12;
+                               s += len;
                                break;
                        }
                        return 0;
@@ -112,8 +125,11 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri
                        break;
                case 'U':
                case 'W':
-                       //FIXME
-                       return 0;
+                       /* Throw away result, for now. (FIXME?) */
+                       dest = &dummy;
+                       min = 0;
+                       range = 54;
+                       goto numeric_range;
                case 'w':
                        dest = &tm->tm_wday;
                        min = 0;
@@ -128,16 +144,21 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri
                        if (!s) return 0;
                        break;
                case 'y':
-                       //FIXME
-                       return 0;
+                       dest = &relyear;
+                       w = 2;
+                       want_century |= 1;
+                       goto numeric_digits;
                case 'Y':
                        dest = &tm->tm_year;
                        if (w<0) w=4;
                        adj = 1900;
+                       want_century = 0;
                        goto numeric_digits;
                case '%':
                        if (*s++ != '%') return 0;
                        break;
+               default:
+                       return 0;
                numeric_range:
                        if (!isdigit(*s)) return 0;
                        *dest = 0;
@@ -176,5 +197,10 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri
                        ;
                }
        }
+       if (want_century) {
+               tm->tm_year = relyear;
+               if (want_century & 2) tm->tm_year += century * 100 - 1900;
+               else if (tm->tm_year <= 68) tm->tm_year += 100;
+       }
        return (char *)s;
 }