2021-06-10 23:10:47 -05:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <poll.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2021-06-13 23:34:53 -05:00
|
|
|
struct timer {
|
|
|
|
int s; /* seconds */
|
|
|
|
int d; /* data storage */
|
|
|
|
void (*u)(struct timer *t); /* update function */
|
|
|
|
int (*c)(struct timer *t); /* stop check function */
|
|
|
|
int (*p)(struct timer *t); /* pause check function */
|
|
|
|
};
|
|
|
|
|
|
|
|
void timerdec(struct timer *t) { if (t->s != 0) t->s--; }
|
|
|
|
void timerinc(struct timer *t) { t->s++; }
|
|
|
|
void timerupdate(struct timer *t) { if(t->u != NULL) t->u(t); }
|
|
|
|
|
|
|
|
int timerstate(int (*f)(struct timer *t), struct timer *t) {
|
|
|
|
if(f != NULL) {
|
|
|
|
if(f(t)) return 1;
|
|
|
|
else return 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int timerstop(struct timer *t) { return timerstate(t->c, t); }
|
|
|
|
int timerpause(struct timer *t) { return timerstate(t->p, t); }
|
|
|
|
|
|
|
|
int timerzero(struct timer *t) {
|
|
|
|
if(t->s == 0) return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int seconds(int t) { return t % 60; }
|
|
|
|
int minutes(int t) { return (t / 60) % 60; }
|
|
|
|
int minute(int t) { return t / 60; }
|
|
|
|
int hours(int t) { return (t / 60) / 60; }
|
|
|
|
|
|
|
|
struct timer *timerinit(void) {
|
|
|
|
struct timer *t = malloc(sizeof *t);
|
|
|
|
t->s = 0;
|
|
|
|
t->d = 0;
|
|
|
|
t->u = NULL;
|
|
|
|
t->c = NULL;
|
|
|
|
t->p = NULL;
|
|
|
|
return t;
|
|
|
|
}
|
2021-06-10 23:10:47 -05:00
|
|
|
|
|
|
|
struct settings {
|
|
|
|
int e:1; /* use escape (v assumed) */
|
|
|
|
int v:1; /* verbose */
|
|
|
|
int d:1; /* count down/up (1/0) */
|
|
|
|
int b:1; /* ascii bel when done */
|
|
|
|
int f:1; /* display hours */
|
2021-06-13 23:23:24 -05:00
|
|
|
int t:1; /* tomato timer */
|
2021-06-10 23:10:47 -05:00
|
|
|
int s; /* seconds */
|
2021-06-11 00:29:37 -05:00
|
|
|
} s = {
|
2021-06-10 23:10:47 -05:00
|
|
|
.e = 0,
|
|
|
|
.v = 0,
|
|
|
|
.d = 0,
|
|
|
|
.b = 0,
|
|
|
|
.f = 0,
|
2021-06-13 23:23:24 -05:00
|
|
|
.t = 0,
|
2021-06-10 23:10:47 -05:00
|
|
|
.s = 0
|
|
|
|
};
|
|
|
|
|
|
|
|
int timerissettings(struct timer *t) {
|
2021-06-11 00:26:49 -05:00
|
|
|
if(t->s == 0) return 0;
|
2021-06-11 00:49:03 -05:00
|
|
|
if(s.s == t->s) return 1;
|
2021-06-10 23:10:47 -05:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-06-13 23:23:24 -05:00
|
|
|
int tomatotimer(struct timer *t) {
|
|
|
|
if(t->s != 0) return 0;
|
|
|
|
if(t->d % 2) t->s = s.s / 2;
|
|
|
|
else t->s = s.s;
|
|
|
|
t->d++;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-06-10 23:10:47 -05:00
|
|
|
char *timerdisp(struct timer *t) {
|
|
|
|
char *str = malloc(20);
|
2021-06-11 00:29:37 -05:00
|
|
|
if(s.f) snprintf(str, 20, "%02i:%02i:%02i",
|
2021-06-11 00:58:16 -05:00
|
|
|
hours(t->s), minutes(t->s), seconds(t->s));
|
|
|
|
/* TODO: give minute(...) and minutes(...) better names */
|
|
|
|
else snprintf(str, 20, "%02i:%02i", minute(t->s), seconds(t->s));
|
2021-06-10 23:10:47 -05:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
void timerloop() {
|
|
|
|
struct timer *t = timerinit();
|
2021-06-11 00:29:37 -05:00
|
|
|
if(s.d) {
|
2021-06-10 23:10:47 -05:00
|
|
|
t->u = timerdec;
|
2021-06-11 00:49:03 -05:00
|
|
|
t->s = s.s;
|
2021-06-10 23:10:47 -05:00
|
|
|
t->c = timerzero;
|
|
|
|
} else {
|
|
|
|
t->u = timerinc;
|
|
|
|
t->c = timerissettings;
|
|
|
|
}
|
2021-06-13 23:23:24 -05:00
|
|
|
if(s.t) {
|
|
|
|
t->u = timerdec;
|
|
|
|
if(s.s == 0) s.s = 20 * 60;
|
|
|
|
t->s = s.s;
|
|
|
|
t->d = 1;
|
|
|
|
t->p = tomatotimer;
|
|
|
|
t->c = NULL;
|
|
|
|
}
|
|
|
|
|
2021-06-10 23:10:47 -05:00
|
|
|
char *c;
|
2021-06-13 23:23:24 -05:00
|
|
|
int e;
|
2021-06-11 00:06:29 -05:00
|
|
|
struct pollfd p = { .fd = STDIN_FILENO, .events = POLLIN };
|
2021-06-10 23:10:47 -05:00
|
|
|
for(;;) {
|
2021-06-11 00:06:29 -05:00
|
|
|
poll(&p, 1, 60);
|
2021-06-13 23:23:24 -05:00
|
|
|
if((e = (p.revents == POLLIN)) || timerpause(t)) {
|
2021-06-10 23:10:47 -05:00
|
|
|
/* TODO: make this nicer */
|
2021-06-13 23:23:24 -05:00
|
|
|
if(e) getchar();
|
2021-06-11 00:29:37 -05:00
|
|
|
if(s.e) {
|
2021-06-10 23:10:47 -05:00
|
|
|
c = timerdisp(t);
|
2021-06-13 23:23:24 -05:00
|
|
|
if(e) printf("\r\e[1A* %s", c);
|
|
|
|
else printf("\r* %s", c);
|
2021-06-10 23:10:47 -05:00
|
|
|
}
|
|
|
|
getchar();
|
|
|
|
/* TODO: stop relying on hard assumptions */
|
2021-06-11 00:32:02 -05:00
|
|
|
if(s.e) printf("\r\e[1A \r");
|
2021-06-10 23:10:47 -05:00
|
|
|
}
|
|
|
|
c = timerdisp(t);
|
2021-06-11 00:29:37 -05:00
|
|
|
if(s.e) {
|
2021-06-10 23:10:47 -05:00
|
|
|
printf("%s\r", c);
|
|
|
|
fflush(stdout);
|
|
|
|
}
|
2021-06-11 00:29:37 -05:00
|
|
|
else if(s.v) printf("%s\n", c);
|
2021-06-11 00:06:29 -05:00
|
|
|
if(timerstop(t)) break;
|
2021-06-11 00:26:49 -05:00
|
|
|
free(c);
|
2021-06-10 23:10:47 -05:00
|
|
|
timerupdate(t);
|
|
|
|
sleep(1);
|
|
|
|
}
|
2021-06-11 00:29:37 -05:00
|
|
|
if(s.b) putchar('\a');
|
2021-06-11 00:26:49 -05:00
|
|
|
free(t);
|
|
|
|
free(c);
|
2021-06-10 23:10:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
char c;
|
2021-06-13 23:23:24 -05:00
|
|
|
while((c = getopt(argc, argv, "evdbfth:m:s:")) != -1) {
|
2021-06-10 23:10:47 -05:00
|
|
|
switch(c) {
|
2021-06-11 00:29:37 -05:00
|
|
|
break; case 'e': s.e = 1;
|
|
|
|
break; case 'v': s.v = 1;
|
|
|
|
break; case 'd': s.d = 1;
|
|
|
|
break; case 'b': s.b = 1;
|
|
|
|
break; case 'f': s.f = 1;
|
2021-06-13 23:23:24 -05:00
|
|
|
break; case 't': s.t = 1;
|
2021-06-11 00:59:40 -05:00
|
|
|
break; case 'h': s.s = s.s + (atoi(optarg) * 3600);
|
2021-06-11 00:49:03 -05:00
|
|
|
break; case 'm': s.s = s.s + (atoi(optarg) * 60);
|
|
|
|
break; case 's': s.s = s.s + atoi(optarg);
|
2021-06-10 23:23:06 -05:00
|
|
|
break; case '?': return 1;
|
|
|
|
break; default: abort();
|
2021-06-10 23:10:47 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
timerloop();
|
|
|
|
return 0;
|
|
|
|
}
|