From 1f19e74d21b4b511090794458ae4cd0094ed98f2 Mon Sep 17 00:00:00 2001 From: "Kyle J. McKay" Date: Mon, 25 Dec 2017 08:00:41 -0800 Subject: [PATCH] strftime.c: implement %N format specifier with extra semantics The '%N' format specifier is implemented to insert the 9-digit nanoseconds value (which will always be all zeros unless the current time is used). Since the gettimeofday() function only provides microseconds, the last three digits of the %N value will always be zero anyway. To assist with generating unique names, the "extra semantics" are that whenever %N is used together with current time then a 1 ms sleep will be performed before and after the call to the gettimeofday() function. This provides a guarantee to the caller (excluding the possibility of any clock resets) that combining the pid with the timestamp will produce a unique value that will not be generated by any other process on the system either before or after the call. Signed-off-by: Kyle J. McKay --- src/strftime.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 11 deletions(-) diff --git a/src/strftime.c b/src/strftime.c index c639a65..08f053a 100644 --- a/src/strftime.c +++ b/src/strftime.c @@ -1,7 +1,7 @@ /* strftime.c -- provide strftime functionality on the command line -Copyright (C) 2016 Kyle J. McKay. All rights reserved. +Copyright (C) 2016,2017 Kyle J. McKay. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -20,8 +20,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #define VERSION \ -"strftime version 1.1.0\n" \ -"Copyright (C) 2016 Kyle J. McKay \n" \ +"strftime version 1.2.0\n" \ +"Copyright (C) 2016,2017 Kyle J. McKay \n" \ "License GPLv2+: GNU GPL version 2 or later.\n" \ "\n" \ "This is free software: you are free to change and redistribute it.\n" \ @@ -41,14 +41,18 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. "If is NOT omitted then a strftime(3) '%Z' value will format as either\n" \ "\"unknown\" or \"UTC\" (for a zero offset). Note that except for the time zone\n" \ "name, `date` and `strftime '%a %b %e %T %Z %Y' $(date +'%s %z')` should match.\n" \ -"If --locale is NOT used the default format strips leading spaces from %e value.\n" +"If --locale is NOT used the default format strips leading spaces from %e value.\n" \ +"The %N format specifier is also supported for a 9-digit nanoseconds but the\n" \ +"last three digits will always be zero in this implementation and only the first\n" \ +"occurrence of %N will be replaced. Additionally, if the current time is used\n" \ +"along with %N then a 1 ms sleep will occur before and after gettimeofday().\n" -#define _XOPEN_SOURCE #include #include #include #include #include +#include #define DEFAULT_FORMAT "%a, %e %b %Y %T %z" #define MAXLENGTH 4096 @@ -60,13 +64,16 @@ int main(int argc, char *argv[]) { int arg = 1; char *bp = buff; - time_t t = time(NULL); - const char *fmt = DEFAULT_FORMAT; + struct timeval tv; + char *fmt = DEFAULT_FORMAT; int defaultformat = 1; int dosetlocale = 0; + int needtime = 1; struct tm localvals; long adjust = 0; + size_t fmtlen, i, firstN; + tv.tv_usec = 0; while (arg < argc && *argv[arg] == '-') { if (!strcmp(argv[arg], "--help") || !strcmp(argv[arg], "-h")) { printf("%s", USAGE); @@ -125,7 +132,8 @@ int main(int argc, char *argv[]) argv[arg+1]); return 2; } - t = (time_t)l; + tv.tv_sec = (time_t)l; + needtime = 0; } if (argc - arg >= 3) { const char *o = argv[arg+2]; @@ -172,12 +180,55 @@ int main(int argc, char *argv[]) setlocale(LC_ALL, ""); } tzset(); - t += (time_t)adjust; - localvals = *localtime(&t); - if (!strftime(buff, sizeof(buff), fmt, &localvals)) { + fmtlen = strlen(fmt); + firstN = 0; + for (i=0; i