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