text: #include <stdlib.h>
  #include <langinfo.h>
  #include <time.h>
  #include <ctype.h>
  #include <stddef.h>
  #include <string.h>
  #include <strings.h>
  
  char *strptime(const char *restrict s, const char *restrict f, struct tm *restrict tm)
  {
  	int i, w, neg, adj, min, range, *dest;
  	const char *ex;
  	size_t len;
  	while (*f) {
  		if (*f != '%') {
  			if (isspace(*f)) for (; *s && isspace(*s); s++);
  			else if (*s != *f) return 0;
  			else s++;
  			f++;
  			continue;
  		}
  		f++;
  		if (*f == '+') f++;
  		if (isdigit(*f)) w=strtoul(f, (void *)&f, 10);
  		else w=-1;
  		adj=0;
  		switch (*f++) {
  		case 'a': case 'A':
  			dest = &tm->tm_wday;
  			min = ABDAY_1;
  			range = 7;
  			goto symbolic_range;
  		case 'b': case 'B': case 'h':
  			dest = &tm->tm_mon;
  			min = ABMON_1;
  			range = 12;
  			goto symbolic_range;
  		case 'c':
  			s = strptime(s, nl_langinfo(D_T_FMT), tm);
  			if (!s) return 0;
  			break;
  		case 'C':
  		case 'd': case 'e':
  			dest = &tm->tm_mday;
  			min = 1;
  			range = 31;
  			goto numeric_range;
  		case 'D':
  			s = strptime(s, "%m/%d/%y", tm);
  			if (!s) return 0;
  			break;
  		case 'H':
  			dest = &tm->tm_hour;
  			min = 0;
  			range = 24;
  			goto numeric_range;
  		case 'I':
  			dest = &tm->tm_hour;
  			min = 1;
  			range = 12;
  			goto numeric_range;
  		case 'j':
  			dest = &tm->tm_yday;
  			min = 1;
  			range = 366;
  			goto numeric_range;
  		case 'm':
  			dest = &tm->tm_mon;
  			min = 1;
  			range = 12;
  			adj = 1;
  			goto numeric_range;
  		case 'M':
  			dest = &tm->tm_min;
  			min = 0;
  			range = 60;
  			goto numeric_range;
  		case 'n': case 't':
  			for (; *s && isspace(*s); s++);
  			break;
  		case 'p':
  			ex = nl_langinfo(AM_STR);
  			len = strlen(ex);
  			if (!strncasecmp(s, ex, len)) {
  				tm->tm_hour %= 12;
  				break;
  			}
  			ex = nl_langinfo(PM_STR);
  			len = strlen(ex);
  			if (!strncasecmp(s, ex, len)) {
  				tm->tm_hour %= 12;
  				tm->tm_hour += 12;
  				break;
  			}
  			return 0;
  		case 'r':
  			s = strptime(s, nl_langinfo(T_FMT_AMPM), tm);
  			if (!s) return 0;
  			break;
  		case 'R':
  			s = strptime(s, "%H:%M", tm);
  			if (!s) return 0;
  			break;
  		case 'S':
  			dest = &tm->tm_sec;
  			min = 0;
  			range = 61;
  			goto numeric_range;
  		case 'T':
  			s = strptime(s, "%H:%M:%S", tm);
  			if (!s) return 0;
  			break;
  		case 'U':
  		case 'W':
  			//FIXME
  			return 0;
  		case 'w':
  			dest = &tm->tm_wday;
  			min = 0;
  			range = 7;
  			goto numeric_range;
  		case 'x':
  			s = strptime(s, nl_langinfo(D_FMT), tm);
  			if (!s) return 0;
  			break;
  		case 'X':
  			s = strptime(s, nl_langinfo(T_FMT), tm);
  			if (!s) return 0;
  			break;
  		case 'y':
  			//FIXME
  			return 0;
  		case 'Y':
  			dest = &tm->tm_year;
  			if (w<0) w=4;
  			adj = 1900;
  			goto numeric_digits;
  		case '%':
  			if (*s++ != '%') return 0;
  			break;
  		numeric_range:
  			if (!isdigit(*s)) return 0;
  			*dest = 0;
  			for (i=1; i<=min+range && isdigit(*s); i*=10)
  				*dest = *dest * 10 + *s++ - '0';
  			if (*dest - min >= (unsigned)range) return 0;
  			*dest -= adj;
  			switch((char *)dest - (char *)tm) {
  			case offsetof(struct tm, tm_yday):
  				;
  			}
  			goto update;
  		numeric_digits:
  			neg = 0;
  			if (*s == '+') s++;
  			else if (*s == '-') neg=1, s++;
  			if (!isdigit(*s)) return 0;
  			for (*dest=i=0; i<w && isdigit(*s); i++)
  				*dest = *dest * 10 + *s++ - '0';
  			if (neg) *dest = -*dest;
  			*dest -= adj;
  			goto update;
  		symbolic_range:
  			for (i=2*range-1; i>=0; i--) {
  				ex = nl_langinfo(min+i);
  				len = strlen(ex);
  				if (strncasecmp(s, ex, len)) continue;
  				s += len;
  				*dest = i % range;
  				break;
  			}
  			if (i<0) return 0;
  			goto update;
  		update:
  			//FIXME
  			;
  		}
  	}
  	return (char *)s;
  }
  