summaryrefslogtreecommitdiff
path: root/clectio.c
diff options
context:
space:
mode:
Diffstat (limited to 'clectio.c')
-rw-r--r--clectio.c127
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;
+}