X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=snooze.c;h=8bbd93fb366b35437a7fa0aef6cf0610e725074b;hb=d44fd0169fcb9ba3debcaab38b526c7c7bf96d61;hp=a5df96767c541106a85deec9494c062ca0dd691a;hpb=a99b4704518369ebf6606b6a1a271c5cfd21bd5e;p=user%2Fhenk%2Fcode%2Fsnooze.git diff --git a/snooze.c b/snooze.c index a5df967..8bbd93f 100644 --- a/snooze.c +++ b/snooze.c @@ -1,16 +1,11 @@ /* * snooze - run a command at a particular time * - * To the extent possible under law, - * Christian Neukirchen + * To the extent possible under law, Leah Neukirchen * has waived all copyright and related or neighboring rights to this work. * http://creativecommons.org/publicdomain/zero/1.0/ */ -/* -##% gcc -Os -Wall -g -o $STEM $FILE -Wextra -Wwrite-strings -*/ - #include #include @@ -64,6 +59,34 @@ parse_int(char **s, size_t minn, size_t maxn) return n; } +static long +parse_dur(char *s) +{ + long n; + char *end; + + errno = 0; + n = strtol(s, &end, 10); + if (errno) { + perror("strtol"); + exit(1); + } + if (n < 0) { + fprintf(stderr, "negative duration\n"); + exit(1); + } + switch (*end) { + case 'm': n *= 60; break; + case 'h': n *= 60*60; break; + case 'd': n *= 24*60*60; break; + case 0: break; + default: + fprintf(stderr, "junk after duration: %s\n", end); + exit(1); + } + return n; +} + static int parse(char *expr, char *buf, long bufsiz, int offset) { @@ -76,7 +99,7 @@ parse(char *expr, char *buf, long bufsiz, int offset) while (*s) { switch (*s) { case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': + case '5': case '6': case '7': case '8': case '9': n = parse_int(&s, -offset, bufsiz); buf[n+offset] = '*'; break; @@ -90,13 +113,14 @@ parse(char *expr, char *buf, long bufsiz, int offset) case '/': s++; n0 = n; - n = parse_int(&s, -offset, bufsiz); + if (*s) + n = parse_int(&s, -offset, bufsiz); if (n == 0) // / = * n = 1; for (i = n0; i < bufsiz; i += n) buf[i+offset] = '*'; break; - case ',': + case ',': s++; n = 0; break; @@ -116,10 +140,10 @@ parse(char *expr, char *buf, long bufsiz, int offset) } char weekday[8] = {0}; -char dayofmonth[31] = {0}; -char month[12] = {0}; -char dayofyear[366] = {0}; -char weekofyear[53] = {0}; +char dayofmonth[32] = {0}; +char month[13] = {0}; +char dayofyear[367] = {0}; +char weekofyear[54] = {0}; char hour[24] = {0}; char minute[60] = {0}; char second[61] = {0}; @@ -144,11 +168,12 @@ find_next(time_t from) tm = localtime(&t); next_day: - while (!(weekday[tm->tm_wday] == '*' - && dayofmonth[tm->tm_mday-1] == '*' - && month[tm->tm_mon] == '*' - && weekofyear[isoweek(tm)] == '*' - && dayofyear[tm->tm_yday] == '*')) { + while (!( + weekday[tm->tm_wday] == '*' && + dayofmonth[tm->tm_mday-1] == '*' && + month[tm->tm_mon] == '*' && + weekofyear[isoweek(tm)-1] == '*' && + dayofyear[tm->tm_yday] == '*')) { if (month[tm->tm_mon] != '*') { // if month is not good, step month tm->tm_mon++; @@ -157,20 +182,24 @@ next_day: tm->tm_mday++; } + tm->tm_isdst = -1; tm->tm_sec = 0; tm->tm_min = 0; tm->tm_hour = 0; t = mktime(tm); - if (t > from+(365*24*60*60)) // no result within a year + tm->tm_isdst = -1; + + if (t > from+(366*24*60*60)) // no result within a year return -1; } int y = tm->tm_yday; // save yday - while (!(hour[tm->tm_hour] == '*' - && minute[tm->tm_min] == '*' - && second[tm->tm_sec] == '*')) { + while (!( + hour[tm->tm_hour] == '*' && + minute[tm->tm_min] == '*' && + second[tm->tm_sec] == '*')) { if (hour[tm->tm_hour] != '*') { tm->tm_hour++; tm->tm_min = 0; @@ -185,7 +214,7 @@ next_day: if (tm->tm_yday != y) // hit a different day, retry... goto next_day; } - + return t; } @@ -197,11 +226,13 @@ isotime(const struct tm *tm) return isobuf; } -int main(int argc, char *argv[]) +int +main(int argc, char *argv[]) { int c; time_t t; time_t now = time(0); + time_t last = 0; /* default: every day at 00:00:00 */ memset(weekday, '*', sizeof weekday); @@ -213,8 +244,10 @@ int main(int argc, char *argv[]) minute[0] = '*'; second[0] = '*'; - while ((c = getopt(argc, argv, "D:W:H:M:S:T:R:d:m:ns:t:vw:")) != -1) - switch(c) { + setvbuf(stdout, 0, _IOLBF, 0); + + while ((c = getopt(argc, argv, "+D:W:H:M:S:T:R:d:m:ns:t:vw:")) != -1) + switch (c) { case 'D': parse(optarg, dayofyear, sizeof dayofyear, -1); break; case 'W': parse(optarg, weekofyear, sizeof weekofyear, -1); break; case 'H': parse(optarg, hour, sizeof hour, 0); break; @@ -224,23 +257,23 @@ int main(int argc, char *argv[]) case 'm': parse(optarg, month, sizeof month, -1); break; case 'w': parse(optarg, weekday, sizeof weekday, 0); // special case: sunday is both 0 and 7. - if (weekday[7] == '*') + if (weekday[7] == '*') weekday[0] = '*'; break; case 'n': nflag++; break; case 'v': vflag++; break; - case 's': slack = atoi(optarg); break; - case 'T': timewait = atoi(optarg); break; + case 's': slack = parse_dur(optarg); break; + case 'T': timewait = parse_dur(optarg); break; case 't': timefile = optarg; break; - case 'R': randdelay = atoi(optarg); break; + case 'R': randdelay = parse_dur(optarg); break; default: - fprintf(stderr, "Usage: %s [-nv] [-t timefile] [-T timewait] [-R randdelay] [-s slack]\n" + fprintf(stderr, "Usage: %s [-nv] [-t timefile] [-T timewait] [-R randdelay] [-s slack]\n" " [-d mday] [-m mon] [-w wday] [-D yday] [-W yweek] [-H hour] [-M min] [-S sec] COMMAND...\n" "Timespec: exact: 1,3,5\n" " range: 1-7\n" " every n-th: /10\n", argv[0]); - exit(2); - } + exit(2); + } time_t start = now + 1; @@ -251,7 +284,7 @@ int main(int argc, char *argv[]) perror("stat"); t = start - slack - 1 - timewait; } else { - t = st.st_mtime; + t = st.st_mtime + 1; } if (timewait == -1) { while (t < start - slack) @@ -290,9 +323,22 @@ int main(int argc, char *argv[]) /* dry-run, just output the next 5 dates. */ int i; for (i = 0; i < 5; i++) { - if (t > 0) - printf("%s\n", isotime(localtime(&t))); + char weekstr[4]; + struct tm *tm = localtime(&t); + strftime(weekstr, sizeof weekstr, "%a", tm); + printf("%s %s %2ldd%3ldh%3ldm%3lds\n", + isotime(tm), + weekstr, + ((t - now) / (60*60*24)), + ((t - now) / (60*60)) % 24, + ((t - now) / 60) % 60, + (t - now) % 60); t = find_next(t + 1); + if (t < 0) { + fprintf(stderr, + "no satisfying date found within a year.\n"); + exit(2); + } } exit(0); } @@ -310,6 +356,11 @@ int main(int argc, char *argv[]) while (!alarm_rang) { now = time(0); + if (now < last) { + t = find_next(now); + if (vflag) + printf("Time moved backwards, rescheduled for %s\n", isotime(tm)); + } t = mktime(tm); if (t <= now) { if (now - t <= slack) // still about time @@ -327,6 +378,7 @@ int main(int argc, char *argv[]) struct timespec ts; ts.tv_nsec = 0; ts.tv_sec = t - now > SLEEP_PHASE ? SLEEP_PHASE : t - now; + last = now; nanosleep(&ts, 0); // we just iterate again when this exits early }