summaryrefslogtreecommitdiff
path: root/util/sbase/cal.c
diff options
context:
space:
mode:
authorLeah Rowe <leah@libreboot.org>2025-10-04 09:14:33 +0100
committerLeah Rowe <leah@libreboot.org>2025-10-04 09:20:12 +0100
commite9a910b33c7837b4b868e3abda18eb4810df7f02 (patch)
tree749e1830cb0607952df1a1afc0ae09ec1db54140 /util/sbase/cal.c
parent2cfaba181b3c68761871fa47b32725c934423c14 (diff)
config/git: import suckless sbase
i currently use the output of sha512sum in several places of xbmk, which is a bit unreliable in case output changes. other cases where i use util outputs in variables are probably reliable, because i'm using mostly posix utilities in those. to mitigate this, i now import suckless sbase, which has a reasonable sha512sum implementation. *every* binary it builds is being placed in build.list, because i'll probably start using more of them. for example, i may start modifying the "date" implementation, adding the GNU-specific options that i need as mentioned on init.sh i'm importing it in util/ because the sha512sum util is needed for verifying project sources, so if sbase itself is a "project source", that means we can into a chicken and egg bootstrapping problem. this is sbase at revision: 055cc1ae1b3a13c3d8f25af0a4a3316590efcd48 Signed-off-by: Leah Rowe <leah@libreboot.org>
Diffstat (limited to 'util/sbase/cal.c')
-rw-r--r--util/sbase/cal.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/util/sbase/cal.c b/util/sbase/cal.c
new file mode 100644
index 00000000..a8c91f19
--- /dev/null
+++ b/util/sbase/cal.c
@@ -0,0 +1,226 @@
+/* See LICENSE file for copyright and license details. */
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "util.h"
+
+enum { JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };
+enum caltype { JULIAN, GREGORIAN };
+enum { TRANS_YEAR = 1752, TRANS_MONTH = SEP, TRANS_DAY = 2 };
+
+static struct tm *ltime;
+
+static int
+isleap(size_t year, enum caltype cal)
+{
+ if (cal == GREGORIAN) {
+ if (year % 400 == 0)
+ return 1;
+ if (year % 100 == 0)
+ return 0;
+ return (year % 4 == 0);
+ }
+ else { /* cal == Julian */
+ return (year % 4 == 0);
+ }
+}
+
+static int
+monthlength(size_t year, int month, enum caltype cal)
+{
+ int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+ return (month == FEB && isleap(year, cal)) ? 29 : mdays[month];
+}
+
+/* From http://www.tondering.dk/claus/cal/chrweek.php#calcdow */
+static int
+dayofweek(size_t year, int month, int dom, enum caltype cal)
+{
+ size_t y;
+ int m, a;
+
+ a = (13 - month) / 12;
+ y = year - a;
+ m = month + 12 * a - 1;
+
+ if (cal == GREGORIAN)
+ return (dom + y + y / 4 - y / 100 + y / 400 + (31 * m) / 12) % 7;
+ else /* cal == Julian */
+ return (5 + dom + y + y / 4 + (31 * m) / 12) % 7;
+}
+
+static void
+printgrid(size_t year, int month, int fday, int line)
+{
+ enum caltype cal;
+ int offset, dom, d = 0, trans; /* are we in the transition from Julian to Gregorian? */
+ int today = 0;
+
+ cal = (year < TRANS_YEAR || (year == TRANS_YEAR && month <= TRANS_MONTH)) ? JULIAN : GREGORIAN;
+ trans = (year == TRANS_YEAR && month == TRANS_MONTH);
+ offset = dayofweek(year, month, 1, cal) - fday;
+
+ if (offset < 0)
+ offset += 7;
+ if (line == 1) {
+ for (; d < offset; ++d)
+ printf(" ");
+ dom = 1;
+ } else {
+ dom = 8 - offset + (line - 2) * 7;
+ if (trans && !(line == 2 && fday == 3))
+ dom += 11;
+ }
+ if (ltime && year == ltime->tm_year + 1900 && month == ltime->tm_mon)
+ today = ltime->tm_mday;
+ for (; d < 7 && dom <= monthlength(year, month, cal); ++d, ++dom) {
+ if (dom == today)
+ printf("\x1b[7m%2d\x1b[0m ", dom); /* highlight today's date */
+ else
+ printf("%2d ", dom);
+ if (trans && dom == TRANS_DAY)
+ dom += 11;
+ }
+ for (; d < 7; ++d)
+ printf(" ");
+}
+
+static void
+drawcal(size_t year, int month, size_t ncols, size_t nmons, int fday)
+{
+ char *smon[] = { "January", "February", "March", "April",
+ "May", "June", "July", "August",
+ "September", "October", "November", "December" };
+ char *days[] = { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", };
+ size_t m, n, col, cur_year, cur_month, dow;
+ int line, pad;
+ char month_year[sizeof("Su Mo Tu We Th Fr Sa")];
+
+ for (m = 0; m < nmons; ) {
+ n = m;
+ for (col = 0; m < nmons && col < ncols; ++col, ++m) {
+ cur_year = year + m / 12;
+ cur_month = month + m % 12;
+ if (cur_month > 11) {
+ cur_month -= 12;
+ cur_year += 1;
+ }
+ snprintf(month_year, sizeof(month_year), "%s %zu", smon[cur_month], cur_year);
+ pad = sizeof(month_year) - 1 - strlen(month_year);
+ printf("%*s%s%*s ", pad / 2 + pad % 2, "", month_year, pad / 2, "");
+ }
+ putchar('\n');
+ for (col = 0, m = n; m < nmons && col < ncols; ++col, ++m) {
+ for (dow = fday; dow < (fday + 7); ++dow)
+ printf("%s ", days[dow % 7]);
+ printf(" ");
+ }
+ putchar('\n');
+ for (line = 1; line <= 6; ++line) {
+ for (col = 0, m = n; m < nmons && col < ncols; ++col, ++m) {
+ cur_year = year + m / 12;
+ cur_month = month + m % 12;
+ if (cur_month > 11) {
+ cur_month -= 12;
+ cur_year += 1;
+ }
+ printgrid(cur_year, cur_month, fday, line);
+ printf(" ");
+ }
+ putchar('\n');
+ }
+ }
+}
+
+static void
+usage(void)
+{
+ eprintf("usage: %s [-1 | -3 | -y | -n num] "
+ "[-s | -m | -f num] [-c num] [[month] year]\n", argv0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ time_t now;
+ size_t year, ncols, nmons;
+ int fday, month;
+
+ now = time(NULL);
+ ltime = localtime(&now);
+ year = ltime->tm_year + 1900;
+ month = ltime->tm_mon + 1;
+ fday = 0;
+
+ if (!isatty(STDOUT_FILENO))
+ ltime = NULL; /* don't highlight today's date */
+
+ ncols = 3;
+ nmons = 0;
+
+ ARGBEGIN {
+ case '1':
+ nmons = 1;
+ break;
+ case '3':
+ nmons = 3;
+ if (--month == 0) {
+ month = 12;
+ year--;
+ }
+ break;
+ case 'c':
+ ncols = estrtonum(EARGF(usage()), 0, MIN(SIZE_MAX, LLONG_MAX));
+ break;
+ case 'f':
+ fday = estrtonum(EARGF(usage()), 0, 6);
+ break;
+ case 'm': /* Monday */
+ fday = 1;
+ break;
+ case 'n':
+ nmons = estrtonum(EARGF(usage()), 1, MIN(SIZE_MAX, LLONG_MAX));
+ break;
+ case 's': /* Sunday */
+ fday = 0;
+ break;
+ case 'y':
+ month = 1;
+ nmons = 12;
+ break;
+ default:
+ usage();
+ } ARGEND
+
+ if (nmons == 0) {
+ if (argc == 1) {
+ month = 1;
+ nmons = 12;
+ } else {
+ nmons = 1;
+ }
+ }
+
+ switch (argc) {
+ case 2:
+ month = estrtonum(argv[0], 1, 12);
+ argv++;
+ case 1: /* fallthrough */
+ year = estrtonum(argv[0], 0, INT_MAX);
+ break;
+ case 0:
+ break;
+ default:
+ usage();
+ }
+
+ drawcal(year, month - 1, ncols, nmons, fday);
+
+ return fshut(stdout, "<stdout>");
+}