More file path fixes
[synfig.git] / ETL / trunk / ETL / _stringf.h
1 /* =========================================================================
2 ** Extended Template and Library
3 ** stringf Prodecure Implementation
4 ** $Id: _stringf.h,v 1.1.1.1 2005/01/04 01:31:48 darco Exp $
5 **
6 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
7 **
8 ** This package is free software; you can redistribute it and/or
9 ** modify it under the terms of the GNU General Public License as
10 ** published by the Free Software Foundation; either version 2 of
11 ** the License, or (at your option) any later version.
12 **
13 ** This package is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 ** General Public License for more details.
17 **
18 ** === N O T E S ===========================================================
19 **
20 ** This is an internal header file, included by other ETL headers.
21 ** You should not attempt to use it directly.
22 **
23 ** ========================================================================= */
24
25 /* === S T A R T =========================================================== */
26
27 #ifndef __ETL__STRINGF_H
28 #define __ETL__STRINGF_H
29
30 /* === H E A D E R S ======================================================= */
31
32 #include <string>
33 #include <cstdarg>
34
35 /* === M A C R O S ========================================================= */
36
37 #ifndef ETL_STRPRINTF_MAX_LENGTH
38 #define ETL_STRPRINTF_MAX_LENGTH        (800)
39 #endif
40
41 /* === T Y P E D E F S ===================================================== */
42
43 _ETL_BEGIN_CDECLS
44
45 #if defined(__APPLE__) || defined(__CYGWIN__) || defined(_WIN32)
46 #define ETL_NO_THROW
47 #else
48 #define ETL_NO_THROW throw()
49 #endif
50
51 #ifdef HAVE_VASPRINTF   // This is the prefered method
52  extern int vasprintf(char **,const char *,va_list)ETL_NO_THROW;
53 #else
54
55 # ifdef HAVE_VSNPRINTF  // This is the secondary method
56 #  if defined(__CYGWIN__)  || defined(_WIN32)
57 extern int vsnprintf(char *,unsigned int,const char*,va_list)ETL_NO_THROW;
58 #  else
59 extern int vsnprintf(char *,int,const char*,va_list)ETL_NO_THROW;
60 #  endif
61 # endif
62
63 #endif
64
65 #ifdef HAVE_VSSCANF
66 extern int vsscanf(const char *,const char *,va_list)ETL_NO_THROW;
67 #else
68 #define ETL_NO_VSTRSCANF
69 #ifdef HAVE_SSCANF
70 extern int sscanf(const char *buf, const char *format, ...)ETL_NO_THROW;
71 #endif
72 #endif
73
74 #include <unistd.h>
75
76 _ETL_END_CDECLS
77
78 /* === C L A S S E S & S T R U C T S ======================================= */
79
80 _ETL_BEGIN_NAMESPACE
81
82 inline std::string
83 vstrprintf(const char *format, va_list args)
84 {
85 #ifdef HAVE_VASPRINTF   // This is the prefered method (and safest)
86         char *buffer;
87         std::string ret;
88         vasprintf(&buffer,format,args);
89         ret=buffer;
90         free(buffer);
91         return ret;
92 #else
93 #ifdef HAVE_VSNPRINTF   // This is the secondary method (Safe, but bulky)
94 #warning etl::vstrprintf() has a maximum size of ETL_STRPRINTF_MAX_LENGTH in this configuration.
95 #ifdef ETL_THREAD_SAFE
96         char buffer[ETL_STRPRINTF_MAX_LENGTH];
97 #else
98         static char buffer[ETL_STRPRINTF_MAX_LENGTH];
99 #endif
100         vsnprintf(buffer,sizeof(buffer),format,args);
101         return buffer;
102 #else                                   // This is the worst method (UNSAFE, but "works")
103 #warning Potential for Buffer-overflow bug using vsprintf
104 #define ETL_UNSAFE_STRPRINTF    (true)
105 // Here, we are doubling the size of the buffer to make this case
106 // slightly more safe.
107 #ifdef ETL_THREAD_SAFE
108         char buffer[ETL_STRPRINTF_MAX_LENGTH*2];
109 #else
110         static char buffer[ETL_STRPRINTF_MAX_LENGTH*2];
111 #endif
112         vsprintf(buffer,format,args);
113         return buffer;
114 #endif
115 #endif
116 }
117
118 inline std::string
119 strprintf(const char *format, ...)
120 {
121         va_list args;
122         va_start(args,format);
123         return vstrprintf(format,args);
124 }
125
126 #ifndef ETL_NO_VSTRSCANF
127 inline int
128 vstrscanf(const std::string &data, const char*format, va_list args)
129 {
130     return vsscanf(data.c_str(),format,args);
131 }
132
133 inline int
134 strscanf(const std::string &data, const char*format, ...)
135 {
136         va_list args;
137         va_start(args,format);
138         return vstrscanf(data, format,args);
139 }
140 #else
141
142 #if defined (HAVE_SSCANF) && defined (__GNUC__)
143 #define strscanf(data,format,...) sscanf(data.c_str(),format,__VA_ARGS__)
144 #endif
145 #endif
146
147
148 #define stratof(X) (atof((X).c_str()))
149 #define stratoi(X) (atoi((X).c_str()))
150
151 inline std::string
152 basename(const std::string &str)
153 {
154         std::string::const_iterator iter;
155
156         if(str.end()[-1]==ETL_DIRECTORY_SEPERATOR)
157                 iter=str.end()-2;
158         else
159                 iter=str.end()-1;
160
161         for(;iter!=str.begin();iter--)
162                 if(*iter==ETL_DIRECTORY_SEPERATOR)
163                         break;
164
165         if(iter==str.begin())
166                 return str;
167
168         iter++;
169
170         if(str.end()[-1]==ETL_DIRECTORY_SEPERATOR)
171                 return std::string(iter,str.end()-1);
172
173         return std::string(iter,str.end());
174 }
175
176 inline std::string
177 dirname(const std::string &str)
178 {
179         std::string::const_iterator iter;
180
181         if(str.end()[-1]==ETL_DIRECTORY_SEPERATOR)
182                 iter=str.end()-2;
183         else
184                 iter=str.end()-1;
185
186         for(;iter!=str.begin();iter--)
187                 if(*iter==ETL_DIRECTORY_SEPERATOR)
188                         break;
189
190         if(iter==str.begin())
191                 return ".";
192
193         return std::string(str.begin(),iter);
194 }
195
196 inline bool
197 is_absolute_path(const std::string &path)
198 {
199 #ifdef WIN32
200         if(path.size()>=3 && path[1]==':' && (path[2]=='\\' || path[2]=='/'))
201                 return true;
202 #endif  
203         if(!path.empty() && path[0]==ETL_DIRECTORY_SEPERATOR)
204                 return true;
205         return false;
206 }
207
208 inline std::string
209 unix_to_local_path(const std::string &path)
210 {
211         std::string ret;
212         std::string::const_iterator iter;
213         for(iter=path.begin();iter!=path.end();iter++)
214                 switch(*iter)
215                 {
216                 case '/':
217                         ret+=ETL_DIRECTORY_SEPERATOR;
218                         break;
219                 case '~':
220                         ret+='~';
221                         break;
222                 default:
223                         ret+=*iter;
224                         break;
225                 }
226         return ret;
227 }
228
229 inline std::string
230 current_working_directory()
231 {
232         char dir[256];
233         std::string ret(getcwd(dir,sizeof(dir)));
234         return ret;
235 }
236
237 inline std::string
238 get_root_from_path(std::string path)
239 {
240         std::string ret;
241         std::string::const_iterator iter;
242         
243         for(iter=path.begin();iter!=path.end();++iter)
244         {
245                 if(*iter==ETL_DIRECTORY_SEPERATOR)
246                         break;
247                 ret+=*iter;
248         }
249         //if(iter!=path.end())
250                 ret+=ETL_DIRECTORY_SEPERATOR;
251         return ret;
252 }
253
254 inline std::string
255 remove_root_from_path(std::string path)
256 {
257         while(!path.empty())
258         {
259                 if(path[0]==ETL_DIRECTORY_SEPERATOR)
260                 {
261                         path.erase(path.begin());
262                         return path;
263                 }
264                 path.erase(path.begin());
265         }
266         return path;
267 }
268
269 inline std::string
270 cleanup_path(std::string path)
271 {
272         std::string ret;
273
274         while(basename(path)==".")path=dirname(path);
275         
276         while(!path.empty())
277         {
278                 std::string dir(get_root_from_path(path));
279                 if((dir=="../" || dir=="..\\") && ret.size())
280                 {
281                         ret=dirname(ret)+ETL_DIRECTORY_SEPERATOR;
282                 }
283                 else if((dir!="./" && dir!=".\\") && dir!=".")
284                 {
285                         ret+=dir;
286                 }
287                 path=remove_root_from_path(path);
288         }
289         
290         // Remove any trailing directory seperators
291         if(ret.size() && ret[ret.size()-1]==ETL_DIRECTORY_SEPERATOR)
292         {
293                 ret.erase(ret.begin()+ret.size()-1);
294         }
295         return ret;
296 }
297
298 inline std::string
299 absolute_path(std::string path)
300 {
301         std::string ret(current_working_directory());
302         
303         if(path.empty())
304                 return cleanup_path(ret);
305         if(is_absolute_path(path))
306                 return cleanup_path(path);
307         // TODO: This needs to be written
308         return cleanup_path(ret+ETL_DIRECTORY_SEPERATOR+path);
309 }
310
311 inline std::string
312 relative_path(std::string curr_path,std::string dest_path)
313 {       
314         // If dest_path is already a relative path,
315         // then there is no need to do anything.
316         if(!is_absolute_path(dest_path))
317                 dest_path=absolute_path(dest_path);
318         else
319                 dest_path=cleanup_path(dest_path);
320         
321         if(!is_absolute_path(curr_path))
322                 curr_path=absolute_path(curr_path);
323         else
324                 curr_path=cleanup_path(curr_path);
325
326 #ifdef WIN32
327         // If we are on windows and the dest path is on a different drive,
328         // then there is no way to make a relative path to it.
329         if(dest_path.size()>=3 && dest_path[1]==':' && dest_path[0]!=curr_path[0])
330         {
331                 return dest_path;
332         }
333 #endif
334
335         if(curr_path==dirname(dest_path))
336         {
337                 return basename(dest_path);
338         }
339         
340         while(!dest_path.empty() && !curr_path.empty() && get_root_from_path(dest_path)==get_root_from_path(curr_path))
341         {
342                 dest_path=remove_root_from_path(dest_path);
343                 curr_path=remove_root_from_path(curr_path);
344         }
345
346         while(!curr_path.empty())
347         {
348                 dest_path=std::string("..")+ETL_DIRECTORY_SEPERATOR+dest_path;
349                 curr_path=remove_root_from_path(curr_path);
350         }
351         
352         return dest_path;
353 }
354
355 _ETL_END_NAMESPACE
356
357 /* === E N D =============================================================== */
358
359 #endif