#include <cstdio> // mkdtemp()
#include <cstdlib> // getenv()
#include <iostream> // cout, endl
#include <vector>
namespace {
/// <summary>Creates a unique temporary directory for use by the unit tests</summary>
class TemporaryDirectoryScope {
/// <summary>Creates the unique temporary directory</summary>
public: TemporaryDirectoryScope() :
path(createTemporaryDirectory()) {}
public: ~TemporaryDirectoryScope() { /* omitted */ }
/// <summary>Gives the path of the unique temporary directory</summary>
/// <returns>The absolute path of the unique temporary directory</returns>
public: const std::string &GetPath() const { return this->path; }
#if defined(NUCLEX_PIXELS_WIN32)
#else // Any Linux/Posix compatible system
/// <summary>Creates a unique temporary directory and returns its path</summary>
/// <returns>The path to the unique temporary directory</returns>
private: static std::string createTemporaryDirectory() {
std::vector<char> temporaryDirectoryPath;
temporaryDirectoryPath.reserve(16 + 32);
// First, look up the system's temporary directory
appendTempDirectory(temporaryDirectoryPath);
// Append a path component separator if appendTempDirectory() didn't provide one
// and the temp path isn't empty (i.e. user wants temp files loaded into CWD ?_?)
if(temporaryDirectoryPath.size() > 0) {
if(temporaryDirectoryPath[temporaryDirectoryPath.size() - 1] != '/') {
temporaryDirectoryPath.push_back('/');
}
}
// Then append our directory name template to it
const char directoryNameTemplate[] = u8"nuclex-pixels-unittest-XXXXXX";
{
const char *iterator = directoryNameTemplate;
while(*iterator != 0) {
temporaryDirectoryPath.push_back(*iterator);
++iterator;
}
}
// DEBUGGING. REMOVE.
std::cout <<
u8"Passing the following to mkdtemp(): " <<
std::string(&temporaryDirectoryPath[0], temporaryDirectoryPath.size()) <<
std::endl;
// Let mkdtemp() sort out a unique directory name for us (and create it!)
const char *directoryName = ::mkdtemp(&temporaryDirectoryPath[0]);
if(directoryName == nullptr) {
perror("mkdtemp() failed."); // DEBUGGING. REMOVE.
throw std::runtime_error("mkdtemp() failed.");
}
return std::string(&temporaryDirectoryPath[0], temporaryDirectoryPath.size());
}
/// <summary>Appenfs the user's/system's preferred temp directory to a path</summary>
/// <param name="path">Path vector the temp directory will be appended to</param>
private: static void appendTempDirectory(std::vector<char> &path) {
// Obtain the most likely system temp directory
const char *tempDirectory = ::getenv(u8"TMPDIR");
if(tempDirectory == nullptr) {
tempDirectory = ::getenv(u8"TMP");
if(tempDirectory == nullptr) {
tempDirectory = ::getenv(u8"TEMP");
if(tempDirectory == nullptr) {
// This is safe (part of the file system standard and Linux standard base),
// but we wanted to honor any possible user preferences first.
tempDirectory = u8"/tmp";
}
}
}
// Append the temporary directory to the path vector
while(*tempDirectory != 0) {
path.push_back(*tempDirectory);
++tempDirectory;
}
}
#endif
/// <summary>Path of the temporary directory</summary>
private: std::string path;
};
} // anonymous namespace
int main() {
TemporaryDirectoryScope myTempDir;
std::cout <<
u8"Determined temporary directory is " <<
myTempDir.GetPath() <<
std::endl;
}