diff options
Diffstat (limited to 'clectio.c')
| -rw-r--r-- | clectio.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/clectio.c b/clectio.c new file mode 100644 index 0000000..7a660cb --- /dev/null +++ b/clectio.c @@ -0,0 +1,127 @@ +/* clectio -- tiny, fast, suckless daily readings. + * + * Computes nothing at runtime: the liturgical calendar, its reading citations + * and the scripture text are all compiled in (see gen/ and the Makefile). For a + * date it does a table lookup and prints the day and its readings. Configuration + * is compile-time (config.h), suckless-style: edit and recompile. + * + * Public domain. The compiled scripture corpus is NOT part of this program's + * licence (see README): the default is the public-domain Latin Vulgate. + */ +#define _POSIX_C_SOURCE 200809L /* localtime_r, isatty under -std=c99 */ + +#include "config.h" +#include LITURGY /* gen/liturgy_<form>.h: names,parts,cites_*,vpool,readings,rpool,days,cal,EPOCH,NDAYS */ +#include "text.lz.h" /* embedded LZSS text blob: text_lz[], text_lz_len */ +#include "lz.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +static char *textbuf; /* inflated verse text */ +static const char **verse; /* verse[i] -> the text of the i-th key, nul-terminated */ +static int usecolor; + +static const char *const colname[] = { "green", "white", "red", "violet", "rose", "black" }; +static const char *const colansi[] = { "\033[32m", "\033[37m", "\033[31m", "\033[35m", "\033[95m", "\033[90m" }; + +/* Days since the civil epoch 1970-01-01 (Howard Hinnant's algorithm). */ +static long days_from_civil(long y, unsigned m, unsigned d) { + y -= m <= 2; + long era = (y >= 0 ? y : y - 399) / 400; + unsigned yoe = (unsigned)(y - era * 400); + unsigned doy = (153u * (m + (m > 2 ? -3u : 9u)) + 2u) / 5u + d - 1; + unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; + return era * 146097 + (long)doe - 719468; +} + +static void load_text(void) { + unsigned raw = text_lz[0] | text_lz[1] << 8 | text_lz[2] << 16 | (unsigned)text_lz[3] << 24; + int cap = 8192, n = 0; + char *p; + textbuf = malloc(raw + 1); + lz_unpack(text_lz + 4, text_lz_len - 4, (unsigned char *)textbuf, raw); + textbuf[raw] = 0; + verse = malloc(cap * sizeof(*verse)); + verse[n++] = textbuf; + for (p = textbuf; *p; p++) + if (*p == '\n') { + *p = 0; + if (p[1]) { + if (n == cap) { cap *= 2; verse = realloc(verse, cap * sizeof(*verse)); } + verse[n++] = p + 1; + } + } +} + +static const char *citation(int r) { +#ifdef SIGLA_LATIN + return cites_la[readings_cite_la[r]]; +#else + return cites_en[readings[r].cite]; +#endif +} + +static void print_day(long off, const char *datestr) { + const Day *d = &days[cal[off]]; + unsigned k, ri; + if (usecolor) + printf("%s%s\033[0m", colansi[d->colour], names[d->name]); + else + printf("%s \xc2\xb7 %s", names[d->name], colname[d->colour]); + printf("\n%s for %s\n", FORMNAME, datestr); + for (k = 0; k < d->rlen; k++) + putchar('='); + putchar('\n'); + for (ri = 0; ri < d->rlen; ri++) { + const Reading *r = &readings[rpool[d->roff + ri]]; + unsigned v; + printf("\n%s (%s)\n\n", parts[r->part], citation(rpool[d->roff + ri])); + for (v = 0; v < r->vlen; v++) + printf("%s\n", verse[vpool[r->voff + v]]); + } +} + +int main(int argc, char **argv) { + struct tm tm; + long off; + char datestr[16]; + int y, m, dd; + + usecolor = COLOR && isatty(1); + + if (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) { + fprintf(stderr, "usage: clectio [YYYY-MM-DD] (default: today)\n" + " compiled: %s, %s, %d-%d\n", FORMNAME, SIGLANAME, EPOCH_Y, EPOCH_Y + (NDAYS / 366)); + return 0; + } + if (argc > 1) { + if (sscanf(argv[1], "%d-%d-%d", &y, &m, &dd) != 3) { + fprintf(stderr, "clectio: bad date %s (want YYYY-MM-DD)\n", argv[1]); + return 2; + } + snprintf(datestr, sizeof datestr, "%04d-%02d-%02d", y, m, dd); + } else { + time_t t = time(NULL); + localtime_r(&t, &tm); + y = tm.tm_year + 1900; + m = tm.tm_mon + 1; + dd = tm.tm_mday; + strftime(datestr, sizeof datestr, "%Y-%m-%d", &tm); + } + + off = days_from_civil(y, (unsigned)m, (unsigned)dd) - + days_from_civil(EPOCH_Y, EPOCH_M, EPOCH_D); + if (off < 0 || off >= NDAYS) { + fprintf(stderr, "clectio: %s is outside the compiled range %d..%d\n", + datestr, EPOCH_Y, EPOCH_Y + (NDAYS / 366)); + return 1; + } + + load_text(); + print_day(off, datestr); + return 0; +} |
