diff --git a/utils/date.c b/utils/date.c index fb6a1cb0..b708b7d2 100644 --- a/utils/date.c +++ b/utils/date.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Jonas 'Sortie' Termansen. + * Copyright (c) 2013, 2021 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,24 +17,59 @@ * Print or set system date and time. */ -#include -#include -#include +#include +#include #include +#include +#include +#include #include -int main(void) +// Note: There's no way to discern whether the format string was too long for +// the output buffer or if the output was simply empty, so don't call this +// function with a format that could produce an empty string. E.g. use a prefix +// like '+' and skip it when using the string. +static char* astrftime(const char* format, const struct tm* tm) { + size_t format_size = strlen(format) + 1; + size_t buffer_size = format_size; + while ( true ) + { + char* buffer = calloc(buffer_size, 2); + if ( !buffer ) + return NULL; + buffer_size *= 2; + if ( strftime(buffer, buffer_size, format, tm) ) + return buffer; + free(buffer); + } +} + +int main(int argc, char* argv[]) +{ + const char* format = "+%a %b %e %H:%M:%S %Z %Y"; + + if ( 2 <= argc ) + { + if ( argv[1][0] != '+' ) + errx(1, "setting the system time is not implemented"); + format = argv[1]; + } + if ( 3 <= argc ) + errx(1, "unexpected extra operand: %s", argv[2]); + time_t current_time = time(NULL); struct tm tm; if ( !localtime_r(¤t_time, &tm) ) - error(1, errno, "time(%ji)", (intmax_t) current_time); - - const size_t BUFFER_SIZE = 256; - char buffer[BUFFER_SIZE]; - strftime(buffer, BUFFER_SIZE, "%a %b %d %H:%M:%S %Y", &tm); - printf("%s\n", buffer); + err(1, "localtime_r(%ji)", (intmax_t) current_time); + char* string = astrftime(format, &tm); + if ( !string ) + err(1, "malloc"); + if ( printf("%s\n", string + 1) == EOF ) + err(1, "stdout"); + if ( ferror(stdout) || fflush(stdout) == EOF ) + err(1, "stdout"); return 0; }