From 41f73b0a45ba3e63ac33ebdc99f12481f5b7cdab Mon Sep 17 00:00:00 2001 From: katherine Date: Fri, 20 Dec 2019 09:28:54 -0700 Subject: implement printing --- src/calendar.c | 125 +++++++++++++++-------------- src/calendar.h | 2 + src/entry.c | 219 +++++++++++++++++--------------------------------- src/entry.h | 4 +- src/err.h | 19 +++++ src/main.c | 10 ++- src/opt.h | 6 +- src/print.c | 246 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/print.h | 9 +++ 9 files changed, 427 insertions(+), 213 deletions(-) create mode 100644 src/err.h create mode 100644 src/print.c create mode 100644 src/print.h diff --git a/src/calendar.c b/src/calendar.c index 1240547..06d80d7 100644 --- a/src/calendar.c +++ b/src/calendar.c @@ -20,6 +20,7 @@ struct state_s { size_t line, col; size_t last_line, last_col; struct entry_interval_s cur_warn; + struct entry_interval_s cur_stay; bool cur_urgent; bool cur_local; FILE *f; @@ -30,6 +31,7 @@ enum cmd_type_e { CMD_TYPE_WARN, CMD_TYPE_URGENT, CMD_TYPE_LOCAL, + CMD_TYPE_STAY, }; struct cmd_s { @@ -364,6 +366,17 @@ static inline struct cmd_s sub_get_cmd_warn(struct state_s *s) return cmd; } +static inline struct cmd_s sub_get_cmd_stay(struct state_s *s) +{ + struct cmd_s cmd = { + .type = CMD_TYPE_STAY + }; + + cmd.iv = sub_get_interval(s); + + return cmd; +} + static bool sub_get_bool(struct state_s *s) { bool r = false; @@ -526,7 +539,19 @@ static inline struct cmd_s sub_get_cmd(struct state_s *s) ) { s->col += 5; sub_eat_spaces(s); - return sub_get_cmd_urgent(s); + return sub_get_cmd_local(s); + } + break; + + case 's': + if ( + getc(s->f) == 't' && + getc(s->f) == 'a' && + getc(s->f) == 'y' + ) { + s->col += 4; + sub_eat_spaces(s); + return sub_get_cmd_stay(s); } break; } @@ -545,7 +570,7 @@ static char* sub_get_msg(struct state_s *s) while ( (c = getc(s->f)) != '\n' && c != EOF) { s->col++; - if (count == width) { + if (count == width || count + 1 == width) { width += step_size; msg = realloc(msg, width * sizeof(*msg)); @@ -568,6 +593,7 @@ static char* sub_get_msg(struct state_s *s) count++; } + msg[count] = '\0'; s->col = 0; s->line++; @@ -577,10 +603,18 @@ static char* sub_get_msg(struct state_s *s) static inline struct entry_s sub_get_entry_on(struct state_s *s) { struct entry_s e = { - .type = ENTRY_TYPE_ON + .type = ENTRY_TYPE_ON, + .urgent = s->cur_urgent, + .local = s->cur_local, + .warn = s->cur_warn, + .stay = s->cur_stay, }; time_t rt; int c; + struct pos_s p = { + .line = s->last_line, + .col = s->last_col, + }; rt = sub_get_date(s); if (s->err_flag) @@ -593,19 +627,10 @@ static inline struct entry_s sub_get_entry_on(struct state_s *s) c = getc(s->f); if (c != ',') { - if (c == 'w' - && getc(s->f) == 'a' - && getc(s->f) == 'r' - && getc(s->f) == 'n' - ) { - s->col += 4; - e.warn = sub_get_interval(s); - if (s->err_flag) - return e; - } else { - ungetc(c, s->f); - return e; - } + sub_set_pos(s, p); + ERRP("invalid calendar entry"); + s->err_flag = true; + return e; } s->col++; @@ -622,8 +647,9 @@ static inline struct entry_s sub_get_entry_every(struct state_s *s) .urgent = s->cur_urgent, .local = s->cur_local, .warn = s->cur_warn, + .stay = s->cur_stay, }; - bool from_seen = false, to_seen = false, warn_seen = false; + bool from_seen = false, to_seen = false; char c; struct pos_s p = { .line = s->last_line, @@ -685,29 +711,6 @@ static inline struct entry_s sub_get_entry_every(struct state_s *s) break; } - case 'w': - if ( - getc(s->f) == 'a' && - getc(s->f) == 'r' && - getc(s->f) == 'n' - ) { - if (warn_seen) { - ERRP("invalid calendar entry"); - s->err_flag = true; - return e; - } - warn_seen = true; - - s->col += 4; - sub_eat_spaces(s); - e.warn = sub_get_interval(s); - - if (s->err_flag) - return e; - - break; - } - default: goto done; } @@ -792,22 +795,6 @@ static inline void sub_cal_push(struct state_s *s, struct calendar_s *cal, cal->count++; } -static void sub_cal_free(struct calendar_s *cal) -{ - size_t i; - - if (cal->entries == NULL) - return; - - for (i = 0; i < cal->count; i++) { - if (cal->entries[i].msg != NULL) - free(cal->entries[i].msg); - } - - free(cal->entries); - cal->entries = NULL; -} - struct calendar_s calendar_parse(FILE *f) { struct calendar_s cal = { @@ -821,6 +808,9 @@ struct calendar_s calendar_parse(FILE *f) .cur_warn = { .day = 1, }, + .cur_stay = { + .day = 1, + }, .cur_urgent = false, .cur_local = true, .f = f, @@ -843,7 +833,7 @@ struct calendar_s calendar_parse(FILE *f) cmd = sub_get_cmd(&s); if (s.err_flag) { - sub_cal_free(&cal); + calendar_wipe(&cal); cal.err_flag = true; return cal; } @@ -858,6 +848,9 @@ struct calendar_s calendar_parse(FILE *f) case CMD_TYPE_LOCAL: s.cur_local = cmd.b; break; + case CMD_TYPE_STAY: + s.cur_stay = cmd.iv; + break; } continue; @@ -867,7 +860,7 @@ struct calendar_s calendar_parse(FILE *f) e = sub_get_entry(&s); if (s.err_flag) { - sub_cal_free(&cal); + calendar_wipe(&cal); cal.err_flag = true; return cal; } @@ -876,3 +869,19 @@ struct calendar_s calendar_parse(FILE *f) return cal; } + +void calendar_wipe(struct calendar_s *cal) +{ + size_t i; + + if (cal->entries == NULL) + return; + + for (i = 0; i < cal->count; i++) { + if (cal->entries[i].msg != NULL) + free(cal->entries[i].msg); + } + + free(cal->entries); + cal->entries = NULL; +} diff --git a/src/calendar.h b/src/calendar.h index ccf59bb..cee6f3d 100644 --- a/src/calendar.h +++ b/src/calendar.h @@ -14,4 +14,6 @@ struct calendar_s { struct calendar_s calendar_parse(FILE *f); +void calendar_wipe(struct calendar_s *cal); + #endif diff --git a/src/entry.c b/src/entry.c index f903d97..13208ca 100644 --- a/src/entry.c +++ b/src/entry.c @@ -2,177 +2,100 @@ #include -static int sub_inc_year(struct tm *t, int n) -{ - if (n == 0) - return 0; - - t->tm_year += n; - - if (mktime(t) == -1) - return -1; - - return 0; -} +static time_t rt; -static int sub_inc_month(struct tm *t, int n) +/* super inefficient, 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) { - unsigned i; - - if (n == 0) - return 0; - - for (i = 0; i < n; i++) { - t->tm_mon++; - if (mktime(t) == -1) { - t->tm_mon = 0; - if (sub_inc_year(t, 1) == -1) - return -1; - } - } - - return 0; -} + struct tm t, ttmp, *tmp; + time_t rttmp, now_plus_warn, now_minus_stay; + + assert(e != NULL); -static int sub_inc_day(struct tm *t, int n) -{ - unsigned i; + tmp = localtime(&now); + if (tmp == NULL) + return NULL; + t = *tmp; + ttmp = t; - if (n == 0) - return 0; + 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; - for (i = 0; i < n; i++) { - t->tm_mday++; - if (mktime(t) == -1) { - t->tm_mday = 1; - if (sub_inc_month(t, 1) == -1) - return -1; - } - } + now_plus_warn = mktime(&t); - return 0; -} + 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; -static int sub_inc_hour(struct tm *t, int n) -{ - unsigned i; + now_minus_stay = mktime(&ttmp); - if (n == 0) - return 0; + if (now_plus_warn == -1 || now_minus_stay == -1) + return NULL; - for (i = 0; i < n; i++) { - t->tm_hour++; - if (mktime(t) == -1) { - t->tm_hour = 0; - if (sub_inc_day(t, 1) == -1) - return -1; + if (e->type == ENTRY_TYPE_ON) { + if (e->start >= now_minus_stay && e->start <= now_plus_warn) { + rt = e->start; + return &rt; } - } - - return 0; -} - -static int sub_inc_minute(struct tm *t, int n) -{ - unsigned i; - if (n == 0) - return 0; - - for (i = 0; i < n; i++) { - t->tm_min++; - if (mktime(t) == -1) { - t->tm_min = 0; - if (sub_inc_hour(t, 1) == -1) - return -1; - } + return NULL; } - return 0; -} - -static int sub_inc_second(struct tm *t, int n) -{ - time_t rt; - struct tm *tmp; - - if (n == 0) - return 0; - - rt = mktime(t); - - if (rt + n <= rt) - return -1; - rt += n; + if (e->has_end && now_minus_stay > e->end) + return NULL; - tmp = localtime(&rt); - *t = *tmp; - - return 0; -} + tmp = localtime( &(e->start) ); + if (tmp == NULL) + return NULL; + t = *tmp; -/* super inefficient, but should best-possible avoid any weird leap - * years/seconds/dst-problems/other future changes */ -bool entry_is_active(struct entry_s *e, time_t now) -{ - struct tm t, *tmp; - time_t rt, now_plus_warn; - - assert(e != NULL); + for (rt = e->start;;) { + if (rt > now_plus_warn) + return NULL; - tmp = localtime(&now); - assert(tmp != NULL); - t = *tmp; + if (rt >= now_minus_stay) + return &rt; - if (sub_inc_year(&t, e->warn.year)) - return false; - if (sub_inc_month(&t, e->warn.month)) - return false; - if (sub_inc_day(&t, e->warn.day)) - return false; - if (sub_inc_hour(&t, e->warn.hour)) - return false; - if (sub_inc_minute(&t, e->warn.minute)) - return false; - if (sub_inc_second(&t, e->warn.second)) - return false; + ttmp = t; - now_plus_warn = mktime(&t); + t.tm_year += e->every.year; + t.tm_mon += e->every.month; + t.tm_mday += e->every.day; + t.tm_hour += e->every.hour; + t.tm_min += e->every.minute; + t.tm_sec += e->every.second; - if (e->type == ENTRY_TYPE_ON) { - if (e->start >= now && e->start <= now_plus_warn) - return true; + rt = mktime(&t); - return false; - } + if (rt == -1) { + rttmp = mktime(&ttmp); + if (rttmp == -1) + return NULL; - tmp = localtime(&(e->start)); - assert(tmp != NULL); - t = *tmp; + tmp = localtime(&rttmp); + if (tmp == NULL) + return NULL; + t = *tmp; - if (e->has_end && now > e->end) - return false; + t.tm_year += e->every.year; + t.tm_mon += e->every.month; + t.tm_mday += e->every.day; + t.tm_hour += e->every.hour; + t.tm_min += e->every.minute; + t.tm_sec += e->every.second; - for (rt = e->start;;) { - rt = mktime(&t); + rt = mktime(&t); - if (rt > now_plus_warn) - return false; - - if (rt >= now) - return true; - - if (sub_inc_year(&t, e->every.year)) - return false; - if (sub_inc_month(&t, e->every.month)) - return false; - if (sub_inc_day(&t, e->every.day)) - return false; - if (sub_inc_hour(&t, e->every.hour)) - return false; - if (sub_inc_minute(&t, e->every.minute)) - return false; - if (sub_inc_second(&t, e->every.second)) - return false; + if (rt == -1) + return NULL; + } } } diff --git a/src/entry.h b/src/entry.h index 41b7808..6c9791f 100644 --- a/src/entry.h +++ b/src/entry.h @@ -18,13 +18,13 @@ struct entry_s { enum entry_type_e type; bool has_end; time_t start, end; - struct entry_interval_s every, warn; + struct entry_interval_s every, warn, stay; bool urgent; bool local; char *msg; }; /* test if an entry needs warning */ -bool entry_is_active(struct entry_s *e, time_t now); +time_t* entry_is_active(struct entry_s *e, time_t now); #endif diff --git a/src/err.h b/src/err.h new file mode 100644 index 0000000..dd097fc --- /dev/null +++ b/src/err.h @@ -0,0 +1,19 @@ +#ifndef EVERY_ERR_H +#define EVERY_ERR_H + +#include +#include + +#define ERRM(...) \ + do { \ + fprintf(stderr, "err: " __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + } while (0) + +#define ERR(...) \ + do { \ + ERRM(__VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } while (0) + +#endif diff --git a/src/main.c b/src/main.c index 5c01fe0..27c5349 100644 --- a/src/main.c +++ b/src/main.c @@ -1,10 +1,10 @@ #include "opt.h" #include "err.h" +#include "calendar.h" +#include "print.h" #include "../reqs/simple-xdg-bdirs/simple-xdg-bdirs.h" -#include "calendar.h" - #include #include @@ -115,6 +115,12 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); /* output commands */ + if (cmd == OPT_COMMAND_CONSOLE) + print_console(&cal); + else + print_script(&cal); + + calendar_wipe(&cal); return 0; } diff --git a/src/opt.h b/src/opt.h index dee767c..45bc0bd 100644 --- a/src/opt.h +++ b/src/opt.h @@ -2,9 +2,9 @@ #define EVERY_OPT_H enum opt_command_e { - OPT_COMMAND_CONSOLE = 0, - OPT_COMMAND_SCRIPT = 1, - OPT_COMMAND_EDIT = 1, + OPT_COMMAND_CONSOLE, + OPT_COMMAND_SCRIPT, + OPT_COMMAND_EDIT, }; void opt_parse(int argc, char **argv); diff --git a/src/print.c b/src/print.c new file mode 100644 index 0000000..93ce295 --- /dev/null +++ b/src/print.c @@ -0,0 +1,246 @@ +#include "print.h" + +#include "entry.h" +#include "opt.h" +#include "err.h" + +#include +#include +#include + +static const char *weekday_names[] = { + "Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat" +}; + +static const char *weekday_names_l[] = { + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday" +}; + +static const char *month_names[] = { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" +}; + +struct buf_s { + time_t rt; + struct entry_s e; +}; + +static int buf_cmp(const void *a, const void *b) +{ + const struct buf_s *a1 = a, *b1 = b; + + if (b1->e.urgent && !(a1->e.urgent)) + return 1; + + if (a1->e.urgent && !(b1->e.urgent)) + return -1; + + if (a1->rt > b1->rt) + return 1; + + if (b1->rt > a1->rt) + return -1; + + return 0; +} + +void print_console(struct calendar_s *cal) +{ + size_t i, j; + struct tm t = { 0 }, ttmp; + time_t now = time(NULL), *rttmp; + time_t ototois_end, yesterdays_end, todays_end, tomorrows_end, weeks_end; + bool has_urgent = false, urgent_printed = false; + + struct buf_s *buf = malloc(cal->count * sizeof(*buf)); + + if (buf == NULL) { + ERRM("failed to allocate memory"); + return; + } + + /* get interval limits */ + + t = *localtime(&now); + + ttmp.tm_year = t.tm_year; + ttmp.tm_mon = t.tm_mon; + ttmp.tm_mday = t.tm_mday - 1; + ttmp.tm_hour = 0; + ttmp.tm_min = 0; + ttmp.tm_sec = 0; + ttmp.tm_isdst = -1; + + ototois_end = mktime(&ttmp); + + ttmp.tm_mday++; + + yesterdays_end = mktime(&ttmp); + + ttmp.tm_mday++; + + todays_end = mktime(&ttmp); + + ttmp.tm_mday++; + + tomorrows_end = mktime(&ttmp); + + ttmp.tm_mday = t.tm_mday + (6 - t.tm_wday) + 1; + + weeks_end = mktime(&ttmp); + + printf("%s %d %s %02d %02d:%02d\n\n", + weekday_names[t.tm_wday], + t.tm_year + 1900, + month_names[t.tm_mon], + t.tm_mday, + t.tm_hour, + t.tm_min + ); + + /* fill buffer with active events */ + for (i = 0, j = 0; i < cal->count; i++) { + if ( !(rttmp = entry_is_active( &(cal->entries[i]), now)) ) + continue; + + buf[j].rt = *rttmp; + buf[j].e = cal->entries[i]; + + if (buf[j].e.urgent) + has_urgent = true; + + j++; + } + + qsort(buf, j, sizeof(*buf), buf_cmp); + + /* print from buffer */ + if (has_urgent) + printf("\n[ URGENT ]\n\n"); + + for (i = 0; i < j; i++) { + t = *localtime( &(buf[i].rt) ); + + if (has_urgent && !urgent_printed && !(buf[i].e.urgent) ) { + printf("\n\n[ normal ]\n\n"); + urgent_printed = true; + } + + /* date */ + if (ototois_end > buf[i].rt) { + printf("%04d %s %02d", + t.tm_year + 1900, + month_names[t.tm_mon], + t.tm_mday + ); + } else if (yesterdays_end > buf[i].rt) { + printf("Yesterday "); + } else if (todays_end > buf[i].rt) { + printf("Today "); + } else if (tomorrows_end > buf[i].rt) { + printf("Tomorrow "); + } else if (weeks_end > buf[i].rt) { + printf("%-11s", weekday_names_l[t.tm_wday]); + } else { + printf("%04d %s %02d", + t.tm_year + 1900, + month_names[t.tm_mon], + t.tm_mday + ); + } + + /* time */ + if (t.tm_hour != 0 || t.tm_min != 0 || t.tm_sec != 0) { + printf(" %02d:%02d", t.tm_hour, t.tm_min); + + if (t.tm_sec != 0) + printf(":%02d", t.tm_sec); + } + + + if (buf[i].e.msg != NULL) + printf(" %s", buf[i].e.msg); + + puts(""); + } + + free(buf); +} + +void print_script(struct calendar_s *cal) +{ + size_t i, j; + struct tm t = { 0 }; + time_t now = time(NULL), *rttmp; + char cd; + bool first = true; + struct buf_s *buf = malloc(cal->count * sizeof(*buf)); + + if (buf == NULL) { + ERRM("failed to allocate memory"); + return; + } + + cd = opt_col_delim(); + + /* fill buffer with active events */ + for (i = 0, j = 0; i < cal->count; i++) { + if ( !(rttmp = entry_is_active( &(cal->entries[i]), now)) ) + continue; + + buf[j].rt = *rttmp; + buf[j].e = cal->entries[i]; + + j++; + } + + qsort(buf, j, sizeof(*buf), buf_cmp); + + /* print from buffer */ + for (i = 0; i < j; i++) { + t = *localtime( &(buf[i].rt) ); + + if (!first) + printf("%c", opt_line_delim()); + + printf( + "%d%c%d%c%d%c%d%c%d%c%d%c" /* date */ + "%d%c" /* urgent */ + "%d%c" /* local */ + "%s" /* msg */ + , + t.tm_year + 1900, cd, t.tm_mon + 1, cd, t.tm_mday, cd, + t.tm_hour, cd, t.tm_min, cd, t.tm_sec, cd, + cal->entries[i].urgent, cd, + cal->entries[i].local, cd, + (cal->entries[i].msg == NULL ? "" : cal->entries[i].msg) + ); + + first = false; + } + + free(buf); +} diff --git a/src/print.h b/src/print.h new file mode 100644 index 0000000..5bbc2c1 --- /dev/null +++ b/src/print.h @@ -0,0 +1,9 @@ +#ifndef EVERY_PRINT_H +#define EVERY_PRINT_H + +#include "calendar.h" + +void print_console(struct calendar_s *cal); +void print_script(struct calendar_s *cal); + +#endif -- cgit v1.2.3