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 **************************************************************************/
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 '/'
70 typedef std::vector<char> Buffer;
73 Buffer::iterator find(char c) {
74 Buffer::iterator it = buffer.begin();
75 /* Why do we make these functions fail on empty paths? */
76 assert(it != buffer.end());
77 while (it != buffer.end()) {
86 Buffer::iterator rfind(char c) {
87 Buffer::iterator it = buffer.end();
88 assert(it != buffer.begin());
90 while (it != buffer.begin()) {
112 Path(const char *s) :
113 buffer(s, s + strlen(s) + 1)
116 template <class InputIterator>
117 Path(InputIterator first, InputIterator last) :
123 char *buf(size_t size) {
128 void trimDirectory(void) {
129 Buffer::iterator sep = rfind(OS_DIR_SEP);
130 if (sep != buffer.end()) {
131 buffer.erase(buffer.begin(), sep + 1);
135 /* Trim filename component (leaving containing directory).
137 * This function removes everything after the final path
138 * separator, as well as that separator itself if it is not the
139 * only remaining separator.
141 * Some specific consequences of the above:
143 * 1. A path with no separator at all is unchanged.
144 * 2. A path with a trailing separator has only that separator removed
145 * 3. A path of just the root directory is unchaged.
147 void trimFilename(void) {
148 Buffer::iterator first = find(OS_DIR_SEP);
149 Buffer::iterator last = rfind(OS_DIR_SEP);
150 if (last == buffer.end()) {
154 buffer.erase(first + 1, buffer.end() - 1);
156 buffer.erase(last, buffer.end() - 1);
160 void trimExtension(void) {
161 Buffer::iterator dot = rfind('.');
162 if (dot != buffer.end()) {
163 buffer.erase(dot, buffer.end() - 1);
167 size_t length(void) const {
168 size_t size = buffer.size();
170 assert(buffer[size - 1] == 0);
174 void truncate(size_t length) {
175 assert(length < buffer.size());
177 buffer.resize(length + 1);
180 void truncate(void) {
181 truncate(strlen(str()));
184 const char *str(void) const {
185 assert(buffer[buffer.size() - 1] == 0);
189 operator const char *(void) const {
193 void join(const Path & other) {
194 size_t len = length();
195 if (len > 0 && buffer[len - 1] != OS_DIR_SEP) {
196 buffer.insert(buffer.begin() + len++, OS_DIR_SEP);
198 buffer.insert(buffer.begin() + len, other.buffer.begin(), other.buffer.end() - 1);
202 * Create a path from a printf-like format string
205 format(const char *format, ...)
207 __attribute__ ((format (printf, 1, 2)))
213 va_start(args, format);
217 va_copy(args_copy, args);
219 /* We need to use _vcsprintf to calculate the length as vsnprintf returns -1
220 * if the number of characters to write is greater than count.
222 length = _vscprintf(format, args_copy);
225 length = vsnprintf(&dummy, sizeof dummy, format, args_copy);
230 size_t size = length + 1;
234 va_start(args, format);
235 vsnprintf(path.buf(), size, format, args);
241 bool exists(void) const;
245 Path getProcessName();
246 Path getCurrentDir();
251 #endif /* _OS_PATH_HPP_ */