📄 partime.c
字号:
} s = parse_fixed (s1, (int) (s - s1), &num10); product = num10 * resolution; f = (product + (denom10 >> 1)) / denom10; f -= f & (product % denom10 == denom10 >> 1); /* round to even */ if (f < 0 || product/resolution != num10) return 0; /* overflow */ } *fres = f; return s; } return 0;}/* Parse an initial prefix of S; it must denote a time zone. Set *ZONE to the number of seconds east of GMT, or to TM_LOCAL_ZONE if it is the local time zone. Return the first character after the prefix, or 0 if it wasn't parsed. */char *parzone (s, zone) char const *s; long *zone;{ char const *s1; char sign; int hh, mm, ss; int minutes_east_of_UTC; int trailing_DST; long offset, z; /* The formats are LT, n, n DST, nDST, no, o where n is a time zone name and o is a time zone offset of the form [-+]hh[:mm[:ss]]. */ switch (*s) { case '-': case '+': z = 0; break; default: minutes_east_of_UTC = lookup (s, zone_names); if (minutes_east_of_UTC == -1) return 0; /* Don't bother to check rest of spelling, but look for an embedded "DST". */ trailing_DST = 0; while (ISALPHA ((unsigned char) *s)) { if ((*s == 'D' || *s == 'd') && lookup (s, dst_names)) trailing_DST = 1; s++; s += *s == '.'; } /* Don't modify LT. */ if (minutes_east_of_UTC == 1) { *zone = TM_LOCAL_ZONE; return (char *) s; } z = minutes_east_of_UTC * 60L; s1 = s; /* Look for trailing "DST" or " DST". */ while (ISSPACE ((unsigned char) *s)) s++; if (lookup (s, dst_names)) { while (ISALPHA ((unsigned char) *s)) { s++; s += *s == '.'; } trailing_DST = 1; } if (trailing_DST) { *zone = z + 60*60; return (char *) s; } s = s1; switch (*s) { case '-': case '+': break; default: *zone = z; return (char *) s; } break; } sign = *s++; if (! (s = parse_ranged (s, 2, 0, 23, &hh))) return 0; mm = ss = 0; if (*s == ':') s++; if (ISDIGIT (*s)) { if (! (s = parse_ranged (s, 2, 0, 59, &mm))) return 0; if (*s == ':' && s[-3] == ':' && ISDIGIT (s[1]) && ! (s = parse_ranged (s + 1, 2, 0, 59, &ss))) return 0; } if (ISDIGIT (*s)) return 0; offset = (hh * 60 + mm) * 60L + ss; *zone = z + (sign == '-' ? -offset : offset); /* ?? Are fractions allowed here? If so, they're not implemented. */ return (char *) s;}/* Parse an initial prefix of S, matching the pattern whose code is C. Set *T accordingly. Return the first character after the prefix, or 0 if it wasn't parsed. */static char const *parse_pattern_letter (s, c, t) char const *s; int c; struct partime *t;{ char const *s0 = s; switch (c) { case '$': /* The next character must be a non-digit. */ if (ISDIGIT (*s)) return 0; break; case '-': case '/': case ':': /* These characters stand for themselves. */ if (*s++ != c) return 0; break; case '4': /* 4-digit year */ s = parse_fixed (s, 4, &t->tm.tm_year); break; case ';': /* The next character must be a non-digit, and cannot be ':'. */ if (ISDIGIT (*s) || *s == ':') return 0; break; case '=': /* optional '-' */ s += *s == '-'; break; case 'A': /* AM or PM */ /* This matches the regular expression [AaPp]\.?([Mm]\.?)?. It must not be followed by a letter or digit; otherwise it would match prefixes of strings like "PST". */ switch (*s) { case 'A': case 'a': if (t->tm.tm_hour == 12) t->tm.tm_hour = 0; break; case 'P': case 'p': if (t->tm.tm_hour != 12) t->tm.tm_hour += 12; break; default: return 0; } s++; s += *s == '.'; switch (*s) { case 'M': case 'm': s++; s += *s == '.'; break; } if (ISALNUM ((unsigned char) *s)) return 0; break; case 'D': /* day of month [01-31] */ s = parse_ranged (s, 2, 1, 31, &t->tm.tm_mday); break; case 'd': /* day of year [001-366] */ s = parse_ranged (s, 3, 1, 366, &t->tm.tm_yday); t->tm.tm_yday--; break; case 'E': /* traditional day of month [1-9, 01-31] */ s = parse_ranged (s, (ISDIGIT (s[0]) && ISDIGIT (s[1])) + 1, 1, 31, &t->tm.tm_mday); break; case 'h': /* hour [00-23] */ s = parse_ranged (s, 2, 0, 23, &t->tm.tm_hour); break; case 'H': /* hour [00-23 followed by optional fraction] */ { int frac; s = parse_decimal (s, 2, 0, 23, 60 * 60, &t->tm.tm_hour, &frac); t->tm.tm_min = frac / 60; t->tm.tm_sec = frac % 60; } break; case 'i': /* ordinal day number, e.g. "3rd" */ s = parse_varying (s, &t->wday_ordinal); if (s == s0) return 0; while (ISALPHA ((unsigned char) *s)) s++; break; case 'L': /* minute [00-59 followed by optional fraction] */ s = parse_decimal (s, 2, 0, 59, 60, &t->tm.tm_min, &t->tm.tm_sec); break; case 'm': /* minute [00-59] */ s = parse_ranged (s, 2, 0, 59, &t->tm.tm_min); break; case 'M': /* month [01-12] */ s = parse_ranged (s, 2, 1, 12, &t->tm.tm_mon); t->tm.tm_mon--; break; case 'n': /* traditional month [1-9, 01-12] */ s = parse_ranged (s, (ISDIGIT (s[0]) && ISDIGIT (s[1])) + 1, 1, 12, &t->tm.tm_mon); t->tm.tm_mon--; break; case 'N': /* month name [e.g. "Jan"] */ if (! TM_DEFINED (t->tm.tm_mon = lookup (s, month_names))) return 0; /* Don't bother to check rest of spelling. */ while (ISALPHA ((unsigned char) *s)) s++; break; case 'r': /* year % 10 (remainder in origin-0 decade) [0-9] */ s = parse_fixed (s, 1, &t->tm.tm_year); t->ymodulus = 10; break; case_R: case 'R': /* year % 100 (remainder in origin-0 century) [00-99] */ s = parse_fixed (s, 2, &t->tm.tm_year); t->ymodulus = 100; break; case 's': /* second [00-60 followed by optional fraction] */ { int frac; s = parse_decimal (s, 2, 0, 60, 1, &t->tm.tm_sec, &frac); t->tm.tm_sec += frac; } break; case 'T': /* 'T' or 't' */ switch (*s++) { case 'T': case 't': break; default: return 0; } break; case 't': /* traditional hour [1-9 or 01-12] */ s = parse_ranged (s, (ISDIGIT (s[0]) && ISDIGIT (s[1])) + 1, 1, 12, &t->tm.tm_hour); break; case 'u': /* relative unit */ { int i; int n; int negative = 0; switch (*s) { case '-': negative = 1; /* Fall through. */ case '+': s++; } if (ISDIGIT (*s)) s = parse_varying (s, &n); else if (s == s0) n = 1; else return 0; if (negative) n = -n; while (! ISALNUM ((unsigned char) *s) && *s) s++; i = lookup (s, relative_units); if (!TM_DEFINED (i)) return 0; * (int *) ((char *) &t->tmr + RELATIVE_OFFSET (i)) += n * RELATIVE_MULTIPLIER (i); while (ISALPHA ((unsigned char) *s)) s++; while (! ISALNUM ((unsigned char) *s) && *s) s++; if (TM_DEFINED (lookup (s, ago))) { t->tmr.tm_sec = - t->tmr.tm_sec; t->tmr.tm_min = - t->tmr.tm_min; t->tmr.tm_hour = - t->tmr.tm_hour; t->tmr.tm_mday = - t->tmr.tm_mday; t->tmr.tm_mon = - t->tmr.tm_mon; t->tmr.tm_year = - t->tmr.tm_year; while (ISALPHA ((unsigned char) *s)) s++; } break; } case 'w': /* 'W' or 'w' only (stands for current week) */ switch (*s++) { case 'W': case 'w': break; default: return 0; } break; case 'W': /* 'W' or 'w', followed by a week of year [00-53] */ switch (*s++) { case 'W': case 'w': break; default: return 0; } s = parse_ranged (s, 2, 0, 53, &t->yweek); break; case 'X': /* weekday (1=Mon ... 7=Sun) [1-7] */ s = parse_ranged (s, 1, 1, 7, &t->tm.tm_wday); t->tm.tm_wday--; break; case 'x': /* weekday name [e.g. "Sun"] */ if (! TM_DEFINED (t->tm.tm_wday = lookup (s, weekday_names))) return 0; /* Don't bother to check rest of spelling. */ while (ISALPHA ((unsigned char) *s)) s++; break; case 'y': /* either R or Y */ if (ISDIGIT (s[0]) && ISDIGIT (s[1]) && ! ISDIGIT (s[2])) goto case_R; /* fall into */ case 'Y': /* year in full [4 or more digits] */ s = parse_varying (s, &t->tm.tm_year); if (s - s0 < 4) return 0; break; case 'Z': /* time zone */ s = parzone (s, &t->zone); break; case '_': /* possibly empty sequence of non-alphanumerics */ while (! ISALNUM ((unsigned char) *s) && *s) s++; break; default: /* bad pattern */ return 0; } return s;}/* If there is no conflict, merge into *T the additional information in *U and return 0. Otherwise do nothing and return -1. */static intmerge_partime (t, u) struct partime *t; struct partime const *u;{# define conflict(a,b) ((a) != (b) && TM_DEFINED (a) && TM_DEFINED (b)) if (conflict (t->tm.tm_sec, u->tm.tm_sec) || conflict (t->tm.tm_min, u->tm.tm_min) || conflict (t->tm.tm_hour, u->tm.tm_hour) || conflict (t->tm.tm_mday, u->tm.tm_mday) || conflict (t->tm.tm_mon, u->tm.tm_mon) || conflict (t->tm.tm_year, u->tm.tm_year) || conflict (t->tm.tm_wday, u->tm.tm_wday) || conflict (t->tm.tm_yday, u->tm.tm_yday) || conflict (t->ymodulus, u->ymodulus) || conflict (t->yweek, u->yweek) || (t->zone != u->zone && t->zone != TM_UNDEFINED_ZONE && u->zone != TM_UNDEFINED_ZONE)) return -1;# undef conflict# define merge_(a,b) if (TM_DEFINED (b)) (a) = (b); merge_ (t->tm.tm_sec, u->tm.tm_sec) merge_ (t->tm.tm_min, u->tm.tm_min) merge_ (t->tm.tm_hour, u->tm.tm_hour) merge_ (t->tm.tm_mday, u->tm.tm_mday) merge_ (t->tm.tm_mon, u->tm.tm_mon) merge_ (t->tm.tm_year, u->tm.tm_year) merge_ (t->tm.tm_wday, u->tm.tm_wday) merge_ (t->tm.tm_yday, u->tm.tm_yday) merge_ (t->ymodulus, u->ymodulus) merge_ (t->yweek, u->yweek)# undef merge_ t->tmr.tm_sec += u->tmr.tm_sec; t->tmr.tm_min += u->tmr.tm_min; t->tmr.tm_hour += u->tmr.tm_hour; t->tmr.tm_mday += u->tmr.tm_mday; t->tmr.tm_mon += u->tmr.tm_mon; t->tmr.tm_year += u->tmr.tm_year; if (u->zone != TM_UNDEFINED_ZONE) t->zone = u->zone; return 0;}/* Parse a date/time prefix of S, putting the parsed result into *T. Return the first character after the prefix. The prefix may contain no useful information; in that case, *T will contain only undefined values. */char *partime (s, t) char const *s; struct partime *t;{ struct partime p; undefine (t); while (*s) { char const *patterns = time_patterns; char const *s1; do { if (! (s1 = parse_prefix (s, &patterns, &p))) return (char *) s; } while (merge_partime (t, &p) != 0); s = s1; } return (char *) s;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -