#include "prjlibs-include/standards.h" #include #include #include #include #include #include #include "skalibs/include/stddjb.h" #include "prjlibs-include/constants.h" #include "runwhen.h" char const* PROG="rw-match"; static void die_malformed(char const*, char const*) gccattr_noreturn; static void die_malformed(char const* str, char const* exp) { strerr_die5x(100, PROG, ": malformed constraints (expected ", exp, "): ", str); } static void die_range(void) gccattr_noreturn; static void die_range(void) { strerr_die2x(100, PROG, ": timestamp out of range"); } static void die_unit_range(char const*) gccattr_noreturn; static void die_unit_range(char const* x) { strerr_die3x(100, PROG, ": value out of range for unit: ", x); } enum { unset, eq, eqn, div }; typedef struct { unsigned int type; unsigned int spec; unsigned int value; unsigned int const min; unsigned int (* const max)(void); unsigned int const maxmax; char id; } unit; static struct taia const zero=TAIA_ZERO; static unsigned int max_weekday (void) { return 6; } static unsigned int max_year (void) { return -1; } static unsigned int max_month (void) { return 12; } static unsigned int max_monthday(void); static unsigned int max_hour (void) { return 23; } static unsigned int max_minute (void) { return 59; } static unsigned int max_second (void) { return 59; } static unit units_weekday[]={ { unset, 0, -1, 0, max_weekday, 6, 'w' }, { unset, 0, -1, 0, max_hour , 23, 'H' }, { unset, 0, -1, 0, max_minute , 59, 'M' }, { unset, 0, -1, 0, max_second , 59, 'S' }, { unset, 0, -1, 0, null , 0, 0 } }; static unit units_monthday[]={ { unset, 0, -1, 0, max_year , -1, 'y' }, { unset, 0, -1, 1, max_month , 12, 'm' }, { unset, 0, -1, 1, max_monthday, 31, 'd' }, { unset, 0, -1, 0, max_hour , 23, 'H' }, { unset, 0, -1, 0, max_minute , 59, 'M' }, { unset, 0, -1, 0, max_second , 59, 'S' }, { unset, 0, -1, 0, null , 0, 0 } }; static unsigned int max_monthday(void) { static unsigned int const limits[]= { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; unsigned int const year =units_monthday[0].value; unsigned int const month=units_monthday[1].value; int leapday; if (month!=2) leapday=0; else if (year%400==0) leapday=1; else if (year%100==0) leapday=0; else if (year% 4==0) leapday=1; else leapday=0; return limits[month-1]+leapday; } int main(int argc, char** argv) { char const* constraint_str; unit* units; unsigned int i; int flag_increased=0; int flag_need_increase=0; struct tm tm; RW_ARG_CHECK(2, " stamp constraints"); constraint_str=argv[2]; if (constraint_str[str_chr(constraint_str, 'w')]=='w') units=units_weekday; else units=units_monthday; while (*constraint_str!='\0') { char const* const constraint=constraint_str; unsigned int len; if (*constraint_str!=',') die_malformed(constraint_str, ","); ++constraint_str; for (i=0;; ++i) { if (units[i].max==null) die_malformed(constraint_str, "\"y\", \"m\", \"d\", \"w\", \"H\", \"M\", or \"S\""); if (*constraint_str==units[i].id) break; } if (units[i].type!=unset) strerr_die3x(100, PROG, ": duplicate constraint for unit: ", constraint); ++constraint_str; switch (*constraint_str) { case '=': units[i].type=eq; break; case '-': units[i].type=eqn; break; case '/': units[i].type=div; break; default: die_malformed(constraint_str, "\"=\", \"-\", \"/\", or \",\""); } ++constraint_str; len=scan_uint(constraint_str, &units[i].spec); if (len==0) die_malformed(constraint_str, "number"); if (units[i].spec==0) units[i].type=eq; else if (units[i].type==eqn) units[i].spec--; if (units[i].spec>units[i].maxmax) { if (units[i].type!=div || units[i].min>0) die_unit_range(constraint); units[i].type=eq; units[i].spec=0; } else if (units[i].specunits[i].max()) goto need_increase; if (newval>value) { flag_increased=1; flag_need_increase=0; } else if (flag_need_increase) goto need_increase; units[i].value=newval; if (!flag_need_increase) { ++i; continue; } need_increase: if (i!=0) { flag_need_increase=1; flag_increased=0; --i; continue; } if (units!=units_weekday) strerr_die2x(99, PROG, ": no future times match constraints"); tm.tm_mday+=7-units[0].value; units[0].value=tm.tm_wday=0; flag_increased=1; flag_need_increase=0; } { struct taia stamp; struct timeval tv; time_t t; if (units==units_weekday) { tm.tm_mday+=units_weekday[0].value-tm.tm_wday; tm.tm_hour =units_weekday[1].value; tm.tm_min =units_weekday[2].value; tm.tm_sec =units_weekday[3].value; } else { tm.tm_year=units_monthday[0].value-1900; tm.tm_mon =units_monthday[1].value-1; tm.tm_mday=units_monthday[2].value; tm.tm_hour=units_monthday[3].value; tm.tm_min =units_monthday[4].value; tm.tm_sec =units_monthday[5].value; } tm.tm_isdst=-1; t=mktime(&tm); if (t==(time_t)-1) die_range(); tv.tv_sec=t; tv.tv_usec=0; taia_from_timeval(&stamp, &tv); rw_pass(&stamp, argv+3); } }