summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/cmBootstrapCommands.cxx1
-rw-r--r--Source/cmFileCommand.cxx57
-rw-r--r--Source/cmFileCommand.h9
-rw-r--r--Source/cmLocalGenerator.cxx27
-rw-r--r--Source/cmLocalGenerator.h3
-rw-r--r--Source/cmMakefile.cxx75
-rw-r--r--Source/cmMakefile.h2
-rw-r--r--Source/cmPolicies.cxx17
-rw-r--r--Source/cmPolicies.h1
-rw-r--r--Source/cmQtAutomoc.cxx62
-rw-r--r--Source/cmStringCommand.cxx54
-rw-r--r--Source/cmStringCommand.h30
-rw-r--r--Source/cmTimestamp.cxx134
-rw-r--r--Source/cmTimestamp.h40
15 files changed, 428 insertions, 86 deletions
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 5c77993..20e68e9 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -2,5 +2,5 @@
set(CMake_VERSION_MAJOR 2)
set(CMake_VERSION_MINOR 8)
set(CMake_VERSION_PATCH 10)
-set(CMake_VERSION_TWEAK 20121206)
+set(CMake_VERSION_TWEAK 20121211)
#set(CMake_VERSION_RC 1)
diff --git a/Source/cmBootstrapCommands.cxx b/Source/cmBootstrapCommands.cxx
index 9097a74..e3a2ad4 100644
--- a/Source/cmBootstrapCommands.cxx
+++ b/Source/cmBootstrapCommands.cxx
@@ -89,6 +89,7 @@
#include "cmStringCommand.cxx"
#include "cmSubdirCommand.cxx"
#include "cmTargetLinkLibrariesCommand.cxx"
+#include "cmTimestamp.cxx"
#include "cmTryCompileCommand.cxx"
#include "cmTryRunCommand.cxx"
#include "cmUnsetCommand.cxx"
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index b877f3c..0cdbb82 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -17,6 +17,8 @@
#include "cmFileTimeComparison.h"
#include "cmCryptoHash.h"
+#include "cmTimestamp.h"
+
#if defined(CMAKE_BUILD_WITH_CMAKE)
#include "cm_curl.h"
#endif
@@ -161,6 +163,10 @@ bool cmFileCommand
{
return this->HandleCMakePathCommand(args, true);
}
+ else if ( subCommand == "TIMESTAMP" )
+ {
+ return this->HandleTimestampCommand(args);
+ }
std::string e = "does not recognize sub-command "+subCommand;
this->SetError(e.c_str());
@@ -3241,3 +3247,54 @@ cmFileCommand::HandleUploadCommand(std::vector<std::string> const& args)
return false;
#endif
}
+
+//----------------------------------------------------------------------------
+bool cmFileCommand::HandleTimestampCommand(
+ std::vector<std::string> const& args)
+{
+ if(args.size() < 3)
+ {
+ this->SetError("sub-command TIMESTAMP requires at least two arguments.");
+ return false;
+ }
+ else if(args.size() > 5)
+ {
+ this->SetError("sub-command TIMESTAMP takes at most four arguments.");
+ return false;
+ }
+
+ unsigned int argsIndex = 1;
+
+ const std::string& filename = args[argsIndex++];
+
+ 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;
+ }
+ }
+
+ cmTimestamp timestamp;
+ std::string result = timestamp.FileModificationTime(
+ filename.c_str(), formatString, utcFlag);
+ this->Makefile->AddDefinition(outputVariable.c_str(), result.c_str());
+
+ return true;
+}
diff --git a/Source/cmFileCommand.h b/Source/cmFileCommand.h
index a0862ec..5973fa7 100644
--- a/Source/cmFileCommand.h
+++ b/Source/cmFileCommand.h
@@ -87,6 +87,7 @@ public:
" [TLS_VERIFY on|off] [TLS_CAINFO file])\n"
" file(UPLOAD filename url [INACTIVITY_TIMEOUT timeout]\n"
" [TIMEOUT timeout] [STATUS status] [LOG log] [SHOW_PROGRESS])\n"
+ " file(TIMESTAMP filename variable [<format string>] [UTC])\n"
"WRITE will write a message into a file called 'filename'. It "
"overwrites the file if it already exists, and creates the file "
"if it does not exist. (If the file is a build input, use "
@@ -200,6 +201,12 @@ public:
"If SHOW_PROGRESS is specified, progress information will be printed "
"as status messages until the operation is complete."
"\n"
+ "TIMESTAMP will write a string representation of "
+ "the modification time of filename to variable.\n"
+ "Should the command be unable to obtain a timestamp "
+ "variable will be set to the empty string \"\".\n"
+ "See documentation of the string TIMESTAMP sub-command for more details."
+ "\n"
"The file() command also provides COPY and INSTALL signatures:\n"
" file(<COPY|INSTALL> files... DESTINATION <dir>\n"
" [FILE_PERMISSIONS permissions...]\n"
@@ -260,6 +267,8 @@ protected:
bool HandleInstallCommand(std::vector<std::string> const& args);
bool HandleDownloadCommand(std::vector<std::string> const& args);
bool HandleUploadCommand(std::vector<std::string> const& args);
+
+ bool HandleTimestampCommand(std::vector<std::string> const& args);
};
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 6d396b3..b41f060 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -1329,7 +1329,9 @@ std::string cmLocalGenerator::GetIncludeFlags(
void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
cmGeneratorTarget* target,
const char* lang,
- const char *config)
+ const char *config,
+ bool stripImplicitInclDirs
+ )
{
// Need to decide whether to automatically include the source and
// binary directories at the beginning of the include path.
@@ -1404,18 +1406,21 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
return;
}
- // Load implicit include directories for this language.
- std::string impDirVar = "CMAKE_";
- impDirVar += lang;
- impDirVar += "_IMPLICIT_INCLUDE_DIRECTORIES";
- if(const char* value = this->Makefile->GetDefinition(impDirVar.c_str()))
+ if (stripImplicitInclDirs)
{
- std::vector<std::string> impDirVec;
- cmSystemTools::ExpandListArgument(value, impDirVec);
- for(std::vector<std::string>::const_iterator i = impDirVec.begin();
- i != impDirVec.end(); ++i)
+ // Load implicit include directories for this language.
+ std::string impDirVar = "CMAKE_";
+ impDirVar += lang;
+ impDirVar += "_IMPLICIT_INCLUDE_DIRECTORIES";
+ if(const char* value = this->Makefile->GetDefinition(impDirVar.c_str()))
{
- emitted.insert(*i);
+ std::vector<std::string> impDirVec;
+ cmSystemTools::ExpandListArgument(value, impDirVec);
+ for(std::vector<std::string>::const_iterator i = impDirVec.begin();
+ i != impDirVec.end(); ++i)
+ {
+ emitted.insert(*i);
+ }
}
}
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index bd58218..63559d7 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -212,7 +212,8 @@ public:
/** Get the include flags for the current makefile and language. */
void GetIncludeDirectories(std::vector<std::string>& dirs,
cmGeneratorTarget* target,
- const char* lang = "C", const char *config = 0);
+ const char* lang = "C", const char *config = 0,
+ bool stripImplicitInclDirs = true);
/** Compute the language used to compile the given source file. */
const char* GetSourceFileLanguage(const cmSourceFile& source);
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 8498d72..d943c45 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -814,7 +814,7 @@ bool cmMakefile::NeedBackwardsCompatibility(unsigned int major,
void cmMakefile::FinalPass()
{
// do all the variable expansions here
- this->ExpandVariables();
+ this->ExpandVariablesCMP0019();
// give all the commands a chance to do something
// after the file has been parsed before generation
@@ -2122,21 +2122,33 @@ void cmMakefile::AddExtraDirectory(const char* dir)
this->AuxSourceDirectories.push_back(dir);
}
+static bool mightExpandVariablesCMP0019(const char* s)
+{
+ return s && *s && strstr(s,"${") && strchr(s,'}');
+}
-// expand CMAKE_BINARY_DIR and CMAKE_SOURCE_DIR in the
-// include and library directories.
-
-void cmMakefile::ExpandVariables()
+void cmMakefile::ExpandVariablesCMP0019()
{
- // Now expand variables in the include and link strings
+ // Drop this ancient compatibility behavior with a policy.
+ cmPolicies::PolicyStatus pol = this->GetPolicyStatus(cmPolicies::CMP0019);
+ if(pol != cmPolicies::OLD && pol != cmPolicies::WARN)
+ {
+ return;
+ }
+ cmOStringStream w;
- // May not be necessary anymore... But may need a policy for strict
- // backwards compatibility
const char *includeDirs = this->GetProperty("INCLUDE_DIRECTORIES");
- if (includeDirs)
+ if(mightExpandVariablesCMP0019(includeDirs))
{
std::string dirs = includeDirs;
this->ExpandVariablesInString(dirs, true, true);
+ if(pol == cmPolicies::WARN && dirs != includeDirs)
+ {
+ w << "Evaluated directory INCLUDE_DIRECTORIES\n"
+ << " " << includeDirs << "\n"
+ << "as\n"
+ << " " << dirs << "\n";
+ }
this->SetProperty("INCLUDE_DIRECTORIES", dirs.c_str());
}
@@ -2146,10 +2158,17 @@ void cmMakefile::ExpandVariables()
{
cmTarget &t = l->second;
includeDirs = t.GetProperty("INCLUDE_DIRECTORIES");
- if (includeDirs)
+ if(mightExpandVariablesCMP0019(includeDirs))
{
std::string dirs = includeDirs;
this->ExpandVariablesInString(dirs, true, true);
+ if(pol == cmPolicies::WARN && dirs != includeDirs)
+ {
+ w << "Evaluated target " << t.GetName() << " INCLUDE_DIRECTORIES\n"
+ << " " << includeDirs << "\n"
+ << "as\n"
+ << " " << dirs << "\n";
+ }
t.SetProperty("INCLUDE_DIRECTORIES", dirs.c_str());
}
}
@@ -2157,13 +2176,45 @@ void cmMakefile::ExpandVariables()
for(std::vector<std::string>::iterator d = this->LinkDirectories.begin();
d != this->LinkDirectories.end(); ++d)
{
- this->ExpandVariablesInString(*d, true, true);
+ if(mightExpandVariablesCMP0019(d->c_str()))
+ {
+ std::string orig = *d;
+ this->ExpandVariablesInString(*d, true, true);
+ if(pol == cmPolicies::WARN && *d != orig)
+ {
+ w << "Evaluated link directory\n"
+ << " " << orig << "\n"
+ << "as\n"
+ << " " << *d << "\n";
+ }
+ }
}
for(cmTarget::LinkLibraryVectorType::iterator l =
this->LinkLibraries.begin();
l != this->LinkLibraries.end(); ++l)
{
- this->ExpandVariablesInString(l->first, true, true);
+ if(mightExpandVariablesCMP0019(l->first.c_str()))
+ {
+ std::string orig = l->first;
+ this->ExpandVariablesInString(l->first, true, true);
+ if(pol == cmPolicies::WARN && l->first != orig)
+ {
+ w << "Evaluated link library\n"
+ << " " << orig << "\n"
+ << "as\n"
+ << " " << l->first << "\n";
+ }
+ }
+ }
+
+ if(!w.str().empty())
+ {
+ cmOStringStream m;
+ m << this->GetPolicies()->GetPolicyWarning(cmPolicies::CMP0019)
+ << "\n"
+ << "The following variable evaluations were encountered:\n"
+ << w.str();
+ this->IssueMessage(cmake::AUTHOR_WARNING, m.str());
}
}
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 70cfe54..eff05d0 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -693,7 +693,7 @@ public:
/**
* Expand variables in the makefiles ivars such as link directories etc
*/
- void ExpandVariables();
+ void ExpandVariablesCMP0019();
/**
* Replace variables and #cmakedefine lines in the given string.
diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx
index 6aef502..eb7d666 100644
--- a/Source/cmPolicies.cxx
+++ b/Source/cmPolicies.cxx
@@ -491,6 +491,23 @@ cmPolicies::cmPolicies()
"CMAKE_SHARED_LIBRARY_<Lang>_FLAGS whether it is modified or not and "
"honor the POSITION_INDEPENDENT_CODE target property.",
2,8,9,0, cmPolicies::WARN);
+
+ this->DefinePolicy(
+ CMP0019, "CMP0019",
+ "Do not re-expand variables in include and link information.",
+ "CMake 2.8.10 and lower re-evaluated values given to the "
+ "include_directories, link_directories, and link_libraries "
+ "commands to expand any leftover variable references at the "
+ "end of the configuration step. "
+ "This was for strict compatibility with VERY early CMake versions "
+ "because all variable references are now normally evaluated during "
+ "CMake language processing. "
+ "CMake 2.8.11 and higher prefer to skip the extra evaluation."
+ "\n"
+ "The OLD behavior for this policy is to re-evaluate the values "
+ "for strict compatibility. "
+ "The NEW behavior for this policy is to leave the values untouched.",
+ 2,8,11,0, cmPolicies::WARN);
}
cmPolicies::~cmPolicies()
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 6932565..d7d945c 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -68,6 +68,7 @@ public:
CMP0018, ///< Ignore language flags for shared libs, and adhere to
/// POSITION_INDEPENDENT_CODE property and *_COMPILE_OPTIONS_PI{E,C}
/// instead.
+ CMP0019, ///< No variable re-expansion in include and link info
/** \brief Always the last entry.
*
diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx
index 83688dd..bf034cf 100644
--- a/Source/cmQtAutomoc.cxx
+++ b/Source/cmQtAutomoc.cxx
@@ -212,36 +212,11 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target)
}
- const char* qtIncDir = 0;
- const char* qtCoreIncDir = 0;
-
- // check whether ${QT_INCLUDE_DIR} is part of the implicit include dirs,
- // see http://public.kitware.com/Bug/view.php?id=13667
- bool qtIncludeDirMayHaveBeenRemoved = false;
- if (makefile->IsSet("QT_INCLUDE_DIR"))
- {
- qtIncDir = makefile->GetDefinition("QT_INCLUDE_DIR");
- std::string s =
- makefile->GetSafeDefinition("CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES");
- std::vector<std::string> implIncDirs;
- cmSystemTools::ExpandListArgument(s, implIncDirs);
- if (std::find(implIncDirs.begin(), implIncDirs.end(),std::string(qtIncDir))
- != implIncDirs.end())
- {
- qtIncludeDirMayHaveBeenRemoved = true;
- if (makefile->IsSet("QT_QTCORE_INCLUDE_DIR"))
- {
- qtCoreIncDir = makefile->GetDefinition("QT_QTCORE_INCLUDE_DIR");
- }
- }
- }
-
- bool haveQtCoreIncDir = false;
- bool haveQtIncDir = false;
-
std::vector<std::string> includeDirs;
cmGeneratorTarget gtgt(target);
- localGen->GetIncludeDirectories(includeDirs, &gtgt, "CXX");
+ // Get the include dirs for this target, without stripping the implicit
+ // include dirs off, see http://public.kitware.com/Bug/view.php?id=13667
+ localGen->GetIncludeDirectories(includeDirs, &gtgt, "CXX", 0, false);
std::string _moc_incs = "";
const char* sep = "";
for(std::vector<std::string>::const_iterator incDirIt = includeDirs.begin();
@@ -251,37 +226,6 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target)
_moc_incs += sep;
sep = ";";
_moc_incs += *incDirIt;
-
- if (qtIncludeDirMayHaveBeenRemoved && qtCoreIncDir && qtIncDir) // #13667
- {
- if (*incDirIt == qtIncDir)
- {
- haveQtIncDir = true;
- qtIncludeDirMayHaveBeenRemoved = false; // it's here, i.e. not removed
- }
- if (*incDirIt == qtCoreIncDir)
- {
- haveQtCoreIncDir = true;
- }
- }
- }
-
- // Some projects (kdelibs, phonon) query the compiler for its default
- // include search dirs, and add those to
- // CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES.
- // These may include e.g./usr/lib/qt/include . This is typically also part
- // of ${QT_INCLUDES}. If this directory is then contained in the implicit
- // include dirs, it is removed from the include dirs returned from the
- // target above. So we add ${QT_INCLUDE_DIR} manually for moc if we detected
- // that ${QT_QTCORE_INCLUDE_DIR} is among the include dirs (there shouldn't
- // be a way to use Qt4 without using ${QT_QTCORE_INCLUDE_DIR} I think.
- // See #13646 and #13667.
- if (qtIncludeDirMayHaveBeenRemoved && qtCoreIncDir && qtIncDir
- && (haveQtCoreIncDir == true) && (haveQtIncDir == false))
- {
- _moc_incs += sep;
- sep = ";";
- _moc_incs += qtIncDir;
}
const char* tmp = target->GetProperty("COMPILE_DEFINITIONS");
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
index 0193dc9..e49edd8 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,51 @@ 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;
+ }
+
+ unsigned 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;
+ }
+ }
+
+ cmTimestamp timestamp;
+ std::string result = timestamp.CurrentTime(formatString, utcFlag);
+ this->Makefile->AddDefinition(outputVariable.c_str(), result.c_str());
+
+ return true;
+}
diff --git a/Source/cmStringCommand.h b/Source/cmStringCommand.h
index 728b1bc..4423a90 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 "
@@ -142,7 +143,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 the output variable.\n"
+ "Should the command be unable to obtain a timestamp "
+ "the output variable will be set to the empty string \"\".\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);
@@ -165,6 +192,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..ac26503
--- /dev/null
+++ b/Source/cmTimestamp.cxx
@@ -0,0 +1,134 @@
+/*============================================================================
+ 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>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+//----------------------------------------------------------------------------
+std::string cmTimestamp::CurrentTime(
+ const std::string& formatString, bool utcFlag)
+{
+ time_t currentTimeT = time(0);
+ if(currentTimeT == time_t(-1))
+ {
+ return std::string();
+ }
+
+ return CreateTimestampFromTimeT(currentTimeT, formatString, utcFlag);
+}
+
+//----------------------------------------------------------------------------
+std::string cmTimestamp::FileModificationTime(const char* path,
+ const std::string& formatString, bool utcFlag)
+{
+ struct stat info;
+ memset(&info, 0, sizeof(info));
+
+ if(stat(path, &info) != 0)
+ {
+ return std::string();
+ }
+
+ return CreateTimestampFromTimeT(info.st_mtime, formatString, utcFlag);
+}
+
+//----------------------------------------------------------------------------
+std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT,
+ std::string formatString, bool utcFlag)
+{
+ if(formatString.empty())
+ {
+ formatString = "%Y-%m-%dT%H:%M:%S";
+ if(utcFlag)
+ {
+ formatString += "Z";
+ }
+ }
+
+ struct tm timeStruct;
+ memset(&timeStruct, 0, sizeof(timeStruct));
+
+ struct tm* ptr = (struct tm*) 0;
+ if(utcFlag)
+ {
+ ptr = gmtime(&timeT);
+ }
+ else
+ {
+ ptr = localtime(&timeT);
+ }
+
+ if(ptr == 0)
+ {
+ return std::string();
+ }
+
+ timeStruct = *ptr;
+
+ std::string result;
+ for(std::string::size_type i = 0; i < formatString.size(); ++i)
+ {
+ char c1 = formatString[i];
+ char c2 = (i+1 < formatString.size()) ?
+ formatString[i+1] : static_cast<char>(0);
+
+ if(c1 == '%' && c2 != 0)
+ {
+ result += AddTimestampComponent(c2, timeStruct);
+ ++i;
+ }
+ else
+ {
+ result += c1;
+ }
+ }
+
+ return result;
+}
+
+//----------------------------------------------------------------------------
+std::string cmTimestamp::AddTimestampComponent(
+ char flag, struct 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];
+
+ size_t size = 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..24c1869
--- /dev/null
+++ b/Source/cmTimestamp.h
@@ -0,0 +1,40 @@
+/*============================================================================
+ 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 <time.h>
+
+/** \class cmTimestamp
+ * \brief Utility class to generate sting representation of a timestamp
+ *
+ */
+class cmTimestamp
+{
+public:
+ cmTimestamp() {}
+
+ std::string CurrentTime(const std::string& formatString, bool utcFlag);
+
+ std::string FileModificationTime(const char* path,
+ const std::string& formatString, bool utcFlag);
+
+private:
+ std::string CreateTimestampFromTimeT(time_t timeT,
+ std::string formatString, bool utcFlag);
+
+ std::string AddTimestampComponent(char flag, struct tm& timeStruct);
+};
+
+
+#endif