logo

utils-std

Collection of commonly available Unix tools
commit: eae74fb71a2a4f653b5389f3f75aef3a2b9d8628
parent 591dd4ebc96103e6e9b1d62b66be54ca83062076
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Wed,  1 Nov 2023 05:37:28 +0100

cmd/date: Add support for `-f now_format now`

Diffstat:

M.gitignore4++--
MMakefile10+++++-----
Mcmd/date.1.in44+++++++++++++++++++++++++++++++++++++-------
Mcmd/date.c55+++++++++++++++++++++++++++++++++++++++++++++++--------
Mconfigure5++++-
Mlib/iso_parse.mdoc2+-
Mtest-cmd/date17+++++++++++++++--
7 files changed, 111 insertions(+), 26 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -8,11 +8,11 @@ !/cmd/*.ha !/cmd/*.1 !/cmd/*.1.in -/cmd/date.1 -/cmd/touch.1 *.t.err *.o +/build/ + # Binary /test-lib/strtodur diff --git a/Makefile b/Makefile @@ -27,7 +27,7 @@ lint: $(MAN1SO) .PHONY: clean clean: - rm -fr $(EXE) test-lib/strtodur + rm -fr $(EXE) $(MAN1SO) test-lib/strtodur rm -fr ${EXE:=.c.gcov} ${EXE:=.gcda} ${EXE:=.gcno} install: all @@ -48,15 +48,15 @@ cmd/date: cmd/date.c lib/iso_parse.c Makefile rm -f ${<:=.gcov} ${@:=.gcda} ${@:=.gcno} $(CC) -std=c99 $(CFLAGS) -o $@ cmd/date.c lib/iso_parse.c $(LDFLAGS) -cmd/date.1: cmd/date.1.in lib/iso_parse.mdoc Makefile - $(M4) cmd/date.1.in > cmd/date.1 +build/cmd/date.1: cmd/date.1.in lib/iso_parse.mdoc Makefile + $(M4) cmd/date.1.in > $@ cmd/touch: cmd/touch.c lib/iso_parse.c Makefile rm -f ${<:=.gcov} ${@:=.gcda} ${@:=.gcno} $(CC) -std=c99 $(CFLAGS) -o $@ cmd/touch.c lib/iso_parse.c $(LDFLAGS) -cmd/touch.1: cmd/touch.1.in lib/iso_parse.mdoc Makefile - $(M4) cmd/touch.1.in > cmd/touch.1 +build/cmd/touch.1: cmd/touch.1.in lib/iso_parse.mdoc Makefile + $(M4) cmd/touch.1.in > $@ cmd/sleep: cmd/sleep.c lib/strtodur.c Makefile rm -f ${<:=.gcov} ${@:=.gcda} ${@:=.gcno} diff --git a/cmd/date.1.in b/cmd/date.1.in @@ -9,26 +9,46 @@ .Nd display date and time .Sh SYNOPSIS .Nm -.Op Fl u +.Op Fl uR .Op Fl d Ar datetime .Op Cm + Ns Ar format +.Nm +.Op Fl uR +.Fl f Ar now_format +.Ar now +.Op Cm + Ns Ar format .Sh DESCRIPTION When .Nm is invoked without arguments it displays the current datetime Otherwise, depending on the options specified, will print the datetime in a user-defined way. +.Sh OPTIONS .Bl -tag -width Ds .It Fl d Ar datetime +Use +.Ar datetime +instead of current datetime. include(lib/iso_parse.mdoc) +.It Fl f Ar now_format +Use +.Ar now_format +as the +.Xr strptime 3 +format string for +.Ar now , +which will be used instead of the current datetime. .It Fl u Use UTC (coordinated universal time) instead of the local time. -.El -.Pp -The plus operand -.Pq Sq + -specifies in which format the datetime should be displayed, the format string is specified in the +.It Fl R +Set the default value of +.Ar format +to match RFC5322 (Internet Message Format). +.It Cm + Ns Ar format +Set the displayed datetime in .Xr strftime 3 -manual page. +format. Otherwise defaults to +.Ql %c +.El .Sh ENVIRONMENT Look at the manual page of .Xr strftime 3 @@ -45,5 +65,15 @@ for the environment variables, typical ones are is mostly compliant with the .St -p1003.1-2008 specification. +.Pp +The +.Fl d +and +.Fl R +options are present for compatibility with other modern systems such as +NetBSD, BusyBox, and GNU coreutils. +The +.Fl f +option is inspired by NetBSD. .Sh AUTHORS .An Haelwenn (lanodan) Monnier Aq Mt contact@hacktivis.me diff --git a/cmd/date.c b/cmd/date.c @@ -3,6 +3,7 @@ // SPDX-License-Identifier: MPL-2.0 #define _POSIX_C_SOURCE 200809L +#define _XOPEN_SOURCE // strptime #include "../lib/iso_parse.h" /* iso_parse */ @@ -10,13 +11,14 @@ #include <locale.h> /* setlocale() */ #include <stdio.h> /* BUFSIZ, perror(), puts() */ #include <stdlib.h> /* exit(), strtol() */ -#include <time.h> /* time, localtime, tm, strftime */ +#include <time.h> /* time, localtime, tm, strftime, strptime */ #include <unistd.h> /* getopt(), optarg, optind */ void usage() { - fprintf(stderr, "date [-uR][-d datetime] [+format]\n"); + fprintf(stderr, "date [-uR] [-d datetime] [+format]\n"); + fprintf(stderr, "date [-uR] -f now_format now [+format]\n"); } int @@ -25,8 +27,10 @@ main(int argc, char *argv[]) char outstr[BUFSIZ]; struct tm *tm; time_t now; - char *format = "%c"; - int uflag = 0; + char *format = "%c"; + char *input_format = NULL; + int uflag = 0; + int dflag = 0; int c; //setlocale(LC_ALL, ""); @@ -38,19 +42,33 @@ main(int argc, char *argv[]) exit(EXIT_FAILURE); } - while((c = getopt(argc, argv, ":d:uR")) != -1) + while((c = getopt(argc, argv, ":d:f:uR")) != -1) { char *errstr = NULL; switch(c) { case 'd': /* Custom datetime */ - now = iso_parse(optarg, &errstr).tv_sec; + if(input_format != NULL) + { + fprintf(stderr, "date: Cannot both use '-d' and '-f'\n"); + exit(EXIT_FAILURE); + } + now = iso_parse(optarg, &errstr).tv_sec; + dflag = 1; if(errstr != NULL) { fprintf(stderr, "date: iso_parse(\"%s\", …): %s\n", optarg, errstr); exit(EXIT_FAILURE); } break; + case 'f': /* input datetime format */ + if(dflag == 1) + { + fprintf(stderr, "date: Cannot both use '-d' and '-f'\n"); + exit(EXIT_FAILURE); + } + input_format = optarg; + break; case 'u': /* UTC timezone */ uflag++; break; @@ -92,9 +110,30 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; - (void)argc; + if(argc > 0 && input_format != NULL) + { + char *res = strptime(argv[0], input_format, tm); - if(*argv && **argv == '+') format = *argv + 1; + if(res == NULL) + { + fprintf(stderr, + "date: strptime(\"%s\", \"%s\", …) as passed by '-f' option failed\n", + argv[0], + input_format); + exit(EXIT_FAILURE); + } + + argv++; + argc--; + } + + if(argc > 0 && *argv && **argv == '+') + { + format = *argv + 1; + + argv++; + argc--; + } errno = 0; if(strftime(outstr, sizeof(outstr), format, tm) == 0 && errno != 0) diff --git a/configure b/configure @@ -65,7 +65,10 @@ gen_targets() { echo printf 'MAN1SO = ' - printf '%s\n ' cmd/*.1.in | grep -v -f target_filter | sed 's;\.in$;;' | tr -d '\n' + printf '%s\n' cmd/*.1.in \ + | grep -v -f target_filter \ + | sed -e 's;\.in$;;' -e 's;^cmd/;build/cmd/;' \ + | tr '\n' ' ' echo printf 'MAN1 = ${MAN1SO} ' diff --git a/lib/iso_parse.mdoc b/lib/iso_parse.mdoc @@ -7,7 +7,7 @@ .\" .so lib/iso_parse.mdoc .\" Should be formatted either with a leading @ (at) symbol followed by -the Unix timestamp (number of seconds before and after 1970-01-01 00:00:00Z). +the Unix timestamp (number of seconds before and after 1970-01-01 00:00:00Z), for example .Ql @1698791420 corresponds to 2023-10-31 23:30:20 UTC diff --git a/test-cmd/date b/test-cmd/date @@ -2,6 +2,11 @@ # SPDX-FileCopyrightText: 2017-2022 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me> # SPDX-License-Identifier: MPL-2.0 +usage="\ +date [-uR] [-d datetime] [+format] +date [-uR] -f now_format now [+format] +" + atf_test_case noargs noargs_body() { atf_check -o not-empty ../cmd/date @@ -9,7 +14,7 @@ noargs_body() { atf_test_case badarg badarg_body() { - atf_check -s 'exit:1' -e "inline:date: Error: Unrecognised option: '-x'\ndate [-uR][-d datetime] [+format]\n" ../cmd/date -x + atf_check -s 'exit:1' -e "inline:date: Error: Unrecognised option: '-x'\n${usage}" ../cmd/date -x } atf_test_case epoch @@ -59,7 +64,7 @@ timestamp_body() { atf_check -o "inline:1970-01-01T00:01:09\n" ../cmd/date -u -d @69 '+%FT%T' atf_check -o "inline:1969-12-31T23:58:51\n" ../cmd/date -u -d @-69 '+%FT%T' - atf_check -s 'exit:1' -e "inline:date: Error: Missing operand for option: '-d'\ndate [-uR][-d datetime] [+format]\n" ../cmd/date -u -d + atf_check -s 'exit:1' -e "inline:date: Error: Missing operand for option: '-d'\n${usage}" ../cmd/date -u -d # 36893488147419103232 = 2^65 atf_check -s 'exit:1' -e not-empty ../cmd/date -u -d @36893488147419103232 @@ -74,6 +79,13 @@ isodate_body() { atf_check -o "inline:-69\n" ../cmd/date -u -d "1969-12-31T23:58:51,00Z" '+%s' } +atf_test_case now_format +now_format_body() { + # Note: POSIX doesn't specifies %s for strptime(3) + atf_check -o "inline:1155544496\n" ../cmd/date -u -f '%Y-%m-%dT%H:%M:%S' '2006-08-14T08:34:56' '+%s' +} + + atf_init_test_cases() { cd "$(atf_get_srcdir)" || exit 1 @@ -92,4 +104,5 @@ atf_init_test_cases() { atf_add_test_case timestamp atf_add_test_case isodate + atf_add_test_case now_format }