diff options
-rw-r--r-- | bin/.gitignore | 1 | ||||
-rw-r--r-- | bin/Makefile | 1 | ||||
-rw-r--r-- | bin/README | 3 | ||||
-rw-r--r-- | bin/bin.7 | 5 | ||||
-rw-r--r-- | bin/man1/when.1 | 76 | ||||
-rw-r--r-- | bin/when.y (renamed from bin/ddc.y) | 106 |
6 files changed, 152 insertions, 40 deletions
diff --git a/bin/.gitignore b/bin/.gitignore index b9083639..0a1e37aa 100644 --- a/bin/.gitignore +++ b/bin/.gitignore @@ -35,4 +35,5 @@ ttpre up wake wat +when xx diff --git a/bin/Makefile b/bin/Makefile index e03e5093..b246bf28 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -35,6 +35,7 @@ BINS += shotty BINS += ttpre BINS += up BINS += wake +BINS += when BINS += xx LINKS += atch diff --git a/bin/README b/bin/README index c178f342..dc5e9b0d 100644 --- a/bin/README +++ b/bin/README @@ -33,6 +33,7 @@ DESCRIPTION up(1) upload file wake(1) wake-on-LAN wat(1) watch files + when(1) date calculator xx(1) hexdump To build graphical tools, set one of: @@ -41,4 +42,4 @@ DESCRIPTION GFX=fb GFX=x11 -Causal Agency July 9, 2019 Causal Agency +Causal Agency July 24, 2019 Causal Agency diff --git a/bin/bin.7 b/bin/bin.7 index ac34b97c..1503e87f 100644 --- a/bin/bin.7 +++ b/bin/bin.7 @@ -1,4 +1,4 @@ -.Dd July 9, 2019 +.Dd July 24, 2019 .Dt BIN 7 .Os "Causal Agency" . @@ -94,6 +94,9 @@ wake-on-LAN .It Xr wat 1 watch files . +.It Xr when 1 +date calculator +. .It Xr xx 1 hexdump .El diff --git a/bin/man1/when.1 b/bin/man1/when.1 new file mode 100644 index 00000000..0b473573 --- /dev/null +++ b/bin/man1/when.1 @@ -0,0 +1,76 @@ +.Dd July 24, 2019 +.Dt WHEN 1 +.Os +. +.Sh NAME +.Nm when +.Nd date calculator +. +.Sh SYNOPSIS +.Nm +.Op Ar expr +. +.Sh DESCRIPTION +.Nm +is a date calculator. +If no +.Ar expr +is given, +expressions are read +from standard input. +. +.Pp +The grammar is as follows: +.Bl -tag -width Ds +.It Sy \&. +Today's date. +. +.It Ar month Ar date Op Ar year +A full date, +or a date in the current year. +.Ar month +must be at least three letters. +. +.It Ar day +A day of the week +in the current week. +.Ar day +must be at least three letters. +. +.It Sy < Ar date +The date one week before. +. +.It Sy > Ar date +The date one week after. +. +.It Ar date Sy + Ar interval +The date after some interval. +. +.It Ar date Sy - Ar interval +The date before some interval. +. +.It Ar date Sy - Ar date +The interval between two dates. +. +.It Ar num Sy d +A number of days. +. +.It Ar num Sy w +A number of weeks. +. +.It Ar num Sy m +A number of months. +. +.It Ar num Sy y +A number of years. +.El +. +.Sh EXAMPLES +.Bl -tag -width "Dec 25 - ." +.It Ic Dec 25 - \&. +How long until Christmas. +.It Ic >Fri +The date next Friday. +.It Ic \&. + 2w +Your last day at work. +.El diff --git a/bin/ddc.y b/bin/when.y index 35e1b398..e8531ad3 100644 --- a/bin/ddc.y +++ b/bin/when.y @@ -29,19 +29,34 @@ static int yylex(void); #define YYSTYPE struct tm +static const char *Days[7] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", +}; + +static const char *Months[12] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", +}; + +static const struct tm Week = { .tm_mday = 7 }; + static struct tm normalize(struct tm date) { - time_t time = mktime(&date); - struct tm *norm = localtime(&time); - if (!norm) err(EX_OSERR, "localtime"); + time_t time = timegm(&date); + struct tm *norm = gmtime(&time); + if (!norm) err(EX_OSERR, "gmtime"); return *norm; } static struct tm today(void) { time_t now = time(NULL); - struct tm *date = localtime(&now); - if (!date) err(EX_OSERR, "localtime"); - date->tm_hour = date->tm_min = date->tm_sec = 0; - return *date; + struct tm *local = localtime(&now); + if (!local) err(EX_OSERR, "localtime"); + struct tm date = { + .tm_year = local->tm_year, + .tm_mon = local->tm_mon, + .tm_mday = local->tm_mday, + }; + return normalize(date); } static struct tm monthDay(int month, int day) { @@ -52,11 +67,10 @@ static struct tm monthDay(int month, int day) { } static struct tm monthDayYear(int month, int day, int year) { - struct tm date = { - .tm_mon = month, - .tm_mday = day, - .tm_year = year - 1900, - }; + struct tm date = today(); + date.tm_mon = month; + date.tm_mday = day; + date.tm_year = year - 1900; return normalize(date); } @@ -89,26 +103,25 @@ static struct tm dateSub(struct tm date, struct tm scalar) { } static struct tm dateDiff(struct tm a, struct tm b) { - struct tm diff = { .tm_year = a.tm_year - b.tm_year }; + struct tm diff = { + .tm_year = a.tm_year - b.tm_year, + .tm_mon = a.tm_mon - b.tm_mon, + .tm_mday = a.tm_mday - b.tm_mday, + }; + if (a.tm_mon < b.tm_mon) { + diff.tm_year--; + diff.tm_mon += 12; + } if (a.tm_mday < b.tm_mday) { - diff.tm_mon = a.tm_mon - b.tm_mon - 1; + diff.tm_mon--; + diff.tm_mday = 0; while (dateAdd(b, diff).tm_mday != a.tm_mday) diff.tm_mday++; - } else { - diff.tm_mon = a.tm_mon - b.tm_mon; - diff.tm_mday = a.tm_mday - b.tm_mday; } + time_t atime = timegm(&a), btime = timegm(&b); + diff.tm_yday = (atime - btime) / 24 / 60 / 60; return diff; } -static const char *Days[7] = { - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", -}; - -static const char *Months[12] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", -}; - static void printDate(struct tm date) { printf( "%s %s %d %d\n", @@ -121,16 +134,19 @@ static void printScalar(struct tm scalar) { if (scalar.tm_year) printf("%dy ", scalar.tm_year); if (scalar.tm_mon) printf("%dm ", scalar.tm_mon); if (scalar.tm_mday % 7) { - printf("%dd\n", scalar.tm_mday); - } else { - printf("%dw\n", scalar.tm_mday / 7); + printf("%dd ", scalar.tm_mday); + } else if (scalar.tm_mday) { + printf("%dw ", scalar.tm_mday / 7); } + if (scalar.tm_yday && scalar.tm_mon) printf("(%dd) ", scalar.tm_yday); + printf("\n"); } %} %token Number Month Day %left '+' '-' +%right '<' '>' %% @@ -140,26 +156,31 @@ expr: ; date: - dateSpec + dateLit + | '(' date ')' { $$ = $2; } + | '<' date { $$ = dateSub($2, Week); } + | '>' date { $$ = dateAdd($2, Week); } | date '+' scalar { $$ = dateAdd($1, $3); } | date '-' scalar { $$ = dateSub($1, $3); } ; scalar: - scalarSpec + scalarLit + | '(' scalar ')' { $$ = $2; } | scalar '+' scalar { $$ = scalarAdd($1, $3); } | scalar '-' scalar { $$ = scalarSub($1, $3); } | date '-' date { $$ = dateDiff($1, $3); } ; -dateSpec: - '.' { $$ = today(); } +dateLit: + { $$ = today(); } + | '.' { $$ = today(); } | Month Number { $$ = monthDay($1.tm_mon, $2.tm_sec); } | Month Number Number { $$ = monthDayYear($1.tm_mon, $2.tm_sec, $3.tm_sec); } | Day { $$ = weekDay($1.tm_wday); } ; -scalarSpec: +scalarLit: Number 'd' { $$ = (struct tm) { .tm_mday = $1.tm_sec }; } | Number 'w' { $$ = (struct tm) { .tm_mday = 7 * $1.tm_sec }; } | Number 'm' { $$ = (struct tm) { .tm_mon = $1.tm_sec }; } @@ -202,11 +223,20 @@ static int yylex(void) { return *input++; } -int main(void) { - char *buf = NULL; +int main(int argc, char *argv[]) { + if (argc > 1) { + input = argv[1]; + return yyparse(); + } + + printDate(today()); + printf("\n"); + + char *line = NULL; size_t cap = 0; - while (0 < getline(&buf, &cap, stdin)) { - input = buf; + while (0 < getline(&line, &cap, stdin)) { + if (line[0] == '\n') continue; + input = line; yyparse(); printf("\n"); } |