]> git.cworth.org Git - apitrace/blob - common/os_string.hpp
cli: Don't replace, but instead prepend the environment variable.
[apitrace] / common / os_string.hpp
1 /**************************************************************************
2  *
3  * Copyright 2011 Jose Fonseca
4  * All Rights Reserved.
5  *
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:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
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
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 /*
27  * String manipulation.
28  */
29
30 #ifndef _OS_STRING_HPP_
31 #define _OS_STRING_HPP_
32
33
34 #include <assert.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stddef.h>
38
39 #ifdef __MINGW32__
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);
43 #endif
44
45 #ifndef va_copy
46 #ifdef __va_copy
47 #define va_copy(dest, src) __va_copy((dest), (src))
48 #else
49 #define va_copy(dest, src) (dest) = (src)
50 #endif
51 #endif
52
53 #include <vector>
54
55 #include "os.hpp"
56
57
58 #ifdef _WIN32
59 #define OS_DIR_SEP '\\'
60 #define OS_PATH_SEP ';'
61 #else /* !_WIN32 */
62 #define OS_DIR_SEP '/'
63 #define OS_PATH_SEP ':'
64 #endif /* !_WIN32 */
65
66
67 namespace os {
68
69
70 /**
71  * Vector based zero-terminate string, suitable for passing strings or paths
72  * to/from OS calls.
73  */
74 class String {
75 protected:
76     typedef std::vector<char> Buffer;
77
78     /**
79      * The buffer's last element is always the '\0' character, therefore the
80      * buffer must never be empty.
81      */
82     Buffer buffer;
83
84     Buffer::iterator find(char c) {
85         Buffer::iterator it = buffer.begin();
86         assert(it != buffer.end());
87         while (it != buffer.end()) {
88             if (*it == c) {
89                 return it;
90             }
91             ++it;
92         }
93         return buffer.end();
94     }
95
96     Buffer::iterator rfind(char c) {
97         Buffer::iterator it = buffer.end();
98
99         // Skip trailing '\0'
100         assert(it != buffer.begin());
101         --it;
102         assert(*it == '\0');
103
104         while (it != buffer.begin()) {
105             --it;
106             if (*it == c) {
107                 return it;
108             }
109         }
110
111         return buffer.end();
112     }
113
114     String(size_t size) :
115         buffer(size) {
116     }
117
118     char *buf(void) {
119         return &buffer[0];
120     }
121
122     inline bool
123     isSep(char c) {
124         if (c == '/') {
125             return true;
126         }
127 #ifdef _WIN32
128         if (c == '\\') {
129             return true;
130         }
131 #endif
132         return false;
133     }
134
135 public:
136
137     Buffer::iterator rfindSep(bool skipTrailing = true) {
138         Buffer::iterator it = end();
139
140         // Skip trailing separators
141         if (skipTrailing) {
142             while (it != buffer.begin()) {
143                 --it;
144                 if (isSep(*it)) {
145                     // Halt if find the root
146                     if (it == buffer.begin()) {
147                         return it;
148                     }
149                 } else {
150                     break;
151                 }
152             }
153         }
154
155         // Advance to the last separator
156         while (it != buffer.begin()) {
157             --it;
158             if (isSep(*it)) {
159                 return it;
160             }
161         }
162
163         return end();
164     }
165
166     /*
167      * Constructors
168      */
169
170     String() {
171         buffer.push_back(0);
172     }
173
174     String(const char *s) :
175         buffer(s, s + strlen(s) + 1)
176     {}
177
178     String(const String &other) :
179         buffer(other.buffer)
180     {}
181
182     template <class InputIterator>
183     String(InputIterator first, InputIterator last) :
184         buffer(first, last)
185     {
186         buffer.push_back(0);
187     }
188
189     /**
190      * From a printf-like format string
191      */
192     static String
193     format(const char *format, ...)
194 #ifdef __GNUC__
195     __attribute__ ((format (printf, 1, 2)))
196 #endif
197     {
198
199         va_list args;
200
201         va_start(args, format);
202
203         int length;
204         va_list args_copy;
205         va_copy(args_copy, args);
206 #ifdef _WIN32
207         /* We need to use _vscprintf to calculate the length as vsnprintf returns -1
208          * if the number of characters to write is greater than count.
209          */
210         length = _vscprintf(format, args_copy);
211 #else
212         char dummy;
213         length = vsnprintf(&dummy, sizeof dummy, format, args_copy);
214 #endif
215         va_end(args_copy);
216
217         assert(length >= 0);
218         size_t size = length + 1;
219
220         String path(size);
221
222         va_start(args, format);
223         vsnprintf(path.buf(), size, format, args);
224         va_end(args);
225
226         return path;
227     }
228
229     /*
230      * Conversion to ordinary C strings.
231      */
232
233     const char *str(void) const {
234         assert(buffer.back() == 0);
235         return &buffer[0];
236     }
237
238     operator const char *(void) const {
239         return str();
240     }
241
242     /*
243      * Iterators
244      */
245
246     typedef Buffer::const_iterator const_iterator;
247     typedef Buffer::iterator iterator;
248
249     const_iterator begin(void) const {
250         return buffer.begin();
251     }
252
253     iterator begin(void) {
254         return buffer.begin();
255     }
256
257     const_iterator end(void) const {
258         const_iterator it = buffer.end();
259         assert(it != buffer.begin());
260         --it; // skip null
261         return it;
262     }
263
264     iterator end(void) {
265         iterator it = buffer.end();
266         assert(it != buffer.begin());
267         --it; // skip null
268         return it;
269     }
270
271     /*
272      * Operations
273      */
274
275     void insert(iterator position, char c) {
276         buffer.insert(position, c);
277     }
278
279     template <class InputIterator>
280     void insert(iterator position, InputIterator first, InputIterator last) {
281         buffer.insert(position, first, last);
282     }
283
284     void insert(iterator position, const char *s) {
285         assert(s);
286         insert(position, s, s + strlen(s));
287     }
288
289     void insert(iterator position, const String & other) {
290         insert(position, other.begin(), other.end());
291     }
292
293     void append(char c) {
294         insert(end(), c);
295     }
296
297     template <class InputIterator>
298     void append(InputIterator first, InputIterator last) {
299         insert(end(), first, last);
300     }
301
302     void append(const char *s) {
303         insert(end(), s);
304     }
305
306     void append(const String & other) {
307         insert(end(), other);
308     }
309
310     template <class InputIterator>
311     void erase(InputIterator first, InputIterator last) {
312         buffer.erase(first, last);
313     }
314
315     char *buf(size_t size) {
316         buffer.resize(size);
317         return &buffer[0];
318     }
319
320     size_t length(void) const {
321         size_t size = buffer.size();
322         assert(size > 0);
323         assert(buffer[size - 1] == 0);
324         return size - 1;
325     }
326
327     void truncate(size_t length) {
328         assert(length < buffer.size());
329         buffer[length] = 0;
330         buffer.resize(length + 1);
331     }
332
333     void truncate(void) {
334         truncate(strlen(str()));
335     }
336
337
338     /*
339      * Path manipulation
340      */
341
342     bool
343     exists(void) const;
344
345     /* Trim directory (leaving base filename).
346      */
347     void trimDirectory(void) {
348         iterator sep = rfindSep();
349         if (sep != end()) {
350             buffer.erase(buffer.begin(), sep + 1);
351         }
352     }
353
354     /* Trim filename component (leaving containing directory).
355      *
356      * - trailing separators are ignored
357      * - a path with no separator at all yields "."
358      * - a path consisting of just the root directory is left unchanged
359      */
360     void trimFilename(void) {
361         iterator sep = rfindSep();
362
363         // No separator found, so return '.'
364         if (sep == end()) {
365             buffer.resize(2);
366             buffer[0] = '.';
367             buffer[1] = 0;
368             return;
369         }
370
371         // Root. Nothing to do.
372         if (sep == buffer.begin()) {
373             return;
374         }
375
376         // Trim filename
377         buffer.erase(sep, end());
378     }
379
380     void trimExtension(void) {
381         iterator dot = rfind('.');
382         if (dot != buffer.end()) {
383             buffer.erase(dot, end());
384         }
385     }
386
387     void join(const String & other) {
388         if (length() && end()[-1] != OS_DIR_SEP) {
389             append(OS_DIR_SEP);
390         }
391         append(other.begin(), other.end());
392     }
393 };
394
395
396 String getProcessName();
397 String getCurrentDir();
398
399 bool createDirectory(const String &path);
400
401 bool copyFile(const String &srcFileName, const String &dstFileName, bool override = true);
402
403 bool removeFile(const String &fileName);
404
405 } /* namespace os */
406
407 #endif /* _OS_STRING_HPP_ */