summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2022-08-15 20:29:44 -0400
committerJune McEnroe <june@causal.agency>2022-08-15 20:29:44 -0400
commit0f4ebd49c8b6997ac46d89dd2c90cbc1011da54c (patch)
treec50cc90820ac810dfb2e2f58d543f7851be43a08
parentRemove tweets text file (diff)
downloadsrc-0f4ebd49c8b6997ac46d89dd2c90cbc1011da54c.tar.gz
src-0f4ebd49c8b6997ac46d89dd2c90cbc1011da54c.zip
Add named dates to when
-rw-r--r--bin/man1/when.17
-rw-r--r--bin/when.y48
2 files changed, 51 insertions, 4 deletions
diff --git a/bin/man1/when.1 b/bin/man1/when.1
index 0b473573..f955daf4 100644
--- a/bin/man1/when.1
+++ b/bin/man1/when.1
@@ -1,4 +1,4 @@
-.Dd July 24, 2019
+.Dd August 15, 2022
 .Dt WHEN 1
 .Os
 .
@@ -24,6 +24,11 @@ The grammar is as follows:
 .Bl -tag -width Ds
 .It Sy \&.
 Today's date.
+The empty expression is equivalent.
+.
+.It Ar name Op Sy = Ar date
+A named date.
+Names are alphanumeric including underscores.
 .
 .It Ar month Ar date Op Ar year
 A full date,
diff --git a/bin/when.y b/bin/when.y
index 64859da7..095493d7 100644
--- a/bin/when.y
+++ b/bin/when.y
@@ -1,4 +1,4 @@
-/* Copyright (C) 2019  June McEnroe <june@causal.agency>
+/* Copyright (C) 2019, 2022  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -130,6 +130,37 @@ static struct tm dateDiff(struct tm a, struct tm b) {
 	return diff;
 }
 
+static struct {
+	size_t cap, len;
+	struct tm *ptr;
+} dates;
+
+static struct tm getDate(const char *name) {
+	for (size_t i = 0; i < dates.len; ++i) {
+		if (!strcmp(dates.ptr[i].tm_zone, name)) return dates.ptr[i];
+	}
+	return (struct tm) {0};
+}
+
+static void setDate(const char *name, struct tm date) {
+	for (size_t i = 0; i < dates.len; ++i) {
+		if (strcmp(dates.ptr[i].tm_zone, name)) continue;
+		char *tm_zone = dates.ptr[i].tm_zone;
+		dates.ptr[i] = date;
+		dates.ptr[i].tm_zone = tm_zone;
+		return;
+	}
+	if (dates.len == dates.cap) {
+		dates.cap = (dates.cap ? dates.cap * 2 : 8);
+		dates.ptr = realloc(dates.ptr, sizeof(*dates.ptr) * dates.cap);
+		if (!dates.ptr) err(EX_OSERR, "realloc");
+	}
+	dates.ptr[dates.len] = date;
+	dates.ptr[dates.len].tm_zone = strdup(name);
+	if (!dates.ptr[dates.len].tm_zone) err(EX_OSERR, "strdup");
+	dates.len++;
+}
+
 static void printDate(struct tm date) {
 	printf(
 		"%s %s %d %d\n",
@@ -161,9 +192,9 @@ static void printScalar(struct tm scalar) {
 
 %}
 
-%token Number Month Day
+%token Name Number Month Day
 %left '+' '-'
-%right '<' '>'
+%right '=' '<' '>'
 
 %%
 
@@ -174,6 +205,8 @@ expr:
 
 date:
 	dateLit
+	| Name { $$ = getDate($1.tm_zone); free($1.tm_zone); }
+	| Name '=' date { setDate($1.tm_zone, $3); free($1.tm_zone); $$ = $3; }
 	| '(' date ')' { $$ = $2; }
 	| '<' date { $$ = dateSub($2, Week); }
 	| '>' date { $$ = dateAdd($2, Week); }
@@ -237,6 +270,15 @@ static int yylex(void) {
 		return Month;
 	}
 
+	size_t len;
+	for (len = 0; isalnum(input[len]) || input[len] == '_'; ++len);
+	if (len && (len != 1 || !strchr("dwmy", *input))) {
+		yylval.tm_zone = strndup(input, len);
+		if (!yylval.tm_zone) err(EX_OSERR, "strndup");
+		input += len;
+		return Name;
+	}
+
 	return *input++;
 }