📄 time.c
字号:
int fields[13]; unsigned char mod; unsigned char code; i = 0; do { fields[i] = INT_MIN; } while (++i < 13); lvl = 0; p = format; LOOP: if (!*p) { if (lvl == 0) { /* Done. */ if (fields[6] == 7) { /* Cleanup for %u here since just once. */ fields[6] = 0; /* Don't use mod in case unset. */ } i = 0; do { /* Store the values into tm. */ if (fields[i] != INT_MIN) { ((int *) tm)[i] = fields[i]; } } while (++i < 8); return (char *) buf; /* Success. */ } p = stack[--lvl]; goto LOOP; } if ((*p == '%') && (*++p != '%')) { mod = ILLEGAL_SPEC; if ((*p == 'O') || (*p == 'E')) { /* Modifier? */ mod |= ((*p == 'O') ? NO_O_MOD : NO_E_MOD); ++p; } if (!*p || (((unsigned char)(((*p) | 0x20) - 'a')) >= 26) || (((code = spec[(int)(*p - 'A')]) & mod) >= ILLEGAL_SPEC) ) { return NULL; /* Illegal spec. */ } if ((code & MASK_SPEC) == STACKED_SPEC) { if (lvl == MAX_PUSH) { return NULL; /* 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; } ++p; if ((code & MASK_SPEC) == STRING_SPEC) { code &= 0xf; j = spec[STRINGS_NL_ITEM_START + 3 + code]; i = _NL_ITEM(LC_TIME, spec[STRINGS_NL_ITEM_START + code]); /* Go backwards to check full names before abreviations. */ do { --j; o = __XL(nl_langinfo)(i+j __LOCALE_ARG); if (!__XL(strncasecmp)(buf,o,strlen(o) __LOCALE_ARG) && *o) { do { /* Found a match. */ ++buf; } while (*++o); if (!code) { /* am/pm */ fields[8] = j * 12; if (fields[9] >= 0) { /* We have a previous %I or %l. */ fields[2] = fields[9] + fields[8]; } } else { /* day (4) or month (6) */ fields[2 + (code << 1)] = j % (spec[STRINGS_NL_ITEM_START + 3 + code] >> 1); } goto LOOP; } } while (j); return NULL; /* Failed to match. */ } if ((code & MASK_SPEC) == CALC_SPEC) { if ((code &= 0xf) < 1) { /* s or z*/ time_t t; o = (char *) buf; i = errno; __set_errno(0); if (!ISSPACE(*buf)) { /* Signal an error if whitespace. */#ifdef TIME_T_IS_UNSIGNED t = __XL(strtoul)(buf, &o, 10 __LOCALE_ARG);#else t = __XL(strtol)(buf, &o, 10 __LOCALE_ARG);#endif } if ((o == buf) || errno) { /* Not a number or overflow. */ return NULL; } __set_errno(i); /* Restore errno. */ buf = o; if (!code) { /* s */ localtime_r(&t, tm); /* TODO: check for failure? */ i = 0; do { /* Now copy values from tm to fields. */ fields[i] = ((int *) tm)[i]; } while (++i < 8); } } /* TODO: glibc treats %Z as a nop. For now, do the same. */ goto LOOP; } assert((code & MASK_SPEC) == INT_SPEC); { register const unsigned char *x; code &= 0xf; x = spec + INT_FIELD_START + (code << 1); if ((j = x[1]) < 3) { /* upper bound (inclusive) */ j = ((j==1) ? 366 : 9999); } i = -1; while (ISDIGIT(*buf)) { if (i < 0) { i = 0; } if ((i = 10*i + (*buf - '0')) > j) { /* Overflow. */ return NULL; } ++buf; } if (i < (*x & 1)) { /* This catches no-digit case too. */ return NULL; } if (*x & 2) { --i; } if (*x & 4) { i -= 1900; } if (*x == (9 << 3) + 1 + 0) { /* %I or %l */ if (i == 12) { i = 0; } if (fields[8] >= 0) { /* We have a previous %p or %P. */ fields[2] = i + fields[8]; } } fields[(*x) >> 3] = i; if (((unsigned char)(*x - (10<< 3) + 0 + 0)) <= 8) { /* %C or %y */ if ((j = fields[10]) < 0) { /* No %C, so i must be %y data. */ if (i <= 68) { /* Map [0-68] to 2000+i */ i += 100; } } else { /* Have %C data, but what about %y? */ if ((i = fields[11]) < 0) { /* No %y data. */ i = 0; /* Treat %y val as 0 following glibc's example. */ } i += 100*(j - 19); } fields[5] = i; } } goto LOOP; } else if (ISSPACE(*p)) { ++p; while (ISSPACE(*buf)) { ++buf; } goto LOOP; } else if (*buf++ == *p++) { goto LOOP; } return NULL;}__XL_ALIAS(strptime)#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */#endif/**********************************************************************/#ifdef L_time#ifndef __BCC__#error The uClibc version of time is in sysdeps/linux/common.#endiftime_t time(register time_t *tloc){ struct timeval tv; register struct timeval *p = &tv; gettimeofday(p, NULL); /* This should never fail... */ if (tloc) { *tloc = p->tv_sec; } return p->tv_sec;}#endif/**********************************************************************/#ifdef L_tzsetstatic const char vals[] = { 'T', 'Z', 0, /* 3 */ 'U', 'T', 'C', 0, /* 4 */ 25, 60, 60, 1, /* 4 */ '.', 1, /* M */ 5, '.', 1, 6, 0, 0, /* Note: overloaded for non-M non-J case... */ 0, 1, 0, /* J */ ',', 'M', '4', '.', '1', '.', '0', ',', 'M', '1', '0', '.', '5', '.', '0', 0};#define TZ vals#define UTC (vals + 3)#define RANGE (vals + 7)#define RULE (vals + 11 - 1)#define DEFAULT_RULES (vals + 22)/* Initialize to UTC. */int daylight = 0;long timezone = 0;char *tzname[2] = { (char *) UTC, (char *) (UTC-1) };#ifdef __UCLIBC_HAS_THREADS__pthread_mutex_t _time_tzlock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;#endifrule_struct _time_tzinfo[2];static const char *getoffset(register const char *e, long *pn){ register const char *s = RANGE-1; long n; int f; n = 0; f = -1; do { ++s; if (__isdigit_char(*e)) { f = *e++ - '0'; } if (__isdigit_char(*e)) { f = 10 * f + (*e++ - '0'); } if (((unsigned int)f) >= *s) { return NULL; } n = (*s) * n + f; f = 0; if (*e == ':') { ++e; --f; } } while (*s > 1); *pn = n; return e;}static const char *getnumber(register const char *e, int *pn){#ifdef __BCC__ /* bcc can optimize the counter if it thinks it is a pointer... */ register const char *n = (const char *) 3; int f; f = 0; while (n && __isdigit_char(*e)) { f = 10 * f + (*e++ - '0'); --n; } *pn = f; return (n == (const char *) 3) ? NULL : e;#else /* __BCC__ */ int n, f; n = 3; f = 0; while (n && __isdigit_char(*e)) { f = 10 * f + (*e++ - '0'); --n; } *pn = f; return (n == 3) ? NULL : e;#endif /* __BCC__ */}#ifdef __UCLIBC_MJN3_ONLY__#warning CONSIDER: Should we preserve errno from open/read/close errors re TZ file?#endif#ifdef __UCLIBC_HAS_TZ_FILE__#ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__static int TZ_file_read; /* Let BSS initialization set this to 0. */#endif /* __UCLIBC_HAS_TZ_FILE_READ_MANY__ */static char *read_TZ_file(char *buf){ int fd; ssize_t r; size_t todo; char *p = NULL; if ((fd = open(__UCLIBC_TZ_FILE_PATH__, O_RDONLY)) >= 0) { todo = TZ_BUFLEN; p = buf; do { if ((r = read(fd, p, todo)) < 0) { goto ERROR; } if (r == 0) { break; } p += r; todo -= r; } while (todo); if ((p > buf) && (p[-1] == '\n')) { /* Must end with newline. */ p[-1] = 0; p = buf;#ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__ ++TZ_file_read;#endif /* __UCLIBC_HAS_TZ_FILE_READ_MANY__ */ } else { ERROR: p = NULL; } close(fd); } return p;}#endif /* __UCLIBC_HAS_TZ_FILE__ */void tzset(void){ register const char *e; register char *s; long off; short *p; rule_struct new_rules[2]; int n, count, f; char c;#ifdef __UCLIBC_HAS_TZ_FILE__ char buf[TZ_BUFLEN];#endif /* __UCLIBC_HAS_TZ_FILE__ */#ifdef __UCLIBC_HAS_TZ_CACHING__ static char oldval[TZ_BUFLEN]; /* BSS-zero'd. */#endif /* __UCLIBC_HAS_TZ_CACHING__ */ TZLOCK; e = getenv(TZ); /* TZ env var always takes precedence. */#if defined(__UCLIBC_HAS_TZ_FILE__) && !defined(__UCLIBC_HAS_TZ_FILE_READ_MANY__) /* Put this inside the lock to prevent the possiblity of two different * timezones being used in a threaded app. */ if (e != NULL) { TZ_file_read = 0; /* Reset if the TZ env var is set. */ } else if (TZ_file_read > 0) { goto FAST_DONE; }#endif /* defined(__UCLIBC_HAS_TZ_FILE__) && !defined(__UCLIBC_HAS_TZ_FILE_READ_MANY__) */ /* Warning!!! Since uClibc doesn't do lib locking, the following is * potentially unsafe in a multi-threaded program since it is remotely * possible that another thread could call setenv() for TZ and overwrite * the string being parsed. So, don't do that... */ if ((!e /* TZ env var not set... */#ifdef __UCLIBC_HAS_TZ_FILE__ && !(e = read_TZ_file(buf)) /* and no file or invalid file */#endif /* __UCLIBC_HAS_TZ_FILE__ */ ) || !*e) { /* or set to empty string. */ ILLEGAL: /* TODO: Clean up the following... */#ifdef __UCLIBC_HAS_TZ_CACHING__ *oldval = 0; /* Set oldval to an empty string. */#endif /* __UCLIBC_HAS_TZ_CACHING__ */ memset(_time_tzinfo, 0, 2*sizeof(rule_struct)); strcpy(_time_tzinfo[0].tzname, UTC); goto DONE; } if (*e == ':') { /* Ignore leading ':'. */ ++e; }#ifdef __UCLIBC_HAS_TZ_CACHING__ if (strcmp(e, oldval) == 0) { /* Same string as last time... */ goto FAST_DONE; /* So nothing to do. */ } /* Make a copy of the TZ env string. It won't be nul-terminated if * it is too long, but it that case it will be illegal and will be reset * to the empty string anyway. */ strncpy(oldval, e, TZ_BUFLEN);#endif /* __UCLIBC_HAS_TZ_CACHING__ */ count = 0; new_rules[1].tzname[0] = 0; LOOP: /* Get std or dst name. */ c = 0; if (*e == '<') { ++e; c = '>'; } s = new_rules[count].tzname; n = 0; while (*e && isascii(*e) /* SUSv3 requires char in portable char set. */ && (isalpha(*e) || (c && (isalnum(*e) || (*e == '+') || (*e == '-')))) ) { *s++ = *e++; if (++n > TZNAME_MAX) { goto ILLEGAL; } } *s = 0; if ((n < 3) /* Check for minimum length. */ || (c && (*e++ != c)) /* Match any quoting '<'. */ ) { goto ILLEGAL; } /* Get offset */ s = (char *) e; if ((*e != '-') && (*e != '+')) { if (count && !__isdigit_char(*e)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -