From: José Fonseca Date: Thu, 24 Nov 2011 20:09:41 +0000 (+0000) Subject: Cleanup and generalize os string class. X-Git-Url: https://git.cworth.org/git?a=commitdiff_plain;h=447b3d5c7402b0a9e780a26dfed76376e723ac94;p=apitrace Cleanup and generalize os string class. --- diff --git a/cli/cli_diff.cpp b/cli/cli_diff.cpp index 4d24973..d9d6257 100644 --- a/cli/cli_diff.cpp +++ b/cli/cli_diff.cpp @@ -29,7 +29,7 @@ #include #include "cli.hpp" -#include "os_path.hpp" +#include "os_string.hpp" #include "os_process.hpp" #include "trace_tools.hpp" @@ -83,7 +83,7 @@ command(int argc, char *argv[]) #define CLI_DIFF_TRACEDIFF_COMMAND "tracediff.sh" - os::Path command = trace::findFile("scripts/" CLI_DIFF_TRACEDIFF_COMMAND, + os::String command = trace::findFile("scripts/" CLI_DIFF_TRACEDIFF_COMMAND, APITRACE_SCRIPTS_INSTALL_DIR "/" CLI_DIFF_TRACEDIFF_COMMAND, true); @@ -98,7 +98,7 @@ command(int argc, char *argv[]) std::cerr << "The 'apitrace diff' command is not yet supported on this O/S.\n"; return 1; #else - os::Path apitrace = os::getProcessName(); + os::String apitrace = os::getProcessName(); setenv("APITRACE", apitrace.str(), 1); return os::execute(args); diff --git a/cli/cli_diff_images.cpp b/cli/cli_diff_images.cpp index 390174c..91f07c1 100644 --- a/cli/cli_diff_images.cpp +++ b/cli/cli_diff_images.cpp @@ -29,12 +29,12 @@ #include #include "cli.hpp" -#include "os_path.hpp" +#include "os_string.hpp" #include "trace_tools.hpp" static const char *synopsis = "Identify differences between two image dumps."; -static os::Path +static os::String find_command(void) { #define CLI_DIFF_IMAGES_COMMAND "snapdiff.py" @@ -50,7 +50,7 @@ usage(void) { char *args[3]; - os::Path command = find_command(); + os::String command = find_command(); args[0] = (char *) command.str(); args[1] = (char *) "--help"; @@ -71,7 +71,7 @@ command(int argc, char *argv[]) int i; char **args = new char* [argc+2]; - os::Path command = find_command(); + os::String command = find_command(); args[0] = (char *) command.str(); diff --git a/cli/cli_diff_state.cpp b/cli/cli_diff_state.cpp index 5dd0fbe..55d8083 100644 --- a/cli/cli_diff_state.cpp +++ b/cli/cli_diff_state.cpp @@ -29,7 +29,7 @@ #include #include "cli.hpp" -#include "os_path.hpp" +#include "os_string.hpp" #include "os_process.hpp" #include "trace_tools.hpp" @@ -83,7 +83,7 @@ command(int argc, char *argv[]) #define CLI_DIFF_STATE_COMMAND "jsondiff.py" - os::Path command = trace::findFile("scripts/" CLI_DIFF_STATE_COMMAND, + os::String command = trace::findFile("scripts/" CLI_DIFF_STATE_COMMAND, APITRACE_SCRIPTS_INSTALL_DIR "/" CLI_DIFF_STATE_COMMAND, true); diff --git a/common/os_path.hpp b/common/os_path.hpp deleted file mode 100644 index ffb4fd2..0000000 --- a/common/os_path.hpp +++ /dev/null @@ -1,251 +0,0 @@ -/************************************************************************** - * - * Copyright 2011 Jose Fonseca - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - **************************************************************************/ - -/* - * Path manipulation. - */ - -#ifndef _OS_PATH_HPP_ -#define _OS_PATH_HPP_ - - -#include -#include -#include -#include - -#ifdef __MINGW32__ -// Some versions of MinGW are missing _vscprintf's declaration, although they -// still provide the symbol in the import library. -extern "C" _CRTIMP int _vscprintf(const char *format, va_list argptr); -#endif - -#ifndef va_copy -#ifdef __va_copy -#define va_copy(dest, src) __va_copy((dest), (src)) -#else -#define va_copy(dest, src) (dest) = (src) -#endif -#endif - -#include - -#include "os.hpp" - - -#ifdef _WIN32 -#define OS_DIR_SEP '\\' -#else /* !_WIN32 */ -#define OS_DIR_SEP '/' -#endif /* !_WIN32 */ - - -namespace os { - - -class Path { -protected: - typedef std::vector Buffer; - Buffer buffer; - - Buffer::iterator find(char c) { - Buffer::iterator it = buffer.begin(); - /* Why do we make these functions fail on empty paths? */ - assert(it != buffer.end()); - while (it != buffer.end()) { - if (*it == c) { - return it; - } - ++it; - } - return buffer.end(); - } - - Buffer::iterator rfind(char c) { - Buffer::iterator it = buffer.end(); - assert(it != buffer.begin()); - --it; // skip null - while (it != buffer.begin()) { - --it; - if (*it == c) { - return it; - } - } - return buffer.end(); - } - - Path(size_t size) : - buffer(size) { - } - - char *buf(void) { - return &buffer[0]; - } - -public: - Path() { - buffer.push_back(0); - } - - Path(const char *s) : - buffer(s, s + strlen(s) + 1) - {} - - template - Path(InputIterator first, InputIterator last) : - buffer(first, last) - { - buffer.push_back(0); - } - - char *buf(size_t size) { - buffer.resize(size); - return &buffer[0]; - } - - void trimDirectory(void) { - Buffer::iterator sep = rfind(OS_DIR_SEP); - if (sep != buffer.end()) { - buffer.erase(buffer.begin(), sep + 1); - } - } - - /* Trim filename component (leaving containing directory). - * - * This function removes everything after the final path - * separator, as well as that separator itself if it is not the - * only remaining separator. - * - * Some specific consequences of the above: - * - * 1. A path with no separator at all is unchanged. - * 2. A path with a trailing separator has only that separator removed - * 3. A path of just the root directory is unchaged. - */ - void trimFilename(void) { - Buffer::iterator first = find(OS_DIR_SEP); - Buffer::iterator last = rfind(OS_DIR_SEP); - if (last == buffer.end()) { - return; - } - if (last == first) { - buffer.erase(first + 1, buffer.end() - 1); - } else { - buffer.erase(last, buffer.end() - 1); - } - } - - void trimExtension(void) { - Buffer::iterator dot = rfind('.'); - if (dot != buffer.end()) { - buffer.erase(dot, buffer.end() - 1); - } - } - - size_t length(void) const { - size_t size = buffer.size(); - assert(size > 0); - assert(buffer[size - 1] == 0); - return size - 1; - } - - void truncate(size_t length) { - assert(length < buffer.size()); - buffer[length] = 0; - buffer.resize(length + 1); - } - - void truncate(void) { - truncate(strlen(str())); - } - - const char *str(void) const { - assert(buffer[buffer.size() - 1] == 0); - return &buffer[0]; - } - - operator const char *(void) const { - return str(); - } - - void join(const Path & other) { - size_t len = length(); - if (len > 0 && buffer[len - 1] != OS_DIR_SEP) { - buffer.insert(buffer.begin() + len++, OS_DIR_SEP); - } - buffer.insert(buffer.begin() + len, other.buffer.begin(), other.buffer.end() - 1); - } - - /** - * Create a path from a printf-like format string - */ - static Path - format(const char *format, ...) -#ifdef __GNUC__ - __attribute__ ((format (printf, 1, 2))) -#endif - { - - va_list args; - - va_start(args, format); - - int length; - va_list args_copy; - va_copy(args_copy, args); -#ifdef _WIN32 - /* We need to use _vcsprintf to calculate the length as vsnprintf returns -1 - * if the number of characters to write is greater than count. - */ - length = _vscprintf(format, args_copy); -#else - char dummy; - length = vsnprintf(&dummy, sizeof dummy, format, args_copy); -#endif - va_end(args_copy); - - assert(length >= 0); - size_t size = length + 1; - - Path path(size); - - va_start(args, format); - vsnprintf(path.buf(), size, format, args); - va_end(args); - - return path; - } - - bool exists(void) const; -}; - - -Path getProcessName(); -Path getCurrentDir(); - - -} /* namespace os */ - -#endif /* _OS_PATH_HPP_ */ diff --git a/common/os_posix.cpp b/common/os_posix.cpp index da78783..7dc2bb4 100644 --- a/common/os_posix.cpp +++ b/common/os_posix.cpp @@ -52,7 +52,7 @@ #endif #include "os.hpp" -#include "os_path.hpp" +#include "os_string.hpp" namespace os { @@ -76,10 +76,10 @@ releaseMutex(void) } -Path +String getProcessName(void) { - Path path; + String path; size_t size = PATH_MAX; char *buf = path.buf(size); @@ -113,10 +113,10 @@ getProcessName(void) return path; } -Path +String getCurrentDir(void) { - Path path; + String path; size_t size = PATH_MAX; char *buf = path.buf(size); @@ -128,7 +128,7 @@ getCurrentDir(void) } bool -Path::exists(void) const +String::exists(void) const { struct stat st; int err; diff --git a/common/os_string.hpp b/common/os_string.hpp new file mode 100644 index 0000000..c92e6a8 --- /dev/null +++ b/common/os_string.hpp @@ -0,0 +1,343 @@ +/************************************************************************** + * + * Copyright 2011 Jose Fonseca + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + +/* + * String manipulation. + */ + +#ifndef _OS_STRING_HPP_ +#define _OS_STRING_HPP_ + + +#include +#include +#include +#include + +#ifdef __MINGW32__ +// Some versions of MinGW are missing _vscprintf's declaration, although they +// still provide the symbol in the import library. +extern "C" _CRTIMP int _vscprintf(const char *format, va_list argptr); +#endif + +#ifndef va_copy +#ifdef __va_copy +#define va_copy(dest, src) __va_copy((dest), (src)) +#else +#define va_copy(dest, src) (dest) = (src) +#endif +#endif + +#include + +#include "os.hpp" + + +#ifdef _WIN32 +#define OS_DIR_SEP '\\' +#else /* !_WIN32 */ +#define OS_DIR_SEP '/' +#endif /* !_WIN32 */ + + +namespace os { + + +/** + * Vector based zero-terminate string, suitable for passing strings or paths + * to/from OS calls. + */ +class String { +protected: + typedef std::vector Buffer; + + /** + * The buffer's last element is always the '\0' character, therefore the + * buffer must never be empty. + */ + Buffer buffer; + + Buffer::iterator find(char c) { + Buffer::iterator it = buffer.begin(); + assert(it != buffer.end()); + while (it != buffer.end()) { + if (*it == c) { + return it; + } + ++it; + } + return buffer.end(); + } + + Buffer::iterator rfind(char c) { + Buffer::iterator it = buffer.end(); + while (it != buffer.begin()) { + --it; + if (*it == c) { + return it; + } + } + return buffer.end(); + } + + String(size_t size) : + buffer(size) { + } + + char *buf(void) { + return &buffer[0]; + } + +public: + + /* + * Constructors + */ + + String() { + buffer.push_back(0); + } + + String(const char *s) : + buffer(s, s + strlen(s) + 1) + {} + + String(const String &other) : + buffer(other.buffer) + {} + + template + String(InputIterator first, InputIterator last) : + buffer(first, last) + { + buffer.push_back(0); + } + + /** + * From a printf-like format string + */ + static String + format(const char *format, ...) +#ifdef __GNUC__ + __attribute__ ((format (printf, 1, 2))) +#endif + { + + va_list args; + + va_start(args, format); + + int length; + va_list args_copy; + va_copy(args_copy, args); +#ifdef _WIN32 + /* We need to use _vcsprintf to calculate the length as vsnprintf returns -1 + * if the number of characters to write is greater than count. + */ + length = _vscprintf(format, args_copy); +#else + char dummy; + length = vsnprintf(&dummy, sizeof dummy, format, args_copy); +#endif + va_end(args_copy); + + assert(length >= 0); + size_t size = length + 1; + + String path(size); + + va_start(args, format); + vsnprintf(path.buf(), size, format, args); + va_end(args); + + return path; + } + + /* + * Conversion to ordinary C strings. + */ + + const char *str(void) const { + assert(buffer.back() == 0); + return &buffer[0]; + } + + operator const char *(void) const { + return str(); + } + + /* + * Iterators + */ + + typedef Buffer::const_iterator const_iterator; + typedef Buffer::iterator iterator; + + const_iterator begin(void) const { + return buffer.begin(); + } + + iterator begin(void) { + return buffer.begin(); + } + + const_iterator end(void) const { + const_iterator it = buffer.end(); + assert(it != buffer.begin()); + --it; // skip null + return it; + } + + iterator end(void) { + iterator it = buffer.end(); + assert(it != buffer.begin()); + --it; // skip null + return it; + } + + /* + * Operations + */ + + void insert(iterator position, char c) { + buffer.insert(position, c); + } + + template + void insert(iterator position, InputIterator first, InputIterator last) { + buffer.insert(position, first, last); + } + + void insert(iterator position, const char *s) { + assert(s); + insert(position, s, s + strlen(s)); + } + + void insert(iterator position, const String & other) { + insert(position, other.begin(), other.end()); + } + + void append(char c) { + insert(end(), c); + } + + template + void append(InputIterator first, InputIterator last) { + insert(end(), first, last); + } + + void append(const char *s) { + insert(end(), s); + } + + void append(const String & other) { + insert(end(), other); + } + + char *buf(size_t size) { + buffer.resize(size); + return &buffer[0]; + } + + size_t length(void) const { + size_t size = buffer.size(); + assert(size > 0); + assert(buffer[size - 1] == 0); + return size - 1; + } + + void truncate(size_t length) { + assert(length < buffer.size()); + buffer[length] = 0; + buffer.resize(length + 1); + } + + void truncate(void) { + truncate(strlen(str())); + } + + + /* + * String manipulation + */ + + bool + exists(void) const; + + void trimDirectory(void) { + iterator sep = rfind(OS_DIR_SEP); + if (sep != buffer.end()) { + buffer.erase(buffer.begin(), sep + 1); + } + } + + /* Trim filename component (leaving containing directory). + * + * This function removes everything after the final path + * separator, as well as that separator itself if it is not the + * only remaining separator. + * + * Some specific consequences of the above: + * + * 1. A path with no separator at all is unchanged. + * 2. A path with a trailing separator has only that separator removed + * 3. A path of just the root directory is unchaged. + */ + void trimFilename(void) { + iterator first = find(OS_DIR_SEP); + iterator last = rfind(OS_DIR_SEP); + if (last == buffer.end()) { + return; + } + if (last == first) { + buffer.erase(first + 1, end()); + } else { + buffer.erase(last, end()); + } + } + + void trimExtension(void) { + iterator dot = rfind('.'); + if (dot != buffer.end()) { + buffer.erase(dot, end()); + } + } + + void join(const String & other) { + if (length() && end()[-1] != OS_DIR_SEP) { + append(OS_DIR_SEP); + } + append(other.begin(), other.end()); + } +}; + + +String getProcessName(); +String getCurrentDir(); + + +} /* namespace os */ + +#endif /* _OS_STRING_HPP_ */ diff --git a/common/os_win32.cpp b/common/os_win32.cpp index e156c77..13dd4f8 100644 --- a/common/os_win32.cpp +++ b/common/os_win32.cpp @@ -32,7 +32,7 @@ #include #include "os.hpp" -#include "os_path.hpp" +#include "os_string.hpp" namespace os { @@ -61,10 +61,10 @@ releaseMutex(void) } -Path +String getProcessName(void) { - Path path; + String path; size_t size = MAX_PATH; char *buf = path.buf(size); @@ -76,10 +76,10 @@ getProcessName(void) return path; } -Path +String getCurrentDir(void) { - Path path; + String path; size_t size = MAX_PATH; char *buf = path.buf(size); @@ -93,7 +93,7 @@ getCurrentDir(void) } bool -Path::exists(void) const +String::exists(void) const { DWORD attrs = GetFileAttributesA(str()); return attrs != INVALID_FILE_ATTRIBUTES; diff --git a/common/trace_tools.hpp b/common/trace_tools.hpp index ed786e9..7ca908a 100644 --- a/common/trace_tools.hpp +++ b/common/trace_tools.hpp @@ -29,10 +29,7 @@ #include - -namespace os { - class Path; -}; +#include "os_string.hpp" namespace trace { @@ -44,7 +41,7 @@ enum API { }; -os::Path +os::String findFile(const char *relPath, // path relative to the current program const char *absPath, // absolute path bool verbose); diff --git a/common/trace_tools_trace.cpp b/common/trace_tools_trace.cpp index 146f19f..f14617d 100644 --- a/common/trace_tools_trace.cpp +++ b/common/trace_tools_trace.cpp @@ -30,7 +30,7 @@ #include -#include "os_path.hpp" +#include "os_string.hpp" #include "os_process.hpp" #include "trace_tools.hpp" @@ -52,17 +52,17 @@ namespace trace { #endif -os::Path +os::String findFile(const char *relPath, const char *absPath, bool verbose) { - os::Path complete; + os::String complete; /* First look in the same directory from which this process is * running, (to support developers running a compiled program that * has not been installed. */ - os::Path process_dir = os::getProcessName(); + os::String process_dir = os::getProcessName(); process_dir.trimFilename(); @@ -113,7 +113,7 @@ traceProgram(API api, return 1; } - os::Path wrapper; + os::String wrapper; wrapper = findFile(relPath, absPath, verbose); if (!wrapper.length()) { diff --git a/common/trace_writer_local.cpp b/common/trace_writer_local.cpp index 9d0429b..0730150 100644 --- a/common/trace_writer_local.cpp +++ b/common/trace_writer_local.cpp @@ -31,7 +31,7 @@ #include #include "os.hpp" -#include "os_path.hpp" +#include "os_string.hpp" #include "trace_file.hpp" #include "trace_writer.hpp" #include "trace_format.hpp" @@ -74,7 +74,7 @@ LocalWriter::~LocalWriter() void LocalWriter::open(void) { - os::Path szFileName; + os::String szFileName; const char *lpFileName; @@ -82,22 +82,22 @@ LocalWriter::open(void) { if (!lpFileName) { static unsigned dwCounter = 0; - os::Path process = os::getProcessName(); + os::String process = os::getProcessName(); #ifdef _WIN32 process.trimExtension(); #endif process.trimDirectory(); - os::Path prefix = os::getCurrentDir(); + os::String prefix = os::getCurrentDir(); prefix.join(process); for (;;) { FILE *file; if (dwCounter) - szFileName = os::Path::format("%s.%u.trace", prefix.str(), dwCounter); + szFileName = os::String::format("%s.%u.trace", prefix.str(), dwCounter); else - szFileName = os::Path::format("%s.trace", prefix.str()); + szFileName = os::String::format("%s.trace", prefix.str()); lpFileName = szFileName; file = fopen(lpFileName, "rb"); diff --git a/glretrace_main.cpp b/glretrace_main.cpp index dfb051c..3c010d2 100644 --- a/glretrace_main.cpp +++ b/glretrace_main.cpp @@ -26,7 +26,7 @@ #include -#include "os_path.hpp" +#include "os_string.hpp" #include "image.hpp" #include "retrace.hpp" #include "glproc.hpp" @@ -140,7 +140,7 @@ void snapshot(unsigned call_no) { image::Image *ref = NULL; if (compare_prefix) { - os::Path filename = os::Path::format("%s%010u.png", compare_prefix, call_no); + os::String filename = os::String::format("%s%010u.png", compare_prefix, call_no); ref = image::readPNG(filename); if (!ref) { return; @@ -161,7 +161,7 @@ void snapshot(unsigned call_no) { snprintf(comment, sizeof comment, "%u", call_no); src->writePNM(std::cout, comment); } else { - os::Path filename = os::Path::format("%s%010u.png", snapshot_prefix, call_no); + os::String filename = os::String::format("%s%010u.png", snapshot_prefix, call_no); if (src->writePNG(filename) && retrace::verbosity >= 0) { std::cout << "Wrote " << filename << "\n"; }