master
  1#include <stdlib.h>
  2#include <langinfo.h>
  3#include <time.h>
  4#include <ctype.h>
  5#include <stddef.h>
  6#include <string.h>
  7#include <strings.h>
  8
  9char *strptime(const char *restrict s, const char *restrict f, struct tm *restrict tm)
 10{
 11	int i, w, neg, adj, min, range, *dest, dummy;
 12	const char *ex;
 13	size_t len;
 14	int want_century = 0, century = 0, relyear = 0;
 15	while (*f) {
 16		if (*f != '%') {
 17			if (isspace(*f)) for (; *s && isspace(*s); s++);
 18			else if (*s != *f) return 0;
 19			else s++;
 20			f++;
 21			continue;
 22		}
 23		f++;
 24		if (*f == '+') f++;
 25		if (isdigit(*f)) {
 26			char *new_f;
 27			w=strtoul(f, &new_f, 10);
 28			f = new_f;
 29		} else {
 30			w=-1;
 31		}
 32		adj=0;
 33		switch (*f++) {
 34		case 'a': case 'A':
 35			dest = &tm->tm_wday;
 36			min = ABDAY_1;
 37			range = 7;
 38			goto symbolic_range;
 39		case 'b': case 'B': case 'h':
 40			dest = &tm->tm_mon;
 41			min = ABMON_1;
 42			range = 12;
 43			goto symbolic_range;
 44		case 'c':
 45			s = strptime(s, nl_langinfo(D_T_FMT), tm);
 46			if (!s) return 0;
 47			break;
 48		case 'C':
 49			dest = &century;
 50			if (w<0) w=2;
 51			want_century |= 2;
 52			goto numeric_digits;
 53		case 'd': case 'e':
 54			dest = &tm->tm_mday;
 55			min = 1;
 56			range = 31;
 57			goto numeric_range;
 58		case 'D':
 59			s = strptime(s, "%m/%d/%y", tm);
 60			if (!s) return 0;
 61			break;
 62		case 'H':
 63			dest = &tm->tm_hour;
 64			min = 0;
 65			range = 24;
 66			goto numeric_range;
 67		case 'I':
 68			dest = &tm->tm_hour;
 69			min = 1;
 70			range = 12;
 71			goto numeric_range;
 72		case 'j':
 73			dest = &tm->tm_yday;
 74			min = 1;
 75			range = 366;
 76			adj = 1;
 77			goto numeric_range;
 78		case 'm':
 79			dest = &tm->tm_mon;
 80			min = 1;
 81			range = 12;
 82			adj = 1;
 83			goto numeric_range;
 84		case 'M':
 85			dest = &tm->tm_min;
 86			min = 0;
 87			range = 60;
 88			goto numeric_range;
 89		case 'n': case 't':
 90			for (; *s && isspace(*s); s++);
 91			break;
 92		case 'p':
 93			ex = nl_langinfo(AM_STR);
 94			len = strlen(ex);
 95			if (!strncasecmp(s, ex, len)) {
 96				tm->tm_hour %= 12;
 97				s += len;
 98				break;
 99			}
100			ex = nl_langinfo(PM_STR);
101			len = strlen(ex);
102			if (!strncasecmp(s, ex, len)) {
103				tm->tm_hour %= 12;
104				tm->tm_hour += 12;
105				s += len;
106				break;
107			}
108			return 0;
109		case 'r':
110			s = strptime(s, nl_langinfo(T_FMT_AMPM), tm);
111			if (!s) return 0;
112			break;
113		case 'R':
114			s = strptime(s, "%H:%M", tm);
115			if (!s) return 0;
116			break;
117		case 'S':
118			dest = &tm->tm_sec;
119			min = 0;
120			range = 61;
121			goto numeric_range;
122		case 'T':
123			s = strptime(s, "%H:%M:%S", tm);
124			if (!s) return 0;
125			break;
126		case 'U':
127		case 'W':
128			/* Throw away result, for now. (FIXME?) */
129			dest = &dummy;
130			min = 0;
131			range = 54;
132			goto numeric_range;
133		case 'w':
134			dest = &tm->tm_wday;
135			min = 0;
136			range = 7;
137			goto numeric_range;
138		case 'x':
139			s = strptime(s, nl_langinfo(D_FMT), tm);
140			if (!s) return 0;
141			break;
142		case 'X':
143			s = strptime(s, nl_langinfo(T_FMT), tm);
144			if (!s) return 0;
145			break;
146		case 'y':
147			dest = &relyear;
148			w = 2;
149			want_century |= 1;
150			goto numeric_digits;
151		case 'Y':
152			dest = &tm->tm_year;
153			if (w<0) w=4;
154			adj = 1900;
155			want_century = 0;
156			goto numeric_digits;
157		case '%':
158			if (*s++ != '%') return 0;
159			break;
160		default:
161			return 0;
162		numeric_range:
163			if (!isdigit(*s)) return 0;
164			*dest = 0;
165			for (i=1; i<=min+range && isdigit(*s); i*=10)
166				*dest = *dest * 10 + *s++ - '0';
167			if (*dest - min >= (unsigned)range) return 0;
168			*dest -= adj;
169			switch((char *)dest - (char *)tm) {
170			case offsetof(struct tm, tm_yday):
171				;
172			}
173			goto update;
174		numeric_digits:
175			neg = 0;
176			if (*s == '+') s++;
177			else if (*s == '-') neg=1, s++;
178			if (!isdigit(*s)) return 0;
179			for (*dest=i=0; i<w && isdigit(*s); i++)
180				*dest = *dest * 10 + *s++ - '0';
181			if (neg) *dest = -*dest;
182			*dest -= adj;
183			goto update;
184		symbolic_range:
185			for (i=2*range-1; i>=0; i--) {
186				ex = nl_langinfo(min+i);
187				len = strlen(ex);
188				if (strncasecmp(s, ex, len)) continue;
189				s += len;
190				*dest = i % range;
191				break;
192			}
193			if (i<0) return 0;
194			goto update;
195		update:
196			//FIXME
197			;
198		}
199	}
200	if (want_century) {
201		tm->tm_year = relyear;
202		if (want_century & 2) tm->tm_year += century * 100 - 1900;
203		else if (tm->tm_year <= 68) tm->tm_year += 100;
204	}
205	return (char *)s;
206}