diff options
| author | Rich Felker <dalias@aerifal.cx> | 2024-05-06 18:40:23 -0400 | 
|---|---|---|
| committer | Rich Felker <dalias@aerifal.cx> | 2024-05-06 19:04:55 -0400 | 
| commit | fced99e93daeefb0192fd16304f978d4401d1d77 (patch) | |
| tree | f4343f420cca32b240ce95527cc56ce6440435dc | |
| parent | 3f9d4224d8db7868b6c2f526746d597785d30c61 (diff) | |
| download | musl-fced99e93daeefb0192fd16304f978d4401d1d77.tar.gz | |
strptime: implement conversion specifiers adopted for next POSIX issue
the %s conversion is added as the outcome of Austin Group tracker
issue 169 and its unspecified behavior is clarified as the outcome of
issue 1727.
the %F, %g, %G, %u, %V, %z, and %Z conversions are added as the
outcome of Austin Group tracker issue 879 for alignment with strftime
and the behaviors of %u, %z, and %Z are defined as the outcome of
issue 1727.
at this time, the conversions with unspecified effects on struct tm
are all left as parse-only no-ops. this may be changed at a later
time, particularly for %s, if there is reasonable cross-implementation
consensus outside the standards process on what the behavior should
be.
| -rw-r--r-- | src/time/strptime.c | 66 | 
1 files changed, 65 insertions, 1 deletions
diff --git a/src/time/strptime.c b/src/time/strptime.c index c54a0d8c..b1147242 100644 --- a/src/time/strptime.c +++ b/src/time/strptime.c @@ -59,6 +59,22 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri  			s = strptime(s, "%m/%d/%y", tm);  			if (!s) return 0;  			break; +		case 'F': +			/* Use temp buffer to implement the odd requirement +			 * that entire field be width-limited but the year +			 * subfield not itself be limited. */ +			i = 0; +			char tmp[20]; +			if (*s == '-' || *s == '+') tmp[i++] = *s++; +			while (*s=='0' && isdigit(s[1])) s++; +			for (; *s && i<(size_t)w && i+1<sizeof tmp; i++) { +				tmp[i] = *s++; +			} +			tmp[i] = 0; +			char *p = strptime(tmp, "%12Y-%m-%d", tm); +			if (!p) return 0; +			s -= tmp+i-p; +			break;  		case 'H':  			dest = &tm->tm_hour;  			min = 0; @@ -114,6 +130,13 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri  			s = strptime(s, "%H:%M", tm);  			if (!s) return 0;  			break; +		case 's': +			/* Parse only. Effect on tm is unspecified +			 * and presently no effect is implemented.. */ +			if (*s == '-') s++; +			if (!isdigit(*s)) return 0; +			while (isdigit(*s)) s++; +			break;  		case 'S':  			dest = &tm->tm_sec;  			min = 0; @@ -125,11 +148,30 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri  			break;  		case 'U':  		case 'W': -			/* Throw away result, for now. (FIXME?) */ +			/* Throw away result of %U, %V, %W, %g, and %G. Effect +			 * is unspecified and there is no clear right choice. */  			dest = &dummy;  			min = 0;  			range = 54;  			goto numeric_range; +		case 'V': +			dest = &dummy; +			min = 1; +			range = 53; +			goto numeric_range; +		case 'g': +			dest = &dummy; +			w = 2; +			goto numeric_digits; +		case 'G': +			dest = &dummy; +			if (w<0) w=4; +			goto numeric_digits; +		case 'u': +			dest = &tm->tm_wday; +			min = 1; +			range = 7; +			goto numeric_range;  		case 'w':  			dest = &tm->tm_wday;  			min = 0; @@ -154,6 +196,28 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri  			adj = 1900;  			want_century = 0;  			goto numeric_digits; +		case 'z': +			if (*s == '+') neg = 0; +			else if (*s == '-') neg = 1; +			else return 0; +			for (i=0; i<4; i++) if (!isdigit(s[1+i])) return 0; +			tm->__tm_gmtoff = (s[1]-'0')*36000+(s[2]-'0')*3600 +				+ (s[3]-'0')*600 + (s[4]-'0')*60; +			if (neg) tm->__tm_gmtoff = -tm->__tm_gmtoff; +			s += 5; +			break; +		case 'Z': +			if (!strncmp(s, tzname[0], len = strlen(tzname[0]))) { +				tm->tm_isdst = 0; +				s += len; +			} else if (!strncmp(s, tzname[1], len=strlen(tzname[1]))) { +				tm->tm_isdst = 1; +				s += len; +			} else { +				/* FIXME: is this supposed to be an error? */ +				while ((*s|32)-'a' <= 'z'-'a') s++; +			} +			break;  		case '%':  			if (*s++ != '%') return 0;  			break;  | 
