diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/datetime.c | 130 | ||||
-rw-r--r-- | src/datetime.h | 6 | ||||
-rw-r--r-- | src/formats.h | 2 | ||||
-rw-r--r-- | src/i18n.h | 11 | ||||
-rw-r--r-- | src/local.mk | 3 | ||||
-rw-r--r-- | src/main.c | 84 |
6 files changed, 131 insertions, 105 deletions
diff --git a/src/datetime.c b/src/datetime.c index f7cdb89..72f0219 100644 --- a/src/datetime.c +++ b/src/datetime.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 P. J. McDermott + * Copyright (C) 2021, 2022 P. J. McDermott * * This file is part of @ * @@ -18,6 +18,9 @@ */ #define _XOPEN_SOURCE +/* glibc requires these for timegm(): */ +#define _DEFAULT_SOURCE +#define _BSD_SOURCE #include <ctype.h> #include <errno.h> @@ -29,18 +32,7 @@ #include <time.h> #include "datetime.h" #include "formats.h" - -static struct tm DATETIME_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, -}; +#include "i18n.h" static void _datetime_buf_cpy_p(char *dst, const char *src) @@ -83,7 +75,13 @@ _datetime_reset_tm(struct tm *tm) static void _datetime_normalize(struct tm *now_tm, struct tm *arg_tm, time_t *arg_sec) { - int wday; + int days_in_mon[12] = {31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31}; + + if (now_tm->tm_year % 4 == 0 && (now_tm->tm_year % 100 != 0 || + now_tm->tm_year % 400 == 0)) { + days_in_mon[1] = 29; + } if (arg_tm->tm_sec == INT_MIN) { arg_tm->tm_sec = 0; @@ -95,36 +93,44 @@ _datetime_normalize(struct tm *now_tm, struct tm *arg_tm, time_t *arg_sec) arg_tm->tm_mday = now_tm->tm_mday; arg_tm->tm_wday = now_tm->tm_wday; *arg_sec = mktime(arg_tm); - if (*arg_sec <= mktime(now_tm)) { + if (difftime(*arg_sec, mktime(now_tm)) <= 0) { /* Specified time already happened today; use tomorrow. - * Adding the number of seconds in a day is a shortcut - * that ignores leap seconds. One better method would - * be to increment tm_mday % days in tm_mon, etc. */ - *arg_sec += 60 * 60 * 24; - now_tm = localtime(arg_sec); - arg_tm->tm_year = now_tm->tm_year; - arg_tm->tm_mon = now_tm->tm_mon; - arg_tm->tm_mday = now_tm->tm_mday; + */ + ++arg_tm->tm_mday; + arg_tm->tm_wday = (arg_tm->tm_wday + 1) % 7; + if (arg_tm->tm_mday > days_in_mon[arg_tm->tm_mon]) { + arg_tm->tm_mday = 1; + ++arg_tm->tm_mon; + if (arg_tm->tm_mon >= 12) { + arg_tm->tm_mon = 0; + ++arg_tm->tm_year; + } + } *arg_sec = mktime(arg_tm); } } else if (arg_tm->tm_mday == INT_MIN) { - /* Only a weekday specified; try tomorrow or next week. Uses - * same shortcut as above. */ - wday = arg_tm->tm_wday; + /* Only a weekday specified; try tomorrow or next week. */ arg_tm->tm_year = now_tm->tm_year; arg_tm->tm_mon = now_tm->tm_mon; arg_tm->tm_mday = now_tm->tm_mday; - arg_tm->tm_wday = now_tm->tm_wday; - if (wday <= now_tm->tm_wday) { - wday += 7; + if (arg_tm->tm_wday <= now_tm->tm_wday) { + arg_tm->tm_mday += 7; + } + arg_tm->tm_mday += arg_tm->tm_wday - now_tm->tm_wday; + if (arg_tm->tm_mday > days_in_mon[arg_tm->tm_mon]) { + arg_tm->tm_mday -= days_in_mon[arg_tm->tm_mon]; + ++arg_tm->tm_mon; + if (arg_tm->tm_mon >= 12) { + arg_tm->tm_mon = 0; + ++arg_tm->tm_year; + } } *arg_sec = mktime(arg_tm); - *arg_sec += (60 * 60 * 24) * (wday - now_tm->tm_wday); } else if (arg_tm->tm_year == INT_MIN) { /* No year specified; try this year. */ arg_tm->tm_year = now_tm->tm_year; *arg_sec = mktime(arg_tm); - if (*arg_sec <= mktime(now_tm)) { + if (difftime(*arg_sec, mktime(now_tm)) <= 0) { /* Specified time already happened this year; use next * year. */ ++arg_tm->tm_year; @@ -136,7 +142,8 @@ _datetime_normalize(struct tm *now_tm, struct tm *arg_tm, time_t *arg_sec) } int -datetime_parse(struct tm *now_tm, const char *input, time_t *arg_sec) +datetime_parse(struct tm *now_tm, const char *input, + struct tm *arg_tm, time_t *arg_sec) { int date_fmt_len; int time_fmt_len; @@ -146,7 +153,6 @@ datetime_parse(struct tm *now_tm, const char *input, time_t *arg_sec) size_t d; size_t t; char *end; - struct tm arg_tm; time_t sec; bool got; @@ -159,20 +165,20 @@ datetime_parse(struct tm *now_tm, const char *input, time_t *arg_sec) } fmt_buf = calloc(fmt_len + 1, sizeof(*fmt_buf)); if (fmt_buf == NULL) { - fprintf(stderr, "Failed to allocate buffer: %s\n", + fprintf(stderr, _("Failed to allocate buffer: %s\n"), strerror(errno)); return -1; } sec = *arg_sec; /* GCC is dumb. */ got = false; - for (t = 0; t < sizeof(FORMATS_TIME) / sizeof(FORMATS_TIME[0]) ; ++t) { + for (t = 0; t < sizeof(FORMATS_TIME) / sizeof(FORMATS_TIME[0]); ++t) { _datetime_buf_cpy_p(fmt_buf, FORMATS_TIME[t]); - _datetime_reset_tm(&arg_tm); - end = strptime(input, fmt_buf, &arg_tm); + _datetime_reset_tm(arg_tm); + end = strptime(input, fmt_buf, arg_tm); if (end != NULL && *end == '\0') { - _datetime_normalize(now_tm, &arg_tm, arg_sec); - if (datetime_diff_epoch(*arg_sec) >= 0) { + _datetime_normalize(now_tm, arg_tm, arg_sec); + if (arg_tm->tm_year >= 0) { free(fmt_buf); return 0; } @@ -189,11 +195,11 @@ datetime_parse(struct tm *now_tm, const char *input, time_t *arg_sec) ++t) { _datetime_buf_cpy_p(fmt_buf + date_fmt_len, FORMATS_TIME[t]); - _datetime_reset_tm(&arg_tm); - end = strptime(input, fmt_buf, &arg_tm); + _datetime_reset_tm(arg_tm); + end = strptime(input, fmt_buf, arg_tm); if (end != NULL && *end == '\0') { - _datetime_normalize(now_tm, &arg_tm, arg_sec); - if (datetime_diff_epoch(*arg_sec) >= 0) { + _datetime_normalize(now_tm, arg_tm, arg_sec); + if (arg_tm->tm_year >= 0) { free(fmt_buf); return 0; } @@ -211,11 +217,11 @@ datetime_parse(struct tm *now_tm, const char *input, time_t *arg_sec) } _datetime_buf_cpy_p(fmt_buf + time_fmt_len, FORMATS_DATE[d]); - _datetime_reset_tm(&arg_tm); - end = strptime(input, fmt_buf, &arg_tm); + _datetime_reset_tm(arg_tm); + end = strptime(input, fmt_buf, arg_tm); if (end != NULL && *end == '\0') { - _datetime_normalize(now_tm, &arg_tm, arg_sec); - if (datetime_diff_epoch(*arg_sec) >= 0) { + _datetime_normalize(now_tm, arg_tm, arg_sec); + if (arg_tm->tm_year >= 0) { free(fmt_buf); return 0; } @@ -224,13 +230,13 @@ datetime_parse(struct tm *now_tm, const char *input, time_t *arg_sec) } } } - for (d = 0; d < sizeof(FORMATS_MISC) / sizeof(FORMATS_MISC[0]) ; ++d) { + for (d = 0; d < sizeof(FORMATS_MISC) / sizeof(FORMATS_MISC[0]); ++d) { _datetime_buf_cpy_p(fmt_buf, FORMATS_MISC[d]); - _datetime_reset_tm(&arg_tm); - end = strptime(input, fmt_buf, &arg_tm); + _datetime_reset_tm(arg_tm); + end = strptime(input, fmt_buf, arg_tm); if (end != NULL && *end == '\0') { - _datetime_normalize(now_tm, &arg_tm, arg_sec); - if (datetime_diff_epoch(*arg_sec) >= 0) { + _datetime_normalize(now_tm, arg_tm, arg_sec); + if (arg_tm->tm_year >= 0) { free(fmt_buf); return 0; } @@ -244,7 +250,7 @@ datetime_parse(struct tm *now_tm, const char *input, time_t *arg_sec) free(fmt_buf); return 0; } else { - fputs("Unknown date format\n", stderr); + fputs(_("Unknown date format\n"), stderr); free(fmt_buf); return -1; } @@ -289,13 +295,13 @@ _datetime_strftime(const char *fmts[], const struct tm *tm, char **out, *buf_sz = strlen(fmts[0]) + 1; *buf = calloc(*buf_sz, sizeof(**buf)); if (*buf == NULL) { - fprintf(stderr, "Failed to allocate buffer: %s\n", + fprintf(stderr, _("Failed to allocate buffer: %s\n"), strerror(errno)); return -1; } *out = calloc(*buf_sz, sizeof(**out)); if (*out == NULL) { - fprintf(stderr, "Failed to allocate buffer: %s\n", + fprintf(stderr, _("Failed to allocate buffer: %s\n"), strerror(errno)); return -1; } @@ -315,7 +321,7 @@ _datetime_strftime(const char *fmts[], const struct tm *tm, char **out, ++*buf_sz; *buf = realloc(*buf, *buf_sz * sizeof(**buf)); if (*buf == NULL) { - fprintf(stderr, "Failed to allocate buffer: %s\n", + fprintf(stderr, _("Failed to allocate buffer: %s\n"), strerror(errno)); return -1; } @@ -324,7 +330,7 @@ _datetime_strftime(const char *fmts[], const struct tm *tm, char **out, if (resized > 0) { *out = realloc(*out, *buf_sz * sizeof(**out)); if (*out == NULL) { - fprintf(stderr, "Failed to allocate buffer: %s\n", + fprintf(stderr, _("Failed to allocate buffer: %s\n"), strerror(errno)); return -1; } @@ -386,13 +392,3 @@ datetime_strftime_misc(const struct tm *tm, char **out, size_t *buf_sz, return _datetime_strftime(FORMATS_MISC, tm, out, buf_sz, buf, i); } - -double -datetime_diff_epoch(time_t t) -{ - time_t epoch; - - epoch = timegm(&DATETIME_EPOCH_); - - return difftime(t, epoch); -} diff --git a/src/datetime.h b/src/datetime.h index e225b52..1094cf8 100644 --- a/src/datetime.h +++ b/src/datetime.h @@ -23,7 +23,8 @@ #include <time.h> int -datetime_parse(struct tm *now_tm, const char *input, time_t *arg_sec); +datetime_parse(struct tm *now_tm, const char *input, + struct tm *arg_tm, time_t *arg_sec); int datetime_strftime_date(const struct tm *tm, char **out, size_t *out_sz, @@ -37,7 +38,4 @@ int datetime_strftime_misc(const struct tm *tm, char **out, size_t *out_sz, char **buf, size_t *i); -double -datetime_diff_epoch(time_t t); - #endif /* DATETIME_H_ */ diff --git a/src/formats.h b/src/formats.h index 262912e..c88f731 100644 --- a/src/formats.h +++ b/src/formats.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2022 P. J. McDermott + * Copyright (C) 2021, 2022 P. J. McDermott * * This file is part of @ * diff --git a/src/i18n.h b/src/i18n.h new file mode 100644 index 0000000..4d8ee76 --- /dev/null +++ b/src/i18n.h @@ -0,0 +1,11 @@ +#ifdef ENABLE_NLS + +#include <libintl.h> + +#define _(msgid) gettext(msgid) + +#else + +#define _(msgid) (msgid) + +#endif diff --git a/src/local.mk b/src/local.mk index 9992269..1012945 100644 --- a/src/local.mk +++ b/src/local.mk @@ -1,5 +1,6 @@ -@_SOURCES += \ +atsign_SOURCES += \ %reldir%/datetime.c \ %reldir%/datetime.h \ %reldir%/formats.h \ + %reldir%/i18n.h \ %reldir%/main.c @@ -17,16 +17,21 @@ * along with @. If not, see <http://www.gnu.org/licenses/>. */ +#include "config.h" + +#ifdef ENABLE_NLS +#include <locale.h> +#endif + #include <errno.h> -#include <inttypes.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> -#include "config.h" #include "datetime.h" +#include "i18n.h" #if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG #include <getopt.h> @@ -60,22 +65,23 @@ static const struct option LONGOPTS_[] = { static void _print_usage(FILE *stream, const char *program_name) { - fprintf(stream, "Usage: %s [date]time\n", 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"); + puts(_("Options:\n" + " -F, --list-formats List all supported date and time formats\n" + " -h, --help Show this help information\n" + " -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"); + puts(_("Options:\n" + " -F List all supported date and time formats\n" + " -h Show this help information\n" + " -V Show version information")); #endif } @@ -111,31 +117,31 @@ _list_formats(const struct tm *tm) char *buf; size_t i; - puts("Time formats:"); + 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); + printf(_(" * %s\n"), out); } - puts("Date formats:"); + 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); + printf(_(" * %s\n"), out); } - puts("Additional formats:"); + 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); + printf(_(" * %s\n"), out); } } @@ -143,13 +149,12 @@ static void _print_version(void) { printf("@ (atsign) %s%s\n", PACKAGE_VERSION, PACKAGE_VERSION_GIT); - puts("Copyright (C) 2021-2022 P. J. McDermott"); - puts("License GPLv3+: GNU GPL version 3 or later " - "<http://gnu.org/licenses/gpl.html>."); - 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); + puts(_("Copyright (C) 2021, 2022 P. J. McDermott\n" + "License GPLv3+: GNU GPL version 3 or later " + "<http://gnu.org/licenses/gpl.html>.\n" + "This is free software: you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n")); + printf(_("Please report bugs to <%s>.\n"), PACKAGE_BUGREPORT); } static char * @@ -168,7 +173,7 @@ _concat_args(int argc, char * const argv[]) buf = calloc(buf_l, sizeof(*buf)); if (buf == NULL) { - fprintf(stderr, "Failed to allocate buffer: %s\n", + fprintf(stderr, _("Failed to allocate buffer: %s\n"), strerror(errno)); return NULL; } @@ -196,9 +201,19 @@ main(int argc, char * const argv[]) char *buf; time_t now; struct tm *now_tm; + struct tm arg_tm; time_t arg; double dif; +#ifdef ENABLE_NLS + bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR); +#ifdef HAVE_BIND_TEXTDOMAIN_CODESET + bind_textdomain_codeset(PACKAGE, "UTF-8"); +#endif + textdomain(PACKAGE); + setlocale(LC_ALL, ""); +#endif + #if defined(ENABLE_TESTS) && ENABLE_TESTS dbg = false; #endif @@ -243,11 +258,11 @@ main(int argc, char * const argv[]) 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]); + fprintf(stderr, _("Try '%s --help' for more " + "information.\n"), argv[0]); #else - fprintf(stderr, "Try '%s -h' for more " - "information.\n", argv[0]); + fprintf(stderr, _("Try '%s -h' for more " + "information.\n"), argv[0]); #endif return EXIT_FAILURE; } @@ -265,7 +280,7 @@ main(int argc, char * const argv[]) return EXIT_FAILURE; } - if (datetime_parse(now_tm, buf, &arg) < 0) { + if (datetime_parse(now_tm, buf, &arg_tm, &arg) < 0) { free(buf); return EXIT_FAILURE; } @@ -273,8 +288,13 @@ main(int argc, char * const argv[]) #if defined(ENABLE_TESTS) && ENABLE_TESTS if (dbg == true) { - dif = datetime_diff_epoch(arg); - printf("%" PRId64 "\n", (int64_t) dif); + printf("%04d-%02d-%02d %02d:%02d:%02d\n", + arg_tm.tm_year + 1900, + arg_tm.tm_mon + 1, + arg_tm.tm_mday, + arg_tm.tm_hour, + arg_tm.tm_min, + arg_tm.tm_sec); return EXIT_SUCCESS; } #endif @@ -282,7 +302,7 @@ main(int argc, char * const argv[]) now = time(NULL); dif = difftime(arg, now); if (dif >= 1000 * 24 * 60 * 60) { - fputs("Date too far in the future\n", stderr); + fputs(_("Date too far in the future\n"), stderr); return EXIT_FAILURE; } |