/* 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_
.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 #include #include #include #include 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; }