diff options
author | Krow Savcik <krow@savcik.xyz> | 2025-07-26 12:50:28 +0300 |
---|---|---|
committer | Krow Savcik <krow@savcik.xyz> | 2025-07-26 12:50:28 +0300 |
commit | 9f2884c0dcbd7762c8a6a067174c3ca1f304d9c0 (patch) | |
tree | 90d21c6864a5b15b28612bf5ee11d8beb539f87c /vtime.h |
Diffstat (limited to 'vtime.h')
-rw-r--r-- | vtime.h | 194 |
1 files changed, 194 insertions, 0 deletions
@@ -0,0 +1,194 @@ +int vtime(struct tm *, const char *, int); + +enum vtime_flags { + VTIME_START_SUNDAY = 1 +}; + +#ifdef VTIME_IMPL +static const char * vtime_next_word(const char *); +static const char * vtime_relative3(struct tm *, const char *, const int); +static const char * vtime_relative2(struct tm *, const char *); + +static const char* vtime_day_names[] = { + "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" +}; + +int +vtime(struct tm *tm, const char *fmt, int flags) +{ + int i, j, k; + const char *pnt; + for (; *fmt; fmt++) { + if (isblank(*fmt)) + continue; + + /* Do relative 1 */ + if (*fmt == '+' || *fmt == '-') { + i = isdigit(fmt[1]) ? 0 : 1; + pnt = fmt+1; + while (isdigit(*pnt)) + i = i * 10 + (*(pnt++) - '0'); + if (fmt[0] == '-') + i = -i; + + switch (tolower(*pnt)) { + case 'w': + i *= 7; + /* FALLTHROUGH */ + case 'd': + tm->tm_mday += i; + break; + case 'm': + tm->tm_mon += i; + break; + case 'y': + tm->tm_year += i; + break; + default: + return 1; + } + + fmt = pnt; + /* No day-time savings. We want the same relative hh:mm */ + tm->tm_isdst = -1; + mktime(tm); + continue; + } + + /* Absolute 1 */ + if (isdigit(fmt[0])) { + i = j = k = -1; +vtime_abs: + k = j; + j = i; + for (i = 0; isdigit(*fmt); fmt++) + i = i * 10 + (*fmt - '0'); + + if (!isblank(*fmt) && fmt[0]) { + fmt++; + goto vtime_abs; + } + + if (k != -1) + tm->tm_year = k + (k < 100 ? (tm->tm_year / 100 * 100) : -1900); + + tm->tm_mon = (j == -1) ? tm->tm_mon : j-1; + tm->tm_mday = i; + + /* No day-time savings. We want the same relative hh:mm */ + tm->tm_isdst = -1; + mktime(tm); + continue; + } + + switch (tolower(fmt[0])) { + case 'f': + case 's': + case 'b': + case 'e': + fmt = vtime_relative3(tm, fmt, flags & VTIME_START_SUNDAY); + if (fmt == NULL) + return 1; + break; + case 'p': + case 'l': + case 'n': + case 't': + fmt = vtime_relative2(tm, fmt); + if (fmt == NULL) + return 1; + break; + default: + return 1; + } + } + + return 0; +} + +static const char * +vtime_relative2(struct tm *tm, const char *s) +{ + size_t len; + int i, next = (s[0] == 'n') || (s[0] == 't'); + const char *day = vtime_next_word(s); + if (!day[0]) + return NULL; + + for (len = 0; day[len] && !isblank(day[len]); len++); + + for (i = 0; i < 7; i++) { + if (!strncasecmp(day, vtime_day_names[i], len)) + break; + } + + /* TODO: Could change to words like month/week/year/day */ + if (i == 7) + return NULL; + + if (next) + i = ((i + 13 - tm->tm_wday) % 7) + 1; + else + i = - (((tm->tm_wday - i + 13) % 7) + 1); + + tm->tm_mday += i; + /* No day-time savings. We want the same relative hh:mm */ + tm->tm_isdst = -1; + mktime(tm); + + + for (s = day; s[1] && !isblank(s[1]); s++); + return s; +} + +static const char * +vtime_relative3(struct tm *tm, const char *s, const int startSun) +{ + int i, toend = tolower(s[0]) == 'e'; + const char *type = vtime_next_word(s); + switch (tolower(*type)) { + case 'w': + i = tm->tm_wday; + if (!startSun) + i = (i + 6) % 7; + tm->tm_mday += - i + 6 * toend; + break; + case 'm': + tm->tm_mday = 1; + if (toend) { + tm->tm_mon++; + tm->tm_mday = 0; + } + break; + case 'y': + tm->tm_mday = 1; + tm->tm_mon = 0; + if (toend) { + tm->tm_year++; + tm->tm_mday = 0; + } + break; + default: + return NULL; + } + /* No day-time savings. We want the same relative hh:mm */ + tm->tm_isdst = -1; + mktime(tm); + + + for (s = type; s[1] && !isblank(s[1]); s++); + return s; +} + +static const char * +vtime_next_word(const char *s) +{ + while (*s && !isblank(*s)) + s++; + + while (isblank(*s)) + s++; + + return s; +} +#endif |