📄 time.c
字号:
return r;}#define MAX_PUSH 4#ifdef __UCLIBC_MJN3_ONLY__#warning TODO: Check multibyte format string validity.#endifsize_t __XL(strftime)(char *__restrict s, size_t maxsize, const char *__restrict format, const struct tm *__restrict timeptr __LOCALE_PARAM ){ long tzo; register const char *p; register const char *o;#ifndef __UCLIBC_HAS_TM_EXTENSIONS__ const rule_struct *rsp;#endif const char *stack[MAX_PUSH]; size_t count; size_t o_count; int field_val, i, j, lvl; int x[3]; /* wday, yday, year */ int isofm, days; char buf[__UIM_BUFLEN_LONG]; unsigned char mod; unsigned char code; tzset(); /* We'll, let's get this out of the way. */ lvl = 0; p = format; count = maxsize; LOOP: if (!count) { return 0; } if (!*p) { if (lvl == 0) { *s = 0; /* nul-terminate */ return maxsize - count; } p = stack[--lvl]; goto LOOP; } o_count = 1; if ((*(o = p) == '%') && (*++p != '%')) { o_count = 2; mod = ILLEGAL_SPEC; if ((*p == 'O') || (*p == 'E')) { /* modifier */ mod |= ((*p == 'O') ? NO_O_MOD : NO_E_MOD); ++o_count; ++p; } if ((((unsigned char)(((*p) | 0x20) - 'a')) >= 26) || (((code = spec[(int)(*p - 'A')]) & mod) >= ILLEGAL_SPEC) ) { if (!*p) { --p; --o_count; } goto OUTPUT; } code &= ILLEGAL_SPEC; /* modifiers are preserved in mod var. */ if ((code & MASK_SPEC) == STACKED_SPEC) { if (lvl == MAX_PUSH) { goto OUTPUT; /* Stack full so treat as illegal spec. */ } stack[lvl++] = ++p; if ((code &= 0xf) < 8) { p = ((const char *) spec) + STACKED_STRINGS_START + code; p += *((unsigned char *)p); goto LOOP; } p = ((const char *) spec) + STACKED_STRINGS_NL_ITEM_START + (code & 7);#ifdef ENABLE_ERA_CODE if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */ && (*(o = __XL(nl_langinfo)(_NL_ITEM(LC_TIME, (int)(((unsigned char *)p)[4])) __LOCALE_ARG ))) ) { p = o; goto LOOP; }#endif p = __XL(nl_langinfo)(_NL_ITEM(LC_TIME, (int)(*((unsigned char *)p))) __LOCALE_ARG ); goto LOOP; } o = spec + 26; /* set to "????" */ if ((code & MASK_SPEC) == CALC_SPEC) { if (*p == 's') { time_t t; /* Use a cast to silence the warning since *timeptr won't * be changed. */ if ((t = _time_mktime((struct tm *) timeptr, 0)) == ((time_t) -1) ) { o_count = 1; goto OUTPUT; }#ifdef TIME_T_IS_UNSIGNED o = _uintmaxtostr(buf + sizeof(buf) - 1, (uintmax_t) t, 10, __UIM_DECIMAL);#else o = _uintmaxtostr(buf + sizeof(buf) - 1, (uintmax_t) t, -10, __UIM_DECIMAL);#endif o_count = sizeof(buf); goto OUTPUT; } else if (((*p) | 0x20) == 'z') { /* 'z' or 'Z' */ if (timeptr->tm_isdst < 0) { /* SUSv3 specifies this behavior for 'z', but we'll also * treat it as "no timezone info" for 'Z' too. */ o_count = 0; goto OUTPUT; }#ifdef __UCLIBC_HAS_TM_EXTENSIONS__#define RSP_TZUNLOCK ((void) 0)#define RSP_TZNAME timeptr->tm_zone#define RSP_GMT_OFFSET (-timeptr->tm_gmtoff)#else#define RSP_TZUNLOCK TZUNLOCK#define RSP_TZNAME rsp->tzname#define RSP_GMT_OFFSET rsp->gmt_offset TZLOCK; rsp = _time_tzinfo; if (timeptr->tm_isdst > 0) { ++rsp; }#endif if (*p == 'Z') { o = RSP_TZNAME;#ifdef __UCLIBC_HAS_TM_EXTENSIONS__ /* Sigh... blasted glibc extensions. Of course we can't * count on the pointer being valid. Best we can do is * handle NULL, which looks to be all that glibc does. * At least that catches the memset() with 0 case. * NOTE: We handle this case differently than glibc! * It uses system timezone name (based on tm_isdst) in this * case... although it always seems to use the embedded * tm_gmtoff value. What we'll do instead is treat the * timezone name as unknown/invalid and return "???". */ if (!o) { o = "???"; }#endif assert(o != NULL);#if 0 if (!o) { /* PARANOIA */ o = spec+30; /* empty string */ }#endif o_count = SIZE_MAX; RSP_TZUNLOCK; goto OUTPUT; } else { /* z */ *s = '+'; if ((tzo = -RSP_GMT_OFFSET) < 0) { tzo = -tzo; *s = '-'; } RSP_TZUNLOCK; ++s; --count; i = tzo / 60; field_val = ((i / 60) * 100) + (i % 60); i = 16 + 6; /* 0-fill, width = 4 */ } } else { /* TODO: don't need year for U, W */ for (i=0 ; i < 3 ; i++) { if ((x[i] = load_field(spec[CALC_OFFSETS+i],timeptr)) < 0) { goto OUTPUT; } } i = 16 + 2; /* 0-fill, width = 2 */ if ((*p == 'U') || (*p == 'W')) { field_val = ((x[1] - x[0]) + 7); if (*p == 'W') { ++field_val; } field_val /= 7; if ((*p == 'W') && !x[0]) { --field_val; } } else { /* ((*p == 'g') || (*p == 'G') || (*p == 'V')) */ ISO_LOOP: isofm = (((x[1] - x[0]) + 11) % 7) - 3; /* [-3,3] */ if (x[1] < isofm) { /* belongs to previous year */ --x[2]; x[1] += 365 + __isleap(x[2]); goto ISO_LOOP; } field_val = ((x[1] - isofm) / 7) + 1; /* week # */ days = 365 + __isleap(x[2]); isofm = ((isofm + 7*53 + 3 - days)) %7 + days - 3; /* next year */ if (x[1] >= isofm) { /* next year */ x[1] -= days; ++x[2]; goto ISO_LOOP; } if (*p != 'V') { /* need year */ field_val = x[2]; /* TODO: what if x[2] now 10000 ?? */ if (*p == 'g') { field_val %= 100; } else { i = 16 + 6; /* 0-fill, width = 4 */ } } } } } else { i = TP_OFFSETS + (code & 0x1f); if ((field_val = load_field(spec[i],timeptr)) < 0) { goto OUTPUT; } i = spec[i+(TP_CODES - TP_OFFSETS)]; j = (i & 128) ? 100: 12; if (i & 64) { field_val /= j;; } if (i & 32) { field_val %= j; if (((i&128) + field_val) == 0) { /* mod 12? == 0 */ field_val = j; /* set to 12 */ } } field_val += (i & 1); if ((i & 8) && !field_val) { field_val += 7; } } if ((code & MASK_SPEC) == STRING_SPEC) { o_count = SIZE_MAX; field_val += spec[STRINGS_NL_ITEM_START + (code & 0xf)]; o = __XL(nl_langinfo)(_NL_ITEM(LC_TIME, field_val) __LOCALE_ARG ); } else { o_count = ((i >> 1) & 3) + 1; o = buf + o_count; do { *(char *)(--o) = '0' + (field_val % 10); field_val /= 10; } while (o > buf); if (*buf == '0') { *buf = ' ' + (i & 16); } } } OUTPUT: ++p; while (o_count && count && *o) { *s++ = *o++; --o_count; --count; } goto LOOP;}__XL_ALIAS(strftime)#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */#endif/**********************************************************************/#if defined(L_strptime) || defined(L_strptime_l)#if defined(L_strptime) || defined(L_strptime_l)#define ISDIGIT(C) __isdigit_char((C))#endif#ifdef __UCLIBC_DO_XLOCALE#define ISSPACE(C) isspace_l((C), locale_arg)#else#define ISSPACE(C) isspace((C))#endif#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)char *strptime(const char *__restrict buf, const char *__restrict format, struct tm *__restrict tm){ return __strptime_l(buf, format, tm, __UCLIBC_CURLOCALE);}#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) *//* TODO: * 1) %l and %k are space-padded, so "%l" by itself fails while " %l" succeeds. * Both work for glibc. So, should we always strip spaces? * 2) %Z *//* Notes: * There are several differences between this strptime and glibc's strptime. * 1) glibc strips leading space before numeric conversions. * 2) glibc will read fields without whitespace in between. SUSv3 states * that you must have whitespace between conversion operators. Besides, * how do you know how long a number should be if there are leading 0s? * 3) glibc attempts to compute some the struct tm fields based on the * data retrieved; tm_wday in particular. I don't as I consider it * another glibc attempt at mind-reading... */#define NO_E_MOD 0x80#define NO_O_MOD 0x40#define ILLEGAL_SPEC 0x3f#define INT_SPEC 0x00 /* must be 0x00!! */#define STRING_SPEC 0x10 /* must be 0x10!! */#define CALC_SPEC 0x20#define STACKED_SPEC 0x30#define MASK_SPEC 0x30/* Warning: Assumes ASCII values! (as do lots of other things in the lib...) */static const unsigned char spec[] = { /* A */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* B */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* C */ 0x08 | INT_SPEC | NO_O_MOD, /* D */ 0x01 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* E */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* F */ 0x02 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */ /* G */ 0x0f | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */ /* H */ 0x06 | INT_SPEC | NO_E_MOD, /* I */ 0x07 | INT_SPEC | NO_E_MOD, /* J */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* K */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* L */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* M */ 0x04 | INT_SPEC | NO_E_MOD, /* N */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* O */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* P */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */ /* Q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* R */ 0x03 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* S */ 0x05 | INT_SPEC | NO_E_MOD, /* T */ 0x04 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* U */ 0x0c | INT_SPEC | NO_E_MOD, /* V */ 0x0d | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */ /* W */ 0x0c | INT_SPEC | NO_E_MOD, /* X */ 0x0a | STACKED_SPEC | NO_O_MOD, /* Y */ 0x0a | INT_SPEC | NO_O_MOD, /* Z */ 0x02 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */ /* WARNING! This assumes orderings: * AM,PM * ABDAY_1-ABDAY-7,DAY_1-DAY_7 * ABMON_1-ABMON_12,MON_1-MON12 * Also, there are exactly 6 bytes between 'Z' and 'a'. */#define STRINGS_NL_ITEM_START (26) _NL_ITEM_INDEX(AM_STR), /* p (P) */ _NL_ITEM_INDEX(ABMON_1), /* B, b */ _NL_ITEM_INDEX(ABDAY_1), /* A, a */ 2, 24, 14, /* a */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* b */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* c */ 0x08 | STACKED_SPEC | NO_O_MOD, /* d */ 0x00 | INT_SPEC | NO_E_MOD, /* e */ 0x00 | INT_SPEC | NO_E_MOD, /* f */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* g */ 0x0e | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */ /* h */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* i */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* j */ 0x01 | INT_SPEC | NO_E_MOD | NO_O_MOD, /* k */ 0x06 | INT_SPEC | NO_E_MOD, /* glibc */ /* l */ 0x07 | INT_SPEC | NO_E_MOD, /* glibc */ /* m */ 0x02 | INT_SPEC | NO_E_MOD, /* n */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* o */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* p */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* r */ 0x0b | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* s */ 0x00 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */ /* t */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* u */ 0x0b | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */ /* v */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* w */ 0x03 | INT_SPEC | NO_E_MOD, /* x */ 0x09 | STACKED_SPEC | NO_O_MOD, /* y */ 0x09 | INT_SPEC, /* z */ 0x01 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */#define INT_FIELD_START (26+6+26) /* (field #) << 3 + lower bound (0|1) + correction 0:none, 2:-1, 4:-1900 * followed by upper bound prior to correction with 1=>366 and 2=>9999. */ /* d, e */ (3 << 3) + 1 + 0, 31, /* j */ (7 << 3) + 1 + 2, /* 366 */ 1, /* m */ (4 << 3) + 1 + 2, 12, /* w */ (6 << 3) + 0 + 0, 6, /* M */ (1 << 3) + 0 + 0, 59, /* S */ 0 + 0 + 0, 60, /* H (k) */ (2 << 3) + 0 + 0, 23, /* I (l) */ (9 << 3) + 1 + 0, 12, /* goes with 8 -- am/pm */ /* C */ (10<< 3) + 0 + 0, 99, /* y */ (11<< 3) + 0 + 0, 99, /* Y */ (5 << 3) + 0 + 4, /* 9999 */ 2, /* u */ (6 << 3) + 1 + 0, 7, /* The following are processed and range-checked, but ignored otherwise. */ /* U, W */ (12<< 3) + 0 + 0, 53, /* V */ (12<< 3) + 1 + 0, 53, /* g */ (12<< 3) + 0 + 0, 99, /* G */ (12<< 3) + 0 /*+ 4*/, /* 9999 */ 2, /* Note: -1 or 10000? */#define STACKED_STRINGS_START (INT_FIELD_START+32) 5, 6, 14, 22, 27, /* 5 - offsets from offset-count to strings */ ' ', 0, /* 2 - %n or %t */ '%', 'm', '/', '%', 'd', '/', '%', 'y', 0, /* 9 - %D */ '%', 'Y', '-', '%', 'm', '-', '%', 'd', 0, /* 9 - %F (glibc extension) */ '%', 'H', ':', '%', 'M', 0, /* 6 - %R*/ '%', 'H', ':', '%', 'M', ':', '%', 'S', 0, /* 9 - %T */#define STACKED_STRINGS_NL_ITEM_START (STACKED_STRINGS_START + 40) _NL_ITEM_INDEX(D_T_FMT), /* c */ _NL_ITEM_INDEX(D_FMT), /* x */ _NL_ITEM_INDEX(T_FMT), /* X */ _NL_ITEM_INDEX(T_FMT_AMPM), /* r */#ifdef ENABLE_ERA_CODE _NL_ITEM_INDEX(ERA_D_T_FMT), /* Ec */ _NL_ITEM_INDEX(ERA_D_FMT), /* Ex */ _NL_ITEM_INDEX(ERA_T_FMT), /* EX */#endif};#define MAX_PUSH 4char *__XL(strptime)(const char *__restrict buf, const char *__restrict format, struct tm *__restrict tm __LOCALE_PARAM){ register const char *p; char *o; const char *stack[MAX_PUSH]; int i, j, lvl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -