diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-07-29 08:49:03 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-07-29 08:49:03 +0200 |
| commit | 4290b7b2cbeeba4f08446f15c04b64d70dedbabc (patch) | |
| tree | d6e6067a5c179035e17eba33868e948156978599 /clectio.c | |
| parent | 302897c5e8d61db9107505ba929f9abfc197896d (diff) | |
| download | clectio-4290b7b2cbeeba4f08446f15c04b64d70dedbabc.tar.gz clectio-4290b7b2cbeeba4f08446f15c04b64d70dedbabc.zip | |
feat: -a/-g runtime reading toggle and WRAP config option
- -a/--all and -g/--gospel override the compiled GOSPEL_ONLY default per run;
the reading text for both is always embedded, so this is free. Flags may
appear in any position alongside the optional date.
- WRAP config.h option wraps reading text at N columns; 0 (default) fits the
terminal via TIOCGWINSZ and leaves piped output one line per verse. Greedy,
space-breaking, UTF-8 aware (continuation bytes do not count as columns).
- Rework arg parsing into a small flag loop; expand -h usage.
No table/data change; OF and EF both build clean under -Wall -Wextra. Binary
grows ~4 KB (666 KB OF). Stays compile-time-first, suckless-style: the only
run-time options are the reading-set toggle and -h.
Claude-Session: https://claude.ai/code/session_01S1CD1u3tgSS4xNu6WHfp5a
Diffstat (limited to 'clectio.c')
| -rw-r--r-- | clectio.c | 100 |
1 files changed, 85 insertions, 15 deletions
@@ -9,6 +9,7 @@ * licence (see README): the default is the public-domain Latin Vulgate. */ #define _POSIX_C_SOURCE 200809L /* localtime_r, isatty under -std=c99 */ +#define _DEFAULT_SOURCE /* struct winsize / TIOCGWINSZ under -std=c99 */ #include "config.h" #include LITURGY /* gen/liturgy_<form>.h: names,parts,cites_*,vpool,readings,rpool,days,cal,EPOCH,NDAYS */ @@ -20,6 +21,7 @@ #include <string.h> #include <time.h> #include <unistd.h> +#include <sys/ioctl.h> static char *textbuf; /* inflated verse text */ static const char **verse; /* verse[i] -> the text of the i-th key, nul-terminated */ @@ -66,7 +68,46 @@ static const char *citation(int r) { #endif } -static void print_day(long off, const char *datestr) { +/* Column width of the terminal on stdout, or 72 if it cannot be determined. */ +static int termwidth(void) { + struct winsize ws; + if (ioctl(1, TIOCGWINSZ, &ws) == 0 && ws.ws_col > 0) + return ws.ws_col; + return 72; +} + +/* Print s wrapped at w columns, breaking on spaces (greedy). w <= 0 prints s + * unwrapped. UTF-8 aware: continuation bytes (0x80-0xBF) do not count as a + * column, so multibyte letters measure as one. */ +static void putwrapped(const char *s, int w) { + if (w <= 0) { + printf("%s\n", s); + return; + } + while (*s) { + const char *p = s, *brk = NULL; + int col = 0; + while (*p && col < w) { + if (*p == ' ') + brk = p; + if ((*p & 0xC0) != 0x80) + col++; + p++; + } + if (!*p) { /* the rest fits on one line */ + printf("%s\n", s); + return; + } + if (!brk) /* a single word longer than w: hard-break at the column */ + brk = p; + fwrite(s, 1, (size_t)(brk - s), stdout); + putchar('\n'); + for (s = brk; *s == ' '; s++) /* skip the space(s) we broke on */ + ; + } +} + +static void print_day(long off, const char *datestr, int gospel, int wrap) { const Day *d = &days[cal[off]]; unsigned ri; int n; @@ -81,13 +122,11 @@ static void print_day(long off, const char *datestr) { for (ri = 0; ri < d->rlen; ri++) { const Reading *r = &readings[rpool[d->roff + ri]]; unsigned v; -#if GOSPEL_ONLY - if (strcmp(parts[r->part], "Gospel") != 0) + if (gospel && strcmp(parts[r->part], "Gospel") != 0) continue; -#endif 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]]); + putwrapped(verse[vpool[r->voff + v]], wrap); } } @@ -95,18 +134,42 @@ int main(int argc, char **argv) { struct tm tm; long off; char datestr[16]; - int y, m, dd; + int y, m, dd, i; + int gospel = GOSPEL_ONLY; /* compiled default, overridable per run */ + int istty = isatty(1); + int wrap; + const char *datearg = NULL; - usecolor = COLOR && isatty(1); + usecolor = COLOR && istty; - if (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) { - fprintf(stderr, "usage: clectio [YYYY-MM-DD] (default: today)\n" - " compiled: %s, %s, %s, %d-%d\n", FORMNAME, SIGLANAME, READMODE, EPOCH_Y, EPOCH_Y + (NDAYS / 366)); - return 0; + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { + fprintf(stderr, + "usage: clectio [-a|--all | -g|--gospel] [YYYY-MM-DD]\n" + " -a, --all print all readings\n" + " -g, --gospel print the Gospel only\n" + " (default: today, %s)\n" + " compiled: %s, %s, wrap %s, range %d-%d\n", + READMODE, FORMNAME, SIGLANAME, WRAPNAME, EPOCH_Y, EPOCH_Y + (NDAYS / 366)); + return 0; + } else if (!strcmp(argv[i], "-a") || !strcmp(argv[i], "--all")) { + gospel = 0; + } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--gospel")) { + gospel = 1; + } else if (argv[i][0] == '-' && argv[i][1]) { + fprintf(stderr, "clectio: unknown option %s (try -h)\n", argv[i]); + return 2; + } else if (!datearg) { + datearg = argv[i]; + } else { + fprintf(stderr, "clectio: unexpected argument %s (try -h)\n", argv[i]); + return 2; + } } - 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]); + + if (datearg) { + if (sscanf(datearg, "%d-%d-%d", &y, &m, &dd) != 3) { + fprintf(stderr, "clectio: bad date %s (want YYYY-MM-DD)\n", datearg); return 2; } snprintf(datestr, sizeof datestr, "%04d-%02d-%02d", y, m, dd); @@ -127,7 +190,14 @@ int main(int argc, char **argv) { return 1; } + /* WRAP>0: always wrap to that width. WRAP==0: fit the terminal, but leave + * piped output as one line per verse (0 -> putwrapped prints unwrapped). */ + if (WRAP > 0) + wrap = WRAP; + else + wrap = istty ? termwidth() : 0; + load_text(); - print_day(off, datestr); + print_day(off, datestr, gospel, wrap); return 0; } |
