github.com/afumu/libc@v0.0.6/musl/src/time/strptime.c (about)

     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  
     9  char *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  }