[PATCH] reimplemented timestamp as string subcommand
Nils Gladitz
gladitz at scivis.de
Thu Sep 27 11:08:28 EDT 2012
---
Source/CMakeLists.txt | 2 +
Source/cmStringCommand.cxx | 60 ++++++++++++
Source/cmStringCommand.h | 30 +++++-
Source/cmTimestamp.cxx | 96 ++++++++++++++++++++
Source/cmTimestamp.h | 32 +++++++
.../String-TIMESTAMP-AllSpecifiers.cmake | 11 +++
Tests/CMakeTests/String-TIMESTAMP-BadArg1.cmake | 1 +
Tests/CMakeTests/String-TIMESTAMP-BadArg2.cmake | 1 +
Tests/CMakeTests/String-TIMESTAMP-BadArg3.cmake | 1 +
.../String-TIMESTAMP-CustomFormatLocal.cmake | 2 +
.../String-TIMESTAMP-CustomFormatUTC.cmake | 2 +
.../String-TIMESTAMP-DefaulFormatUTC.cmake | 2 +
.../String-TIMESTAMP-DefaultFormatLocal.cmake | 2 +
.../String-TIMESTAMP-DefaultFormatUTC.cmake | 2 +
.../String-TIMESTAMP-IncompleteSpecifier.cmake | 2 +
.../String-TIMESTAMP-UnknownSpecifier.cmake | 2 +
Tests/CMakeTests/StringTest.cmake.in | 30 ++++++
17 files changed, 277 insertions(+), 1 deletion(-)
create mode 100644 Source/cmTimestamp.cxx
create mode 100644 Source/cmTimestamp.h
create mode 100644 Tests/CMakeTests/String-TIMESTAMP-AllSpecifiers.cmake
create mode 100644 Tests/CMakeTests/String-TIMESTAMP-BadArg1.cmake
create mode 100644 Tests/CMakeTests/String-TIMESTAMP-BadArg2.cmake
create mode 100644 Tests/CMakeTests/String-TIMESTAMP-BadArg3.cmake
create mode 100644 Tests/CMakeTests/String-TIMESTAMP-CustomFormatLocal.cmake
create mode 100644 Tests/CMakeTests/String-TIMESTAMP-CustomFormatUTC.cmake
create mode 100644 Tests/CMakeTests/String-TIMESTAMP-DefaulFormatUTC.cmake
create mode 100644 Tests/CMakeTests/String-TIMESTAMP-DefaultFormatLocal.cmake
create mode 100644 Tests/CMakeTests/String-TIMESTAMP-DefaultFormatUTC.cmake
create mode 100644 Tests/CMakeTests/String-TIMESTAMP-IncompleteSpecifier.cmake
create mode 100644 Tests/CMakeTests/String-TIMESTAMP-UnknownSpecifier.cmake
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 354f123..e2c5fea 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -257,6 +257,8 @@ set(SRCS
cmSystemTools.h
cmTarget.cxx
cmTarget.h
+ cmTimestamp.h
+ cmTimestamp.cxx
cmTest.cxx
cmTest.h
cmTestGenerator.cxx
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
index 0193dc9..c55da23 100644
--- a/Source/cmStringCommand.cxx
+++ b/Source/cmStringCommand.cxx
@@ -19,6 +19,8 @@
#include <ctype.h>
#include <time.h>
+#include <cmTimestamp.h>
+
//----------------------------------------------------------------------------
bool cmStringCommand
::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
@@ -87,6 +89,10 @@ bool cmStringCommand
{
return this->HandleFindCommand(args);
}
+ else if(subCommand == "TIMESTAMP")
+ {
+ return this->HandleTimestampCommand(args);
+ }
std::string e = "does not recognize sub-command "+subCommand;
this->SetError(e.c_str());
@@ -879,3 +885,57 @@ bool cmStringCommand
this->Makefile->AddDefinition(variableName.c_str(), &*result.begin());
return true;
}
+
+//----------------------------------------------------------------------------
+bool cmStringCommand
+::HandleTimestampCommand(std::vector<std::string> const& args)
+{
+ if(args.size() < 2)
+ {
+ this->SetError("sub-command TIMESTAMP requires at least one argument.");
+ return false;
+ }
+ else if(args.size() > 4)
+ {
+ this->SetError("sub-command TIMESTAMP takes at most three arguments.");
+ return false;
+ }
+
+ int argsIndex = 1;
+
+ const std::string &outputVariable = args[argsIndex++];
+
+ std::string formatString;
+ if(args.size() > argsIndex && args[argsIndex] != "UTC")
+ {
+ formatString = args[argsIndex++];
+ }
+
+ bool utcFlag = false;
+ if(args.size() > argsIndex)
+ {
+ if(args[argsIndex] == "UTC")
+ {
+ utcFlag = true;
+ }
+ else
+ {
+ std::string e = " TIMESTAMP sub-command does not recognize option " +
+ args[argsIndex] + ".";
+ this->SetError(e.c_str());
+ return false;
+ }
+ }
+
+ if(formatString.empty())
+ {
+ formatString = "%Y-%m-%dT%H:%M:%S";
+ if(utcFlag) formatString += "Z";
+ }
+
+ cmTimestamp timestamp;
+ std::string result = timestamp.CreateTimestamp(formatString, utcFlag);
+ this->Makefile->AddDefinition(outputVariable.c_str(), result.c_str());
+
+ return true;
+}
diff --git a/Source/cmStringCommand.h b/Source/cmStringCommand.h
index 43a0dbe..3902dc7 100644
--- a/Source/cmStringCommand.h
+++ b/Source/cmStringCommand.h
@@ -93,6 +93,7 @@ public:
" string(RANDOM [LENGTH <length>] [ALPHABET <alphabet>]\n"
" [RANDOM_SEED <seed>] <output variable>)\n"
" string(FIND <string> <substring> <output variable> [REVERSE])\n"
+ " string(TIMESTAMP <output variable> [<format string>] [UTC])\n"
"REGEX MATCH will match the regular expression once and store the "
"match in the output variable.\n"
"REGEX MATCHALL will match the regular expression as many times as "
@@ -141,7 +142,33 @@ public:
" () Saves a matched subexpression, which can be referenced \n"
" in the REGEX REPLACE operation. Additionally it is saved\n"
" by all regular expression-related commands, including \n"
- " e.g. if( MATCHES ), in the variables CMAKE_MATCH_(0..9).";
+ " e.g. if( MATCHES ), in the variables CMAKE_MATCH_(0..9).\n"
+ "TIMESTAMP will write a string representation of "
+ "the current date and/or time to <output variable>.\n"
+ "Should the command be unable to obtain a timestamp "
+ "<output variable> will be set to NOTFOUND.\n"
+ "The optional UTC flag requests the current date/time "
+ "representation to be in Coordinated Universal Time (UTC) "
+ "rather than local time.\n"
+ "The optional <format string> may contain the following "
+ "format specifiers: \n"
+ " %d The day of the current month (01-31).\n"
+ " %H The hour on a 24-hour clock (00-23).\n"
+ " %I The hour on a 12-hour clock (01-12).\n"
+ " %j The day of the current year (001-366).\n"
+ " %m The month of the current year (01-12).\n"
+ " %M The minute of the current hour (00-59).\n"
+ " %S The second of the current minute.\n"
+ " 60 represents a leap second. (00-60)\n"
+ " %U The week number of the current year (00-53).\n"
+ " %w The day of the current week. 0 is Sunday. (0-6)\n"
+ " %y The last two digits of the current year (00-99)\n"
+ " %Y The current year. \n"
+ "Unknown format specifiers will be ignored "
+ "and copied to the output as-is.\n"
+ "If no explicit <format string> is given it will default to:\n"
+ " %Y-%m-%dT%H:%M:%S for local time.\n"
+ " %Y-%m-%dT%H:%M:%SZ for UTC.";
}
cmTypeMacro(cmStringCommand, cmCommand);
@@ -164,6 +191,7 @@ protected:
bool HandleStripCommand(std::vector<std::string> const& args);
bool HandleRandomCommand(std::vector<std::string> const& args);
bool HandleFindCommand(std::vector<std::string> const& args);
+ bool HandleTimestampCommand(std::vector<std::string> const& args);
class RegexReplacement
{
diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx
new file mode 100644
index 0000000..a3d7861
--- /dev/null
+++ b/Source/cmTimestamp.cxx
@@ -0,0 +1,96 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmTimestamp.h"
+
+#include <cstring>
+
+//----------------------------------------------------------------------------
+std::string cmTimestamp::CreateTimestamp(
+ const std::string& formatString, bool utcFlag)
+{
+ std::string result;
+ const char* notFound = "NOTFOUND";
+
+ std::time_t currentTimeT = std::time(0);
+ if(currentTimeT == std::time_t(-1)) return notFound;
+
+ struct std::tm timeStruct;
+ std::memset(&timeStruct, 0, sizeof(std::tm));
+
+ if(utcFlag)
+ {
+ std::tm* ptr = std::gmtime(¤tTimeT);
+ if(ptr == 0) return notFound;
+
+ timeStruct = *ptr;
+ }
+ else
+ {
+ std::tm* ptr = std::localtime(¤tTimeT);
+ if(ptr == 0) return notFound;
+
+ timeStruct = *ptr;
+ }
+
+ for(std::string::size_type i = 0; i < formatString.size(); ++i)
+ {
+ char c1 = formatString[i];
+ char c2 = (i+1 < formatString.size()) ?
+ formatString[i+1] : 0;
+
+ if(c1 == '%' && c2 != 0)
+ {
+ result += AddTimestampComponent(c2, timeStruct);
+ ++i;
+ }
+ else
+ {
+ result += c1;
+ }
+ }
+
+ return result;
+}
+
+//----------------------------------------------------------------------------
+std::string cmTimestamp::AddTimestampComponent(char flag, std::tm& timeStruct)
+{
+ std::string formatString = "%";
+ formatString += flag;
+
+ switch(flag)
+ {
+ case 'd':
+ case 'H':
+ case 'I':
+ case 'j':
+ case 'm':
+ case 'M':
+ case 'S':
+ case 'U':
+ case 'w':
+ case 'y':
+ case 'Y':
+ break;
+ default:
+ {
+ return formatString;
+ }
+ }
+
+ char buffer[16];
+
+ std::size_t size = std::strftime(buffer, sizeof(buffer),
+ formatString.c_str(), &timeStruct);
+
+ return std::string(buffer, size);
+}
diff --git a/Source/cmTimestamp.h b/Source/cmTimestamp.h
new file mode 100644
index 0000000..ada6c83
--- /dev/null
+++ b/Source/cmTimestamp.h
@@ -0,0 +1,32 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmTimestamp_h
+#define cmTimestamp_h
+
+#include <string>
+#include <ctime>
+
+/** \class cmTimestamp
+ * \brief Utility class to generate sting representation of a timestamp
+ *
+ */
+class cmTimestamp
+{
+public:
+ std::string CreateTimestamp(const std::string& formatString, bool utcFlag);
+
+private:
+ std::string AddTimestampComponent(char flag, std::tm& timeStruct);
+};
+
+
+#endif
diff --git a/Tests/CMakeTests/String-TIMESTAMP-AllSpecifiers.cmake b/Tests/CMakeTests/String-TIMESTAMP-AllSpecifiers.cmake
new file mode 100644
index 0000000..2d0fcc8
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-AllSpecifiers.cmake
@@ -0,0 +1,11 @@
+string(TIMESTAMP output "%d;%H;%I;%j;%m;%M;%S;%U;%w;%y;%Y")
+message("~${output}~")
+
+list(LENGTH output output_length)
+
+set(expected_output_length 11)
+
+if(NOT output_length EQUAL ${expected_output_length})
+ message(FATAL_ERROR "expected ${expected_output_length} entries in output "
+ "with all specifiers; found ${output_length}")
+endif()
diff --git a/Tests/CMakeTests/String-TIMESTAMP-BadArg1.cmake b/Tests/CMakeTests/String-TIMESTAMP-BadArg1.cmake
new file mode 100644
index 0000000..8f2d9f8
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-BadArg1.cmake
@@ -0,0 +1 @@
+string(TIMESTAMP)
diff --git a/Tests/CMakeTests/String-TIMESTAMP-BadArg2.cmake b/Tests/CMakeTests/String-TIMESTAMP-BadArg2.cmake
new file mode 100644
index 0000000..c1e5126
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-BadArg2.cmake
@@ -0,0 +1 @@
+string(TIMESTAMP output_variable "%Y" UTF)
diff --git a/Tests/CMakeTests/String-TIMESTAMP-BadArg3.cmake b/Tests/CMakeTests/String-TIMESTAMP-BadArg3.cmake
new file mode 100644
index 0000000..3d577df
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-BadArg3.cmake
@@ -0,0 +1 @@
+string(TIMESTAMP output_variable "%Y" UTC UTC)
diff --git a/Tests/CMakeTests/String-TIMESTAMP-CustomFormatLocal.cmake b/Tests/CMakeTests/String-TIMESTAMP-CustomFormatLocal.cmake
new file mode 100644
index 0000000..eab2a45
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-CustomFormatLocal.cmake
@@ -0,0 +1,2 @@
+string(TIMESTAMP output "%S")
+message("~${output}~")
diff --git a/Tests/CMakeTests/String-TIMESTAMP-CustomFormatUTC.cmake b/Tests/CMakeTests/String-TIMESTAMP-CustomFormatUTC.cmake
new file mode 100644
index 0000000..eab2a45
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-CustomFormatUTC.cmake
@@ -0,0 +1,2 @@
+string(TIMESTAMP output "%S")
+message("~${output}~")
diff --git a/Tests/CMakeTests/String-TIMESTAMP-DefaulFormatUTC.cmake b/Tests/CMakeTests/String-TIMESTAMP-DefaulFormatUTC.cmake
new file mode 100644
index 0000000..dad6a8d
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-DefaulFormatUTC.cmake
@@ -0,0 +1,2 @@
+string(TIMESTAMP output UTC)
+message("~${output}~")
diff --git a/Tests/CMakeTests/String-TIMESTAMP-DefaultFormatLocal.cmake b/Tests/CMakeTests/String-TIMESTAMP-DefaultFormatLocal.cmake
new file mode 100644
index 0000000..d7c7dde
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-DefaultFormatLocal.cmake
@@ -0,0 +1,2 @@
+string(TIMESTAMP output)
+message("~${output}~")
diff --git a/Tests/CMakeTests/String-TIMESTAMP-DefaultFormatUTC.cmake b/Tests/CMakeTests/String-TIMESTAMP-DefaultFormatUTC.cmake
new file mode 100644
index 0000000..dad6a8d
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-DefaultFormatUTC.cmake
@@ -0,0 +1,2 @@
+string(TIMESTAMP output UTC)
+message("~${output}~")
diff --git a/Tests/CMakeTests/String-TIMESTAMP-IncompleteSpecifier.cmake b/Tests/CMakeTests/String-TIMESTAMP-IncompleteSpecifier.cmake
new file mode 100644
index 0000000..ffc5656
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-IncompleteSpecifier.cmake
@@ -0,0 +1,2 @@
+string(TIMESTAMP output "foobar%")
+message("~${output}~")
diff --git a/Tests/CMakeTests/String-TIMESTAMP-UnknownSpecifier.cmake b/Tests/CMakeTests/String-TIMESTAMP-UnknownSpecifier.cmake
new file mode 100644
index 0000000..0e145e5
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-UnknownSpecifier.cmake
@@ -0,0 +1,2 @@
+string(TIMESTAMP output "%g")
+message("~${output}~")
diff --git a/Tests/CMakeTests/StringTest.cmake.in b/Tests/CMakeTests/StringTest.cmake.in
index 49e7dc9..a9fe428 100644
--- a/Tests/CMakeTests/StringTest.cmake.in
+++ b/Tests/CMakeTests/StringTest.cmake.in
@@ -16,6 +16,26 @@ set(SHA384-Works-RESULT 0)
set(SHA384-Works-STDERR "1de9560b4e030e02051ea408200ffc55d70c97ac64ebf822461a5c786f495c36df43259b14483bc8d364f0106f4971ee")
set(SHA512-Works-RESULT 0)
set(SHA512-Works-STDERR "3982a1b4e651768bec70ab1fb97045cb7a659f4ba7203d501c52ab2e803071f9d5fd272022df15f27727fc67f8cd022e710e29010b2a9c0b467c111e2f6abf51")
+set(TIMESTAMP-BadArg1-RESULT 1)
+set(TIMESTAMP-BadArg1-STDERR "string sub-command TIMESTAMP requires at least one argument")
+set(TIMESTAMP-BadArg2-RESULT 1)
+set(TIMESTAMP-BadArg2-STDERR "string TIMESTAMP sub-command does not recognize option UTF")
+set(TIMESTAMP-BadArg3-RESULT 1)
+set(TIMESTAMP-BadArg3-STDERR "string sub-command TIMESTAMP takes at most three arguments")
+set(TIMESTAMP-DefaultFormatLocal-RESULT 0)
+set(TIMESTAMP-DefaultFormatLocal-STDERR "~[0-9]*-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-6][0-9]~")
+set(TIMESTAMP-DefaultFormatUTC-RESULT 0)
+set(TIMESTAMP-DefaultFormatUTC-STDERR "~[0-9]*-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-6][0-9]Z~")
+set(TIMESTAMP-CustomFormatLocal-RESULT 0)
+set(TIMESTAMP-CustomFormatLocal-STDERR "~([0-5][0-9])|60~")
+set(TIMESTAMP-CustomFormatUTC-RESULT 0)
+set(TIMESTAMP-CustomFormatUTC-STDERR "~([0-5][0-9])|60~")
+set(TIMESTAMP-UnknownSpecifier-RESULT 0)
+set(TIMESTAMP-UnknownSpecifier-STDERR "~%g~")
+set(TIMESTAMP-IncompleteSpecifier-RESULT 0)
+set(TIMESTAMP-IncompleteSpecifier-STDERR "~foobar%~")
+set(TIMESTAMP-AllSpecifiers-RESULT 0)
+set(TIMESTAMP-AllSpecifiers-STDERR "~[0-9]+(;[0-9]+)*~")
include("@CMAKE_CURRENT_SOURCE_DIR@/CheckCMakeTest.cmake")
check_cmake_test(String
@@ -28,6 +48,16 @@ check_cmake_test(String
SHA256-Works
SHA384-Works
SHA512-Works
+ TIMESTAMP-BadArg1
+ TIMESTAMP-BadArg2
+ TIMESTAMP-BadArg3
+ TIMESTAMP-DefaultFormatLocal
+ TIMESTAMP-DefaultFormatUTC
+ TIMESTAMP-CustomFormatLocal
+ TIMESTAMP-CustomFormatUTC
+ TIMESTAMP-UnknownSpecifier
+ TIMESTAMP-IncompleteSpecifier
+ TIMESTAMP-AllSpecifiers
)
# Execute each test listed in StringTestScript.cmake:
--
1.7.9.5
--------------060707070007080303040206--
More information about the cmake-developers
mailing list