int tmxsettime(Time_t t) { Tv_t tv; tv.tv_sec = tmxsec(t); tv.tv_nsec = tmxnsec(t); return tvsettime(&tv); }
int tmxtouch(const char* path, Time_t at, Time_t mt, Time_t ct, int flags) { Tv_t av; Tv_t mv; Tv_t cv; Tv_t* ap; Tv_t* mp; Tv_t* cp; if (at == TMX_NOTIME && !(flags & PATH_TOUCH_VERBATIM)) ap = TV_TOUCH_RETAIN; else if (!at && !(flags & PATH_TOUCH_VERBATIM)) ap = 0; else { av.tv_sec = tmxsec(at); av.tv_nsec = tmxnsec(at); ap = &av; } if (mt == TMX_NOTIME && !(flags & PATH_TOUCH_VERBATIM)) mp = TV_TOUCH_RETAIN; else if (!mt && !(flags & PATH_TOUCH_VERBATIM)) mp = 0; else { mv.tv_sec = tmxsec(mt); mv.tv_nsec = tmxnsec(mt); mp = &mv; } if (ct == TMX_NOTIME && !(flags & PATH_TOUCH_VERBATIM)) cp = TV_TOUCH_RETAIN; else if (!ct && !(flags & PATH_TOUCH_VERBATIM)) cp = 0; else { cv.tv_sec = tmxsec(ct); cv.tv_nsec = tmxnsec(ct); cp = &cv; } return tvtouch(path, ap, mp, cp, flags & 1); }
char* tmxfmt(char* buf, size_t len, const char* format, Time_t t) { register char* cp; register char* ep; register char* p; register int n; int c; int i; int flags; int alt; int pad; int delimiter; int width; int prec; int parts; char* arg; char* f; const char* oformat; Tm_t* tm; Tm_zone_t* zp; Time_t now; Stack_t* sp; Stack_t stack[8]; Tm_t ts; char argbuf[256]; char fmt[32]; tmlocale(); tm = tmxtm(&ts, t, NiL); if (!format || !*format) format = tm_info.deformat; oformat = format; flags = tm_info.flags; sp = &stack[0]; cp = buf; ep = buf + len; delimiter = 0; for (;;) { if ((c = *format++) == delimiter) { delimiter = 0; if (sp <= &stack[0]) break; sp--; format = sp->format; delimiter = sp->delimiter; continue; } if (c != '%') { if (cp < ep) *cp++ = c; continue; } alt = 0; arg = 0; pad = 0; width = 0; prec = 0; parts = 0; for (;;) { switch (c = *format++) { case '_': case '-': pad = c; continue; case 'E': case 'O': if (!isalpha(*format)) break; alt = c; continue; case '0': if (!parts) { pad = c; continue; } /*FALLTHROUGH*/ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': switch (parts) { case 0: parts++; /*FALLTHROUGH*/ case 1: width = width * 10 + (c - '0'); break; case 2: prec = prec * 10 + (c - '0'); break; } continue; case '.': if (!parts++) parts++; continue; case '(': i = 1; arg = argbuf; for (;;) { if (!(c = *format++)) { format--; break; } else if (c == '(') i++; else if (c == ')' && !--i) break; else if (arg < &argbuf[sizeof(argbuf) - 1]) *arg++ = c; } *arg = 0; arg = argbuf; continue; default: break; } break; } switch (c) { case 0: format--; continue; case '%': if (cp < ep) *cp++ = '%'; continue; case '?': if (tm_info.deformat != tm_info.format[TM_DEFAULT]) format = tm_info.deformat; else if (!*format) format = tm_info.format[TM_DEFAULT]; continue; case 'a': /* abbreviated day of week name */ n = TM_DAY_ABBREV + tm->tm_wday; goto index; case 'A': /* day of week name */ n = TM_DAY + tm->tm_wday; goto index; case 'b': /* abbreviated month name */ case 'h': n = TM_MONTH_ABBREV + tm->tm_mon; goto index; case 'B': /* month name */ n = TM_MONTH + tm->tm_mon; goto index; case 'c': /* `ctime(3)' date sans newline */ p = tm_info.format[TM_CTIME]; goto push; case 'C': /* 2 digit century */ cp = number(cp, ep, (long)(1900 + tm->tm_year) / 100, 2, width, pad); continue; case 'd': /* day of month */ cp = number(cp, ep, (long)tm->tm_mday, 2, width, pad); continue; case 'D': /* date */ p = tm_info.format[TM_DATE]; goto push; case 'e': /* blank padded day of month */ cp = number(cp, ep, (long)tm->tm_mday, -2, width, pad); continue; case 'f': /* (AST) OBSOLETE use %Qf */ p = "%Qf"; goto push; case 'F': /* ISO 8601:2000 standard date format */ p = "%Y-%m-%d"; goto push; case 'g': /* %V 2 digit year */ case 'G': /* %V 4 digit year */ n = tm->tm_year + 1900; if (tm->tm_yday < 7) { if (tmweek(tm, 2, -1, -1) >= 52) n--; } else if (tm->tm_yday > 358) { if (tmweek(tm, 2, -1, -1) <= 1) n++; } if (c == 'g') { n %= 100; c = 2; } else c = 4; cp = number(cp, ep, (long)n, c, width, pad); continue; case 'H': /* hour (0 - 23) */ cp = number(cp, ep, (long)tm->tm_hour, 2, width, pad); continue; case 'i': /* (AST) OBSOLETE use %QI */ p = "%QI"; goto push; case 'I': /* hour (0 - 12) */ if ((n = tm->tm_hour) > 12) n -= 12; else if (n == 0) n = 12; cp = number(cp, ep, (long)n, 2, width, pad); continue; case 'j': /* Julian date (1 offset) */ cp = number(cp, ep, (long)(tm->tm_yday + 1), 3, width, pad); continue; case 'J': /* Julian date (0 offset) */ cp = number(cp, ep, (long)tm->tm_yday, 3, width, pad); continue; case 'k': /* (AST) OBSOLETE use %QD */ p = "%QD"; goto push; case 'K': /* (AST) largest to smallest */ switch (alt) { case 'E': p = (pad == '_') ? "%Y-%m-%d %H:%M:%S.%N %z" : "%Y-%m-%d+%H:%M:%S.%N%z"; break; case 'O': p = (pad == '_') ? "%Y-%m-%d %H:%M:%S.%N" : "%Y-%m-%d+%H:%M:%S.%N"; break; default: p = (pad == '_') ? "%Y-%m-%d %H:%M:%S" : "%Y-%m-%d+%H:%M:%S"; break; } goto push; case 'l': /* (AST) OBSOLETE use %QL */ p = "%QL"; goto push; case 'L': /* (AST) OBSOLETE use %Ql */ p = "%Ql"; goto push; case 'm': /* month number */ cp = number(cp, ep, (long)(tm->tm_mon + 1), 2, width, pad); continue; case 'M': /* minutes */ cp = number(cp, ep, (long)tm->tm_min, 2, width, pad); continue; case 'n': if (cp < ep) *cp++ = '\n'; continue; case 'N': /* (AST|GNU) nanosecond part */ cp = number(cp, ep, (long)tm->tm_nsec, 9, width, pad); continue; #if 0 case 'o': /* (UNUSED) */ continue; #endif case 'p': /* meridian */ n = TM_MERIDIAN + (tm->tm_hour >= 12); goto index; case 'P': /* (AST|GNU) lower case meridian */ p = tm_info.format[TM_MERIDIAN + (tm->tm_hour >= 12)]; while (cp < ep && (n = *p++)) *cp++ = isupper(n) ? tolower(n) : n; continue; case 'q': /* (AST) OBSOLETE use %Qz */ p = "%Qz"; goto push; case 'Q': /* (AST) %Q<alpha> or %Q<delim>recent<delim>distant<delim> */ if (c = *format) { format++; if (isalpha(c)) { switch (c) { case 'd': /* `ls -l' distant date */ p = tm_info.format[TM_DISTANT]; goto push; case 'D': /* `date(1)' date */ p = tm_info.format[TM_DATE_1]; goto push; case 'f': /* TM_DEFAULT override */ p = tm_info.deformat; goto push; case 'I': /* international `date(1)' date */ p = tm_info.format[TM_INTERNATIONAL]; goto push; case 'l': /* TM_DEFAULT */ p = tm_info.format[TM_DEFAULT]; goto push; case 'L': /* `ls -l' date */ if (t) { now = tmxgettime(); if (warped(t, now)) { p = tm_info.format[TM_DISTANT]; goto push; } } p = tm_info.format[TM_RECENT]; goto push; case 'o': /* set options ( %([+-]flag...)o ) */ if (arg) { c = '+'; i = 0; for (;;) { switch (*arg++) { case 0: n = 0; break; case '=': i = !i; continue; case '+': case '-': case '!': c = *(arg - 1); continue; case 'l': n = TM_LEAP; break; case 'n': case 's': n = TM_SUBSECOND; break; case 'u': n = TM_UTC; break; default: continue; } if (!n) break; /* * right, the global state stinks * but we respect its locale-like status */ if (c == '+') { if (!(flags & n)) { flags |= n; tm_info.flags |= n; tm = tmxtm(tm, t, (flags & TM_UTC) ? &tm_data.zone[2] : tm->tm_zone); if (!i) tm_info.flags &= ~n; } } else if (flags & n) { flags &= ~n; tm_info.flags &= ~n; tm = tmxtm(tm, t, (flags & TM_UTC) ? &tm_data.zone[2] : tm->tm_zone); if (!i) tm_info.flags |= n; } } } break; case 'r': /* `ls -l' recent date */ p = tm_info.format[TM_RECENT]; goto push; case 'z': /* time zone nation code */ if (!(flags & TM_UTC)) { if ((zp = tm->tm_zone) != tm_info.local) for (; zp >= tm_data.zone; zp--) if (p = zp->type) goto string; else if (p = zp->type) goto string; } break; default: format--; break; } } else { if (t) { now = tmxgettime(); p = warped(t, now) ? (char*)0 : (char*)format; } else p = (char*)format; i = 0; while (n = *format) { format++; if (n == c) { if (!p) p = (char*)format; if (++i == 2) goto push_delimiter; } } } } continue; case 'r': p = tm_info.format[TM_MERIDIAN_TIME]; goto push; case 'R': p = "%H:%M"; goto push; case 's': /* (DEFACTO) seconds[.nanoseconds] since the epoch */ case '#': now = t; f = fmt; *f++ = '%'; if (pad == '0') *f++ = pad; if (width) f += sfsprintf(f, &fmt[sizeof(fmt)] - f, "%d", width); f += sfsprintf(f, &fmt[sizeof(fmt)] - f, "I%du", sizeof(Tmxsec_t)); cp += sfsprintf(cp, ep - cp, fmt, tmxsec(now)); if (parts > 1) { n = sfsprintf(cp, ep - cp, ".%09I*u", sizeof(Tmxnsec_t), tmxnsec(now)); if (prec && n >= prec) n = prec + 1; cp += n; } continue; case 'S': /* seconds */ cp = number(cp, ep, (long)tm->tm_sec, 2, width, pad); if ((flags & TM_SUBSECOND) && (format - 2) != oformat) { p = ".%N"; goto push; } continue; case 't': if (cp < ep) *cp++ = '\t'; continue; case 'T': p = tm_info.format[TM_TIME]; goto push; case 'u': /* weekday number [1(Monday)-7] */ if (!(i = tm->tm_wday)) i = 7; cp = number(cp, ep, (long)i, 0, width, pad); continue; case 'U': /* week number, Sunday as first day */ cp = number(cp, ep, (long)tmweek(tm, 0, -1, -1), 2, width, pad); continue; #if 0 case 'v': /* (UNUSED) */ continue; #endif case 'V': /* ISO week number */ cp = number(cp, ep, (long)tmweek(tm, 2, -1, -1), 2, width, pad); continue; case 'W': /* week number, Monday as first day */ cp = number(cp, ep, (long)tmweek(tm, 1, -1, -1), 2, width, pad); continue; case 'w': /* weekday number [0(Sunday)-6] */ cp = number(cp, ep, (long)tm->tm_wday, 0, width, pad); continue; case 'x': p = tm_info.format[TM_DATE]; goto push; case 'X': p = tm_info.format[TM_TIME]; goto push; case 'y': /* year in the form yy */ cp = number(cp, ep, (long)(tm->tm_year % 100), 2, width, pad); continue; case 'Y': /* year in the form ccyy */ cp = number(cp, ep, (long)(1900 + tm->tm_year), 4, width, pad); continue; case 'z': /* time zone west offset */ if (arg) { if ((zp = tmzone(arg, &f, 0, 0)) && !*f && tm->tm_zone != zp) tm = tmxtm(tm, tmxtime(tm, tm->tm_zone->west + (tm->tm_isdst ? tm->tm_zone->dst : 0)), zp); continue; } if ((ep - cp) >= 16) cp = tmpoff(cp, ep - cp, "", (flags & TM_UTC) ? 0 : tm->tm_zone->west + (tm->tm_isdst ? tm->tm_zone->dst : 0), pad == '_' ? -24 * 60 : 24 * 60); continue; case 'Z': /* time zone */ if (arg) { if ((zp = tmzone(arg, &f, 0, 0)) && !*f && tm->tm_zone != zp) tm = tmxtm(tm, tmxtime(tm, tm->tm_zone->west + (tm->tm_isdst ? tm->tm_zone->dst : 0)), zp); continue; } p = (flags & TM_UTC) ? tm_info.format[TM_UT] : tm->tm_isdst && tm->tm_zone->daylight ? tm->tm_zone->daylight : tm->tm_zone->standard; goto string; case '=': /* (AST) OBSOLETE use %([+-]flag...)Qo (old %=[=][+-]flag) */ for (arg = argbuf; *format == '=' || *format == '-' || *format == '+' || *format == '!'; format++) if (arg < &argbuf[sizeof(argbuf) - 2]) *arg++ = *format; if (*arg++ = *format) format++; *arg = 0; arg = argbuf; goto options; default: if (cp < ep) *cp++ = '%'; if (cp < ep) *cp++ = c; continue; } index: p = tm_info.format[n]; string: while (cp < ep && (*cp = *p++)) cp++; continue; options: c = '+'; i = 0; for (;;) { switch (*arg++) { case 0: n = 0; break; case '=': i = !i; continue; case '+': case '-': case '!': c = *(arg - 1); continue; case 'l': n = TM_LEAP; break; case 'n': case 's': n = TM_SUBSECOND; break; case 'u': n = TM_UTC; break; default: continue; } if (!n) break; /* * right, the global state stinks * but we respect its locale-like status */ if (c == '+') { if (!(flags & n)) { flags |= n; tm_info.flags |= n; tm = tmxtm(tm, t, (flags & TM_UTC) ? &tm_data.zone[2] : tm->tm_zone); if (!i) tm_info.flags &= ~n; } } else if (flags & n) { flags &= ~n; tm_info.flags &= ~n; tm = tmxtm(tm, t, (flags & TM_UTC) ? &tm_data.zone[2] : tm->tm_zone); if (!i) tm_info.flags |= n; } } continue; push: c = 0; push_delimiter: if (sp < &stack[elementsof(stack)]) { sp->format = (char*)format; format = p; sp->delimiter = delimiter; delimiter = c; sp++; } continue; } tm_info.flags = flags; if (cp >= ep) cp = ep - 1; *cp = 0; return cp; }
Tm_t* tmxtm(register Tm_t* tm, Time_t t, Tm_zone_t* zone) { register struct tm* tp; register Tm_leap_t* lp; Time_t x; time_t now; int leapsec; int y; uint32_t n; int32_t o; #if TMX_FLOAT Time_t z; uint32_t i; #endif tmset(tm_info.zone); leapsec = 0; if ((tm_info.flags & (TM_ADJUST|TM_LEAP)) == (TM_ADJUST|TM_LEAP) && (n = tmxsec(t))) { for (lp = &tm_data.leap[0]; n < lp->time; lp++); if (lp->total) { if (n == lp->time && (leapsec = (lp->total - (lp+1)->total)) < 0) leapsec = 0; t = tmxsns(n - lp->total, tmxnsec(t)); } } x = tmxsec(t); if (!(tm->tm_zone = zone)) { if (tm_info.flags & TM_UTC) tm->tm_zone = &tm_data.zone[2]; else tm->tm_zone = tm_info.zone; } if ((o = 60 * tm->tm_zone->west) && x > o) { x -= o; o = 0; } #if TMX_FLOAT i = x / (24 * 60 * 60); z = i; n = x - z * (24 * 60 * 60); tm->tm_sec = n % 60 + leapsec; n /= 60; tm->tm_min = n % 60; n /= 60; tm->tm_hour = n % 24; #define x i #else tm->tm_sec = x % 60 + leapsec; x /= 60; tm->tm_min = x % 60; x /= 60; tm->tm_hour = x % 24; x /= 24; #endif tm->tm_wday = (x + 4) % 7; tm->tm_year = (400 * (x + 25202)) / 146097 + 1; n = tm->tm_year - 1; x -= n * 365 + n / 4 - n / 100 + (n + (1900 - 1600)) / 400 - (1970 - 1901) * 365 - (1970 - 1901) / 4; tm->tm_mon = 0; tm->tm_mday = x + 1; tm->tm_nsec = tmxnsec(t); tmfix(tm); n += 1900; tm->tm_isdst = 0; if (tm->tm_zone->daylight) { if ((y = tmequiv(tm) - 1900) == tm->tm_year) now = tmxsec(t); else { Tm_t te; te = *tm; te.tm_year = y; now = tmxsec(tmxtime(&te, tm->tm_zone->west)); } if ((tp = tmlocaltime(&now)) && ((tm->tm_isdst = tp->tm_isdst) || o)) { tm->tm_min -= o / 60 + (tm->tm_isdst ? tm->tm_zone->dst : 0); tmfix(tm); } } return tm; }