1 /* =========================================================================
2 ** Extended Template and Library
3 ** stringf Procedure Implementation
6 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
7 ** Copyright (c) 2007 Chris Moore
9 ** This package is free software; you can redistribute it and/or
10 ** modify it under the terms of the GNU General Public License as
11 ** published by the Free Software Foundation; either version 2 of
12 ** the License, or (at your option) any later version.
14 ** This package is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 ** General Public License for more details.
19 ** === N O T E S ===========================================================
21 ** This is an internal header file, included by other ETL headers.
22 ** You should not attempt to use it directly.
24 ** ========================================================================= */
26 /* === S T A R T =========================================================== */
28 #ifndef __ETL__STRINGF_H
29 #define __ETL__STRINGF_H
31 /* === H E A D E R S ======================================================= */
42 /* === M A C R O S ========================================================= */
44 #ifndef ETL_STRPRINTF_MAX_LENGTH
45 #define ETL_STRPRINTF_MAX_LENGTH (800)
49 #define POPEN_BINARY_READ_TYPE "rb"
50 #define POPEN_BINARY_WRITE_TYPE "wb"
52 #define POPEN_BINARY_READ_TYPE "r"
53 #define POPEN_BINARY_WRITE_TYPE "w"
56 #ifdef __ETL_HAS__VSNPRINTF
57 #ifndef __ETL_HAS_VSNPRINTF
58 #define vnsprintf _vnsprintf
59 #define __ETL_HAS_VSNPRINTF
63 /* === T Y P E D E F S ===================================================== */
67 #if defined(__APPLE__) || defined(__CYGWIN__) || defined(_WIN32)
70 #define ETL_NO_THROW throw()
73 // Prefer prototypes from glibc headers, since defining them ourselves
74 // works around glibc security mechanisms
76 #ifdef __ETL_HAS_VASPRINTF // This is the preferred method
78 extern int vasprintf(char **,const char *,va_list)ETL_NO_THROW;
82 # ifdef __ETL_HAS_VSNPRINTF // This is the secondary method
84 extern int vsnprintf(char *,size_t,const char*,va_list)ETL_NO_THROW;
90 #ifdef __ETL_HAS_VSSCANF
92 extern int vsscanf(const char *,const char *,va_list)ETL_NO_THROW;
95 #define ETL_NO_VSTRSCANF
96 #ifdef __ETL_HAS_SSCANF
98 extern int sscanf(const char *buf, const char *format, ...)ETL_NO_THROW;
107 /* === C L A S S E S & S T R U C T S ======================================= */
112 vstrprintf(const char *format, va_list args)
114 #ifdef __ETL_HAS_VASPRINTF // This is the preferred method (and safest)
117 int i=vasprintf(&buffer,format,args);
125 #ifdef __ETL_HAS_VSNPRINTF // This is the secondary method (Safe, but bulky)
126 #warning etl::vstrprintf() has a maximum size of ETL_STRPRINTF_MAX_LENGTH in this configuration.
127 #ifdef ETL_THREAD_SAFE
128 char buffer[ETL_STRPRINTF_MAX_LENGTH];
130 static char buffer[ETL_STRPRINTF_MAX_LENGTH];
132 vsnprintf(buffer,sizeof(buffer),format,args);
134 #else // This is the worst method (UNSAFE, but "works")
135 #warning Potential for Buffer-overflow bug using vsprintf
136 #define ETL_UNSAFE_STRPRINTF (true)
137 // Here, we are doubling the size of the buffer to make this case
138 // slightly more safe.
139 #ifdef ETL_THREAD_SAFE
140 char buffer[ETL_STRPRINTF_MAX_LENGTH*2];
142 static char buffer[ETL_STRPRINTF_MAX_LENGTH*2];
144 vsprintf(buffer,format,args);
151 strprintf(const char *format, ...)
154 va_start(args,format);
155 return vstrprintf(format,args);
158 #ifndef ETL_NO_VSTRSCANF
160 vstrscanf(const std::string &data, const char*format, va_list args)
162 return vsscanf(data.c_str(),format,args);
166 strscanf(const std::string &data, const char*format, ...)
169 va_start(args,format);
170 return vstrscanf(data, format,args);
174 #if defined (__ETL_HAS_SSCANF) && defined (__GNUC__)
175 #define strscanf(data,format,...) sscanf(data.c_str(),format,__VA_ARGS__)
180 #define stratof(X) (atof((X).c_str()))
181 #define stratoi(X) (atoi((X).c_str()))
184 basename(const std::string &str)
186 std::string::const_iterator iter;
188 if(str.size() == 1 && str[0] == ETL_DIRECTORY_SEPARATOR)
191 if(str.end()[-1]==ETL_DIRECTORY_SEPARATOR)
196 for(;iter!=str.begin();iter--)
197 if(*iter==ETL_DIRECTORY_SEPARATOR)
200 if (*iter==ETL_DIRECTORY_SEPARATOR)
203 if(str.end()[-1]==ETL_DIRECTORY_SEPARATOR)
204 return std::string(iter,str.end()-1);
206 return std::string(iter,str.end());
210 dirname(const std::string &str)
212 std::string::const_iterator iter;
214 if(str.size() == 1 && str[0] == ETL_DIRECTORY_SEPARATOR)
217 if(str.end()[-1]==ETL_DIRECTORY_SEPARATOR)
222 for(;iter!=str.begin();iter--)
223 if(*iter==ETL_DIRECTORY_SEPARATOR)
226 if(iter==str.begin())
228 if (*iter==ETL_DIRECTORY_SEPARATOR)
234 return std::string(str.begin(),iter);
237 // filename_extension("/f.e/d.c") => ".c"
239 filename_extension(const std::string &str)
241 std::string base = basename(str);
242 std::string::size_type pos = base.find_last_of('.');
243 if (pos == std::string::npos) return std::string();
244 return base.substr(pos);
247 // filename_sans_extension("/f.e/d.c") => "/f.e/d"
249 filename_sans_extension(const std::string &str)
251 std::string base = basename(str);
252 std::string::size_type pos = base.find_last_of('.');
253 if (pos == std::string::npos) return str;
254 std::string dir = dirname(str);
255 if (dir == ".") return base.substr(0,pos);
256 return dir + ETL_DIRECTORY_SEPARATOR + base.substr(0,pos);
260 is_absolute_path(const std::string &path)
263 if(path.size()>=3 && path[1]==':' && (path[2]=='\\' || path[2]=='/'))
266 if(!path.empty() && path[0]==ETL_DIRECTORY_SEPARATOR)
272 unix_to_local_path(const std::string &path)
275 std::string::const_iterator iter;
276 for(iter=path.begin();iter!=path.end();iter++)
280 ret+=ETL_DIRECTORY_SEPARATOR;
293 current_working_directory()
296 std::string ret(getcwd(dir,sizeof(dir)));
301 get_root_from_path(std::string path)
304 std::string::const_iterator iter;
306 for(iter=path.begin();iter!=path.end();++iter)
308 if(*iter==ETL_DIRECTORY_SEPARATOR)
312 //if(iter!=path.end())
313 ret+=ETL_DIRECTORY_SEPARATOR;
318 remove_root_from_path(std::string path)
322 if(path[0]==ETL_DIRECTORY_SEPARATOR)
324 path.erase(path.begin());
327 path.erase(path.begin());
333 cleanup_path(std::string path)
337 while(basename(path)=="."&&path.size()!=1)path=dirname(path);
341 std::string dir(get_root_from_path(path));
342 if((dir=="../" || dir=="..\\") && ret.size())
345 if (*(ret.end()-1)!=ETL_DIRECTORY_SEPARATOR)
346 ret+=ETL_DIRECTORY_SEPARATOR;
348 else if((dir!="./" && dir!=".\\") && dir!=".")
350 path=remove_root_from_path(path);
352 if (ret.size()==0)ret+='.';
354 // Remove any trailing directory separators
355 if(ret.size() && ret[ret.size()-1]==ETL_DIRECTORY_SEPARATOR)
356 ret.erase(ret.begin()+ret.size()-1);
361 absolute_path(std::string path)
363 std::string ret(current_working_directory());
366 return cleanup_path(ret);
367 if(is_absolute_path(path))
368 return cleanup_path(path);
369 return cleanup_path(ret+ETL_DIRECTORY_SEPARATOR+path);
373 relative_path(std::string curr_path,std::string dest_path)
375 // If dest_path is already a relative path,
376 // then there is no need to do anything.
377 if(!is_absolute_path(dest_path))
378 dest_path=absolute_path(dest_path);
380 dest_path=cleanup_path(dest_path);
382 if(!is_absolute_path(curr_path))
383 curr_path=absolute_path(curr_path);
385 curr_path=cleanup_path(curr_path);
388 // If we are on windows and the dest path is on a different drive,
389 // then there is no way to make a relative path to it.
390 if(dest_path.size()>=3 && dest_path[1]==':' && dest_path[0]!=curr_path[0])
394 if(curr_path==dirname(dest_path))
395 return basename(dest_path);
397 while(!dest_path.empty() && !curr_path.empty() && get_root_from_path(dest_path)==get_root_from_path(curr_path))
399 dest_path=remove_root_from_path(dest_path);
400 curr_path=remove_root_from_path(curr_path);
403 while(!curr_path.empty())
405 dest_path=std::string("..")+ETL_DIRECTORY_SEPARATOR+dest_path;
406 curr_path=remove_root_from_path(curr_path);
414 /* === E N D =============================================================== */