#include "entry.h" #include #include static time_t rt; static inline time_t* sub_seconds( struct entry_s *e, time_t *now, time_t *now_minus_stay, time_t *now_plus_warn, struct tm *t, struct tm *ttmp, struct tm *torig ) { unsigned mul, mul_last; time_t rttmp; struct tm *swap; rt = e->start; if (rt > *now_plus_warn) return NULL; if (rt >= *now_minus_stay) return &rt; for (mul = 1;;) { mul_last = mul; mul *= 2; if ((int)(mul * e->every.second) <= 0) { mul = ((INT_MAX - 60) / e->every.second); } *t = *ttmp; ttmp->tm_sec += mul * e->every.second; rttmp = rt; if (e->local) rt = mktime(ttmp); else rt = timegm(ttmp); if (rt == -1) return NULL; if (rt >= *now_minus_stay) break; if (e->local) swap = localtime(&rt); else swap = gmtime(&rt); if (swap == NULL) return NULL; *ttmp = *swap; } rt = rttmp; for (mul = mul_last; mul > 1; mul = mul / 2) { *ttmp = *t; ttmp->tm_sec += mul * e->every.second; if (e->local) rttmp = mktime(ttmp); else rttmp = timegm(ttmp); if (rttmp == -1) return NULL; if (rttmp >= *now_minus_stay) continue; rt = rttmp; if (e->local) swap = localtime(&rt); else swap = gmtime(&rt); if (swap == NULL) return NULL; *t = *swap; } while (true) { *ttmp = *t; ttmp->tm_sec += e->every.second; if (e->local) rttmp = mktime(ttmp); else rttmp = timegm(ttmp); if (rttmp == -1) return NULL; if (rttmp > *now_plus_warn) return NULL; rt = rttmp; if (rt >= *now_minus_stay) return &rt; if (e->local) swap = localtime(&rt); else swap = gmtime(&rt); if (swap == NULL) return NULL; *t = *swap; } } static inline time_t* sub_others( struct entry_s *e, time_t *now, time_t *now_minus_stay, time_t *now_plus_warn, struct tm *t, struct tm *ttmp, struct tm *torig ) { unsigned mul, mul_last, mul_max; time_t rttmp; struct tm *swap; mul_max = e->every.year; if (e->every.month > mul_max) mul_max = e->every.month; if (e->every.day > mul_max) mul_max = e->every.day; if (e->every.hour > mul_max) mul_max = e->every.hour; if (e->every.minute > mul_max) mul_max = e->every.minute; if (e->every.second > mul_max) mul_max = e->every.second; mul_max = (INT_MAX - 365) / mul_max; for (mul = 1, mul_last = 1;;) { if (mul == mul_max) return NULL; *t = *torig; t->tm_year += mul * e->every.year; t->tm_mon += mul * e->every.month; t->tm_mday += mul * e->every.day; t->tm_hour += mul * e->every.hour; t->tm_min += mul * e->every.minute; t->tm_sec += mul * e->every.second; if (e->local) rt = mktime(t); else rt = timegm(t); if (rt == -1) return NULL; if (rt >= *now_minus_stay) break; mul_last = mul; mul *= 2; if (mul > mul_max || mul <= mul_last) break; } for (mul = mul_last;;) { mul++; if (mul > mul_max) return NULL; *t = *torig; t->tm_year += mul * e->every.year; t->tm_mon += mul * e->every.month; t->tm_mday += mul * e->every.day; t->tm_hour += mul * e->every.hour; t->tm_min += mul * e->every.minute; t->tm_sec += mul * e->every.second; if (e->local) rt = mktime(t); else rt = timegm(t); if (rt == -1) return NULL; if (rt > *now_plus_warn) return NULL; if (rt >= *now_minus_stay) { if (e->every.second) return &rt; if (e->local) swap = localtime(&rt); else swap = gmtime(&rt); if (swap == NULL) return NULL; *ttmp = *swap; if (ttmp->tm_sec != torig->tm_sec) continue; if (e->every.minute) return &rt; if (ttmp->tm_min != torig->tm_min) continue; if (e->every.hour) return &rt; if (ttmp->tm_hour != torig->tm_hour) continue; if (e->every.day) return &rt; if (ttmp->tm_mday != torig->tm_mday) continue; if (e->every.month) return &rt; if (ttmp->tm_mon != torig->tm_mon) continue; return &rt; } } } /* super messy, but should best-possible avoid any weird leap * years/seconds/dst-problems/other future changes */ time_t* entry_is_active(struct entry_s *e, time_t now) { struct tm t, ttmp, torig, *swap; time_t now_plus_warn, now_minus_stay; assert(e != NULL); swap = localtime(&now); if (swap == NULL) return NULL; t = *swap; ttmp = t; t.tm_year += e->warn.year; t.tm_mon += e->warn.month; t.tm_mday += e->warn.day; t.tm_hour += e->warn.hour; t.tm_min += e->warn.minute; t.tm_sec += e->warn.second; now_plus_warn = mktime(&t); ttmp.tm_year -= e->stay.year; ttmp.tm_mon -= e->stay.month; ttmp.tm_mday -= e->stay.day; ttmp.tm_hour -= e->stay.hour; ttmp.tm_min -= e->stay.minute; ttmp.tm_sec -= e->stay.second; now_minus_stay = mktime(&ttmp); if (now_plus_warn == -1 || now_minus_stay == -1) return NULL; if (e->type == ENTRY_TYPE_ON) { if (e->start >= now_minus_stay && e->start <= now_plus_warn) { rt = e->start; return &rt; } return NULL; } if (e->has_end && now_minus_stay > e->end) return NULL; if (e->local) swap = localtime( &(e->start) ); else swap = gmtime( &(e->start) ); if (swap == NULL) return NULL; t = *swap; torig = t; ttmp = t; if ( e->every.year == 0 && e->every.month == 0 && e->every.day == 0 && e->every.hour == 0 && e->every.minute == 0 ) { return sub_seconds( e, &now, &now_minus_stay, &now_plus_warn, &t, &ttmp, &torig ); } return sub_others( e, &now, &now_minus_stay, &now_plus_warn, &t, &ttmp, &torig ); }