summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-07-29 08:57:11 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-07-29 08:57:11 +0200
commitf16b5d713bcd839a250bf17241c734316389b5fb (patch)
tree8328d3cef8d1122922534c389934709fbc27ed11
parent4290b7b2cbeeba4f08446f15c04b64d70dedbabc (diff)
downloadclectio-f16b5d713bcd839a250bf17241c734316389b5fb.tar.gz
clectio-f16b5d713bcd839a250bf17241c734316389b5fb.zip
feat: --month [YYYY-MM | N] month overview
List a whole month, one line per day: weekday, day, liturgical colour and celebration name. Form-aware; colours the name on a tty and prints the colour word (aligned column) always, so a piped file stays readable. Defaults to the current month; accepts YYYY-MM or a bare month number (current year). Needs no scripture text, so it never loads or decompresses the text blob. Days-in-month and weekday are computed with days_from_civil (leap-correct); a month outside the compiled range is reported, not guessed. No table/data change; OF and EF build clean under -Wall -Wextra; binary unchanged at 666 KB. Claude-Session: https://claude.ai/code/session_01S1CD1u3tgSS4xNu6WHfp5a
-rw-r--r--README.md12
-rw-r--r--clectio.c67
2 files changed, 74 insertions, 5 deletions
diff --git a/README.md b/README.md
index 2fea861..eb763e2 100644
--- a/README.md
+++ b/README.md
@@ -18,14 +18,18 @@ the Go engine that computes and generates clectio's data.
./clectio 2026-12-25 # a given date
./clectio -g 2026-12-25 # the Gospel only
./clectio -a # all readings (override a Gospel-only build)
+ ./clectio --month # this month at a glance (day, colour, celebration)
+ ./clectio --month 2026-04 > apr.txt # a month to a file for reference
make install # into $PREFIX/bin (default /usr/local)
Needs only a C99 compiler and libc. It builds in about a second.
-The only run-time options are `-a`/`--all`, `-g`/`--gospel` (which reading set
-to print, overriding the compiled default) and `-h`/`--help`; everything else is
-compile-time. Reading text wraps to the terminal width by default (see `WRAP`);
-piped output is left one line per verse.
+The run-time options are `-a`/`--all`, `-g`/`--gospel` (which reading set to
+print, overriding the compiled default), `--month [YYYY-MM | N]` (one line per
+day of a month — weekday, colour and celebration, no readings; defaults to the
+current month) and `-h`/`--help`. Everything else is compile-time. Reading text
+wraps to the terminal width by default (see `WRAP`); piped output is left one
+line per verse.
## Configure (suckless style)
diff --git a/clectio.c b/clectio.c
index 72a1306..1839ade 100644
--- a/clectio.c
+++ b/clectio.c
@@ -107,6 +107,64 @@ static void putwrapped(const char *s, int w) {
}
}
+/* One line per day of month `mon` in year `y`: weekday, day, colour, celebration.
+ * Needs no scripture text, so it never touches the text blob. Returns an exit
+ * code (1 if the month falls outside the compiled range). */
+static int print_month(int y, int mon) {
+ static const char *const wd[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+ long base = days_from_civil(EPOCH_Y, EPOCH_M, EPOCH_D);
+ long civ1 = days_from_civil(y, (unsigned)mon, 1);
+ long nextfirst = days_from_civil(mon == 12 ? y + 1 : y, (unsigned)(mon == 12 ? 1 : mon + 1), 1);
+ int dim = (int)(nextfirst - civ1); /* days in the month (leap-correct) */
+ long off1 = civ1 - base;
+ int day, n;
+
+ if (off1 < 0 || off1 + dim - 1 >= NDAYS) {
+ fprintf(stderr, "clectio: %04d-%02d is outside the compiled range %d..%d\n",
+ y, mon, EPOCH_Y, EPOCH_Y + (NDAYS / 366));
+ return 1;
+ }
+ n = printf("%04d-%02d %s\n", y, mon, FORMNAME) - 1; /* underline that line */
+ while (n-- > 0)
+ putchar('=');
+ putchar('\n');
+ for (day = 1; day <= dim; day++) {
+ long civ = civ1 + (day - 1);
+ const Day *d = &days[cal[off1 + (day - 1)]];
+ int w = (int)((civ + 4) % 7); /* 1970-01-01 was Thursday; 0 = Sunday */
+ printf("%s %02d %-6s ", wd[w], day, colname[d->colour]);
+ if (usecolor)
+ printf("%s%s\033[0m\n", colansi[d->colour], names[d->name]);
+ else
+ printf("%s\n", names[d->name]);
+ }
+ return 0;
+}
+
+/* Parse a --month spec ("YYYY-MM", or "N" for month N of the current year, or
+ * NULL for the current month) and print it. Returns an exit code. */
+static int run_month(const char *spec) {
+ struct tm tm;
+ time_t t = time(NULL);
+ int y, mon;
+ localtime_r(&t, &tm);
+ y = tm.tm_year + 1900;
+ mon = tm.tm_mon + 1;
+ if (spec) {
+ int ok = strchr(spec, '-') ? sscanf(spec, "%d-%d", &y, &mon) == 2
+ : sscanf(spec, "%d", &mon) == 1;
+ if (!ok) {
+ fprintf(stderr, "clectio: bad month %s (want YYYY-MM or 1-12)\n", spec);
+ return 2;
+ }
+ }
+ if (mon < 1 || mon > 12) {
+ fprintf(stderr, "clectio: bad month %s (want YYYY-MM or 1-12)\n", spec ? spec : "");
+ return 2;
+ }
+ return print_month(y, mon);
+}
+
static void print_day(long off, const char *datestr, int gospel, int wrap) {
const Day *d = &days[cal[off]];
unsigned ri;
@@ -137,7 +195,7 @@ int main(int argc, char **argv) {
int y, m, dd, i;
int gospel = GOSPEL_ONLY; /* compiled default, overridable per run */
int istty = isatty(1);
- int wrap;
+ int wrap, monthmode = 0;
const char *datearg = NULL;
usecolor = COLOR && istty;
@@ -146,8 +204,10 @@ int main(int argc, char **argv) {
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
fprintf(stderr,
"usage: clectio [-a|--all | -g|--gospel] [YYYY-MM-DD]\n"
+ " clectio --month [YYYY-MM | N]\n"
" -a, --all print all readings\n"
" -g, --gospel print the Gospel only\n"
+ " --month list a whole month (default: current month)\n"
" (default: today, %s)\n"
" compiled: %s, %s, wrap %s, range %d-%d\n",
READMODE, FORMNAME, SIGLANAME, WRAPNAME, EPOCH_Y, EPOCH_Y + (NDAYS / 366));
@@ -156,6 +216,8 @@ int main(int argc, char **argv) {
gospel = 0;
} else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--gospel")) {
gospel = 1;
+ } else if (!strcmp(argv[i], "--month")) {
+ monthmode = 1;
} else if (argv[i][0] == '-' && argv[i][1]) {
fprintf(stderr, "clectio: unknown option %s (try -h)\n", argv[i]);
return 2;
@@ -167,6 +229,9 @@ int main(int argc, char **argv) {
}
}
+ if (monthmode)
+ return run_month(datearg); /* month overview: no readings, no text loaded */
+
if (datearg) {
if (sscanf(datearg, "%d-%d-%d", &y, &m, &dd) != 3) {
fprintf(stderr, "clectio: bad date %s (want YYYY-MM-DD)\n", datearg);