diff options
Diffstat (limited to 'bin/when.y')
-rw-r--r-- | bin/when.y | 48 |
1 files changed, 45 insertions, 3 deletions
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++; } |