1 /**************************************************************************
3 * Copyright 2011 Jose Fonseca
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 **************************************************************************/
27 * String manipulation.
30 #ifndef _OS_STRING_HPP_
31 #define _OS_STRING_HPP_
40 // Some versions of MinGW are missing _vscprintf's declaration, although they
41 // still provide the symbol in the import library.
42 extern "C" _CRTIMP int _vscprintf(const char *format, va_list argptr);
47 #define va_copy(dest, src) __va_copy((dest), (src))
49 #define va_copy(dest, src) (dest) = (src)
59 #define OS_DIR_SEP '\\'
61 #define OS_DIR_SEP '/'
69 * Vector based zero-terminate string, suitable for passing strings or paths
74 typedef std::vector<char> Buffer;
77 * The buffer's last element is always the '\0' character, therefore the
78 * buffer must never be empty.
82 Buffer::iterator find(char c) {
83 Buffer::iterator it = buffer.begin();
84 assert(it != buffer.end());
85 while (it != buffer.end()) {
94 Buffer::iterator rfind(char c) {
95 Buffer::iterator it = buffer.end();
98 assert(it != buffer.begin());
102 while (it != buffer.begin()) {
112 String(size_t size) :
135 Buffer::iterator rfindSep(bool skipTrailing = true) {
136 Buffer::iterator it = end();
138 // Skip trailing separators
140 while (it != buffer.begin()) {
143 // Halt if find the root
144 if (it == buffer.begin()) {
153 // Advance to the last separator
154 while (it != buffer.begin()) {
172 String(const char *s) :
173 buffer(s, s + strlen(s) + 1)
176 String(const String &other) :
180 template <class InputIterator>
181 String(InputIterator first, InputIterator last) :
188 * From a printf-like format string
191 format(const char *format, ...)
193 __attribute__ ((format (printf, 1, 2)))
199 va_start(args, format);
203 va_copy(args_copy, args);
205 /* We need to use _vscprintf to calculate the length as vsnprintf returns -1
206 * if the number of characters to write is greater than count.
208 length = _vscprintf(format, args_copy);
211 length = vsnprintf(&dummy, sizeof dummy, format, args_copy);
216 size_t size = length + 1;
220 va_start(args, format);
221 vsnprintf(path.buf(), size, format, args);
228 * Conversion to ordinary C strings.
231 const char *str(void) const {
232 assert(buffer.back() == 0);
236 operator const char *(void) const {
244 typedef Buffer::const_iterator const_iterator;
245 typedef Buffer::iterator iterator;
247 const_iterator begin(void) const {
248 return buffer.begin();
251 iterator begin(void) {
252 return buffer.begin();
255 const_iterator end(void) const {
256 const_iterator it = buffer.end();
257 assert(it != buffer.begin());
263 iterator it = buffer.end();
264 assert(it != buffer.begin());
273 void insert(iterator position, char c) {
274 buffer.insert(position, c);
277 template <class InputIterator>
278 void insert(iterator position, InputIterator first, InputIterator last) {
279 buffer.insert(position, first, last);
282 void insert(iterator position, const char *s) {
284 insert(position, s, s + strlen(s));
287 void insert(iterator position, const String & other) {
288 insert(position, other.begin(), other.end());
291 void append(char c) {
295 template <class InputIterator>
296 void append(InputIterator first, InputIterator last) {
297 insert(end(), first, last);
300 void append(const char *s) {
304 void append(const String & other) {
305 insert(end(), other);
308 template <class InputIterator>
309 void erase(InputIterator first, InputIterator last) {
310 buffer.erase(first, last);
313 char *buf(size_t size) {
318 size_t length(void) const {
319 size_t size = buffer.size();
321 assert(buffer[size - 1] == 0);
325 void truncate(size_t length) {
326 assert(length < buffer.size());
328 buffer.resize(length + 1);
331 void truncate(void) {
332 truncate(strlen(str()));
343 /* Trim directory (leaving base filename).
345 void trimDirectory(void) {
346 iterator sep = rfindSep();
348 buffer.erase(buffer.begin(), sep + 1);
352 /* Trim filename component (leaving containing directory).
354 * - trailing separators are ignored
355 * - a path with no separator at all yields "."
356 * - a path consisting of just the root directory is left unchanged
358 void trimFilename(void) {
359 iterator sep = rfindSep();
361 // No separator found, so return '.'
369 // Root. Nothing to do.
370 if (sep == buffer.begin()) {
375 buffer.erase(sep, end());
378 void trimExtension(void) {
379 iterator dot = rfind('.');
380 if (dot != buffer.end()) {
381 buffer.erase(dot, end());
385 void join(const String & other) {
386 if (length() && end()[-1] != OS_DIR_SEP) {
389 append(other.begin(), other.end());
394 String getProcessName();
395 String getCurrentDir();
397 bool createDirectory(const String &path);
399 bool copyFile(const String &srcFileName, const String &dstFileName, bool override = true);
401 bool removeFile(const String &fileName);
405 #endif /* _OS_STRING_HPP_ */