/*
* Copyright (C) 2021, 2022 P. J. McDermott
*
* This file is part of @
*
* @ is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with @. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "config.h"
#include "datetime.h"
#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
#include
#endif
extern const char *PACKAGE_VERSION_GIT;
#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
static const struct option LONGOPTS_[] = {
{
.name = "list-formats",
.has_arg = 0,
.flag = NULL,
.val = 'F',
},
{
.name = "help",
.has_arg = 0,
.flag = NULL,
.val = 'h',
},
{
.name = "version",
.has_arg = 0,
.flag = NULL,
.val = 'V',
},
};
#endif
static struct tm EPOCH_ = {
.tm_sec = 0,
.tm_min = 0,
.tm_hour = 0,
.tm_mday = 1,
.tm_mon = 0,
.tm_year = 70,
.tm_wday = 4,
.tm_yday = 0,
.tm_isdst = -1,
};
static void
_print_usage(FILE *stream, const char *program_name)
{
fprintf(stream, "Usage: %s [date]time\n", program_name);
}
static void
_print_help(const char *program_name)
{
_print_usage(stdout, program_name);
puts("Options:");
#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
puts("\t-F, --list-formats List all supported date and time formats");
puts("\t-h, --help Show this help information");
puts("\t-V, --version Show version information");
#else
puts("\t-F List all supported date and time formats");
puts("\t-h Show this help information");
puts("\t-V Show version information");
#endif
}
static void
_list_formats(void)
{
time_t tim;
struct tm *tm;
char *out;
size_t buf_sz;
char *buf;
size_t i;
tim = time(NULL);
tm = localtime(&tim);
puts("Time formats:");
i = 0;
while (datetime_strftime_time(tm, &out, &buf_sz, &buf, &i) > 0) {
if (out[0] == '\0') {
continue;
}
printf(" * %s\n", out);
}
puts("Date formats:");
i = 0;
while (datetime_strftime_date(tm, &out, &buf_sz, &buf, &i) > 0) {
if (out[0] == '\0') {
continue;
}
printf(" * %s\n", out);
}
puts("Additional formats:");
i = 0;
while (datetime_strftime_misc(tm, &out, &buf_sz, &buf, &i) > 0) {
if (out[0] == '\0') {
continue;
}
printf(" * %s\n", out);
}
}
static void
_print_version(void)
{
printf("@ (atsign) %s%s\n", PACKAGE_VERSION, PACKAGE_VERSION_GIT);
puts("Copyright (C) 2021 P. J. McDermott");
puts("License GPLv3+: GNU GPL version 3 or later "
".");
puts("This is free software: you are free to change and redistribute "
"it.");
puts("There is NO WARRANTY, to the extent permitted by law.\n");
printf("Please report bugs to <%s>.\n", PACKAGE_BUGREPORT);
}
static char *
_concat_args(int argc, char * const argv[])
{
int buf_l;
int i;
char *buf;
int buf_i;
int j;
buf_l = 0;
for (i = 0; i < argc; ++i) {
buf_l += strlen(argv[i]) + 1;
}
buf = calloc(buf_l, sizeof(*buf));
if (buf == NULL) {
fprintf(stderr, "Failed to allocate buffer: %s\n",
strerror(errno));
return NULL;
}
buf_i = 0;
for (i = 0; i < argc; ++i) {
for (j = 0; argv[i][j] != '\0'; ++j) {
buf[buf_i++] = argv[i][j];
}
buf[buf_i++] = ' ';
}
buf[--buf_i] = '\0';
return buf;
}
int
main(int argc, char * const argv[])
{
bool dbg;
int opt;
char *buf;
time_t arg;
time_t now;
double dif;
dbg = false;
optind = 1;
opterr = 0;
#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
while ((opt = getopt_long(argc, argv, "FhVd", LONGOPTS_, NULL)) > 0) {
#else
while ((opt = getopt(argc, argv, "FhVd")) > 0) {
#endif
switch (opt) {
case 'F':
_list_formats();
return EXIT_SUCCESS;
case 'h':
_print_help(argv[0]);
return EXIT_SUCCESS;
case 'V':
_print_version();
return EXIT_SUCCESS;
case 'd':
dbg = true;
break;
default:
_print_usage(stderr, argv[0]);
#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
fprintf(stderr, "Try '%s --help' for more "
"information.\n", argv[0]);
#else
fprintf(stderr, "Try '%s -h' for more "
"information.\n", argv[0]);
#endif
return EXIT_FAILURE;
}
}
argc -= optind;
argv += optind;
buf = _concat_args(argc, argv);
if (buf == NULL) {
return EXIT_FAILURE;
}
if (datetime_parse(buf, &arg) < 0) {
free(buf);
return EXIT_FAILURE;
}
free(buf);
if (dbg == true) {
now = timegm(&EPOCH_);
dif = difftime(arg, now);
printf("%" PRId64 "\n", (int64_t) dif);
return EXIT_SUCCESS;
}
time(&now);
dif = difftime(arg, now);
if (dif >= 1000 * 24 * 60 * 60) {
fputs("Date too far in the future\n", stderr);
return EXIT_FAILURE;
}
setvbuf(stdout, NULL, _IONBF, 0);
while (dif > 0) {
printf("\r%03d:%02d:%02d:%02d",
(int) dif / 60 / 60 / 24,
(int) dif / 60 / 60 % 24,
(int) dif / 60 % 60,
(int) dif % 60);
sleep(1);
time(&now);
dif = difftime(arg, now);
}
printf("\r000:00:00:00\n");
return EXIT_SUCCESS;
}