Fix bugs in previous commit that caused FTBFS in synfig and ETL FTBFS with older...
[synfig.git] / ETL / tags / ETL_0_04_08 / ETL / 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  extern int vsnprintf(char *,size_t,const char*,va_list)ETL_NO_THROW;
57 # endif
58
59 #endif
60
61 #ifdef HAVE_VSSCANF
62 extern int vsscanf(const char *,const char *,va_list)ETL_NO_THROW;
63 #else
64 #define ETL_NO_VSTRSCANF
65 #ifdef HAVE_SSCANF
66 extern int sscanf(const char *buf, const char *format, ...)ETL_NO_THROW;
67 #endif
68 #endif
69
70 #include <unistd.h>
71
72 _ETL_END_CDECLS
73
74 /* === C L A S S E S & S T R U C T S ======================================= */
75
76 _ETL_BEGIN_NAMESPACE
77
78 inline std::string
79 vstrprintf(const char *format, va_list args)
80 {
81 #ifdef HAVE_VASPRINTF   // This is the prefered method (and safest)
82         char *buffer;
83         std::string ret;
84         vasprintf(&buffer,format,args);
85         ret=buffer;
86         free(buffer);
87         return ret;
88 #else
89 #ifdef HAVE_VSNPRINTF   // This is the secondary method (Safe, but bulky)
90 #warning etl::vstrprintf() has a maximum size of ETL_STRPRINTF_MAX_LENGTH in this configuration.
91 #ifdef ETL_THREAD_SAFE
92         char buffer[ETL_STRPRINTF_MAX_LENGTH];
93 #else
94         static char buffer[ETL_STRPRINTF_MAX_LENGTH];
95 #endif
96         vsnprintf(buffer,sizeof(buffer),format,args);
97         return buffer;
98 #else                                   // This is the worst method (UNSAFE, but "works")
99 #warning Potential for Buffer-overflow bug using vsprintf
100 #define ETL_UNSAFE_STRPRINTF    (true)
101 // Here, we are doubling the size of the buffer to make this case
102 // slightly more safe.
103 #ifdef ETL_THREAD_SAFE
104         char buffer[ETL_STRPRINTF_MAX_LENGTH*2];
105 #else
106         static char buffer[ETL_STRPRINTF_MAX_LENGTH*2];
107 #endif
108         vsprintf(buffer,format,args);
109         return buffer;
110 #endif
111 #endif
112 }
113
114 inline std::string
115 strprintf(const char *format, ...)
116 {
117         va_list args;
118         va_start(args,format);
119         return vstrprintf(format,args);
120 }
121
122 #ifndef ETL_NO_VSTRSCANF
123 inline int
124 vstrscanf(const std::string &data, const char*format, va_list args)
125 {
126     return vsscanf(data.c_str(),format,args);
127 }
128
129 inline int
130 strscanf(const std::string &data, const char*format, ...)
131 {
132         va_list args;
133         va_start(args,format);
134         return vstrscanf(data, format,args);
135 }
136 #else
137
138 #if defined (HAVE_SSCANF) && defined (__GNUC__)
139 #define strscanf(data,format,...) sscanf(data.c_str(),format,__VA_ARGS__)
140 #endif
141 #endif
142
143
144 #define stratof(X) (atof((X).c_str()))
145 #define stratoi(X) (atoi((X).c_str()))
146
147 inline std::string
148 basename(const std::string &str)
149 {
150         std::string::const_iterator iter;
151
152         if(str.end()[-1]==ETL_DIRECTORY_SEPERATOR)
153                 iter=str.end()-2;
154         else
155                 iter=str.end()-1;
156
157         for(;iter!=str.begin();iter--)
158                 if(*iter==ETL_DIRECTORY_SEPERATOR)
159                         break;
160
161         if(iter==str.begin())
162                 return str;
163
164         iter++;
165
166         if(str.end()[-1]==ETL_DIRECTORY_SEPERATOR)
167                 return std::string(iter,str.end()-1);
168
169         return std::string(iter,str.end());
170 }
171
172 inline std::string
173 dirname(const std::string &str)
174 {
175         std::string::const_iterator iter;
176
177         if(str.end()[-1]==ETL_DIRECTORY_SEPERATOR)
178                 iter=str.end()-2;
179         else
180                 iter=str.end()-1;
181
182         for(;iter!=str.begin();iter--)
183                 if(*iter==ETL_DIRECTORY_SEPERATOR)
184                         break;
185
186         if(iter==str.begin())
187                 return ".";
188
189         return std::string(str.begin(),iter);
190 }
191
192 inline bool
193 is_absolute_path(const std::string &path)
194 {
195 #ifdef WIN32
196         if(path.size()>=3 && path[1]==':' && (path[2]=='\\' || path[2]=='/'))
197                 return true;
198 #endif  
199         if(!path.empty() && path[0]==ETL_DIRECTORY_SEPERATOR)
200                 return true;
201         return false;
202 }
203
204 inline std::string
205 unix_to_local_path(const std::string &path)
206 {
207         std::string ret;
208         std::string::const_iterator iter;
209         for(iter=path.begin();iter!=path.end();iter++)
210                 switch(*iter)
211                 {
212                 case '/':
213                         ret+=ETL_DIRECTORY_SEPERATOR;
214                         break;
215                 case '~':
216                         ret+='~';
217                         break;
218                 default:
219                         ret+=*iter;
220                         break;
221                 }
222         return ret;
223 }
224
225 inline std::string
226 current_working_directory()
227 {
228         char dir[256];
229         std::string ret(getcwd(dir,sizeof(dir)));
230         return ret;
231 }
232
233 inline std::string
234 get_root_from_path(std::string path)
235 {
236         std::string ret;
237         std::string::const_iterator iter;
238         
239         for(iter=path.begin();iter!=path.end();++iter)
240         {
241                 if(*iter==ETL_DIRECTORY_SEPERATOR)
242                         break;
243                 ret+=*iter;
244         }
245         //if(iter!=path.end())
246                 ret+=ETL_DIRECTORY_SEPERATOR;
247         return ret;
248 }
249
250 inline std::string
251 remove_root_from_path(std::string path)
252 {
253         while(!path.empty())
254         {
255                 if(path[0]==ETL_DIRECTORY_SEPERATOR)
256                 {
257                         path.erase(path.begin());
258                         return path;
259                 }
260                 path.erase(path.begin());
261         }
262         return path;
263 }
264
265 inline std::string
266 cleanup_path(std::string path)
267 {
268         std::string ret;
269
270         while(basename(path)==".")path=dirname(path);
271         
272         while(!path.empty())
273         {
274                 std::string dir(get_root_from_path(path));
275                 if((dir=="../" || dir=="..\\") && ret.size())
276                 {
277                         ret=dirname(ret)+ETL_DIRECTORY_SEPERATOR;
278                 }
279                 else if((dir!="./" && dir!=".\\") && dir!=".")
280                 {
281                         ret+=dir;
282                 }
283                 path=remove_root_from_path(path);
284         }
285         
286         // Remove any trailing directory seperators
287         if(ret.size() && ret[ret.size()-1]==ETL_DIRECTORY_SEPERATOR)
288         {
289                 ret.erase(ret.begin()+ret.size()-1);
290         }
291         return ret;
292 }
293
294 inline std::string
295 absolute_path(std::string path)
296 {
297         std::string ret(current_working_directory());
298         
299         if(path.empty())
300                 return cleanup_path(ret);
301         if(is_absolute_path(path))
302                 return cleanup_path(path);
303         // TODO: This needs to be written
304         return cleanup_path(ret+ETL_DIRECTORY_SEPERATOR+path);
305 }
306
307 inline std::string
308 relative_path(std::string curr_path,std::string dest_path)
309 {       
310         // If dest_path is already a relative path,
311         // then there is no need to do anything.
312         if(!is_absolute_path(dest_path))
313                 dest_path=absolute_path(dest_path);
314         else
315                 dest_path=cleanup_path(dest_path);
316         
317         if(!is_absolute_path(curr_path))
318                 curr_path=absolute_path(curr_path);
319         else
320                 curr_path=cleanup_path(curr_path);
321
322 #ifdef WIN32
323         // If we are on windows and the dest path is on a different drive,
324         // then there is no way to make a relative path to it.
325         if(dest_path.size()>=3 && dest_path[1]==':' && dest_path[0]!=curr_path[0])
326         {
327                 return dest_path;
328         }
329 #endif
330
331         if(curr_path==dirname(dest_path))
332         {
333                 return basename(dest_path);
334         }
335         
336         while(!dest_path.empty() && !curr_path.empty() && get_root_from_path(dest_path)==get_root_from_path(curr_path))
337         {
338                 dest_path=remove_root_from_path(dest_path);
339                 curr_path=remove_root_from_path(curr_path);
340         }
341
342         while(!curr_path.empty())
343         {
344                 dest_path=std::string("..")+ETL_DIRECTORY_SEPERATOR+dest_path;
345                 curr_path=remove_root_from_path(curr_path);
346         }
347         
348         return dest_path;
349 }
350
351 _ETL_END_NAMESPACE
352
353 /* === E N D =============================================================== */
354
355 #endif