- Main Page
- Related Pages
- Classes
- Files

# _stringf.h

Go to the documentation of this file.

    00001 /* =========================================================================
    00002 ** Extended Template and Library
    00003 ** stringf Procedure Implementation
    00004 ** $Id$
    00005 **
    00006 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
    00007 ** Copyright (c) 2007 Chris Moore
    00008 **
    00009 ** This package is free software; you can redistribute it and/or
    00010 ** modify it under the terms of the GNU General Public License as
    00011 ** published by the Free Software Foundation; either version 2 of
    00012 ** the License, or (at your option) any later version.
    00013 **
    00014 ** This package is distributed in the hope that it will be useful,
    00015 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
    00016 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00017 ** General Public License for more details.
    00018 **
    00019 ** === N O T E S ===========================================================
    00020 **
    00021 ** This is an internal header file, included by other ETL headers.
    00022 ** You should not attempt to use it directly.
    00023 **
    00024 ** ========================================================================= */
    00025
    00026 /* === S T A R T =========================================================== */
    00027
    00028 #ifndef __ETL__STRINGF_H
    00029 #define __ETL__STRINGF_H
    00030
    00031 /* === H E A D E R S ======================================================= */
    00032
    00033 #ifndef _GNU_SOURCE
    00034 #define _GNU_SOURCE
    00035 #endif
    00036
    00037 #include <string>
    00038 #include <cstdarg>
    00039 #include <cstdlib>
    00040 #include <cstdio>
    00041
    00042 /* === M A C R O S ========================================================= */
    00043
    00044 #ifndef ETL_STRPRINTF_MAX_LENGTH
    00045 #define ETL_STRPRINTF_MAX_LENGTH    (800)
    00046 #endif
    00047
    00048 #ifdef WIN32
    00049 #define POPEN_BINARY_READ_TYPE "rb"
    00050 #define POPEN_BINARY_WRITE_TYPE "wb"
    00051 #else
    00052 #define POPEN_BINARY_READ_TYPE "r"
    00053 #define POPEN_BINARY_WRITE_TYPE "w"
    00054 #endif
    00055
    00056 /* === T Y P E D E F S ===================================================== */
    00057
    00058 _ETL_BEGIN_CDECLS
    00059
    00060 #if defined(__APPLE__) || defined(__CYGWIN__) || defined(_WIN32)
    00061 #define ETL_NO_THROW
    00062 #else
    00063 #define ETL_NO_THROW throw()
    00064 #endif
    00065
    00066 // Prefer prototypes from glibc headers, since defining them ourselves
    00067 // works around glibc security mechanisms
    00068
    00069 #ifdef HAVE_VASPRINTF   // This is the preferred method
    00070  #ifndef __GLIBC__
    00071   extern int vasprintf(char **,const char *,va_list)ETL_NO_THROW;
    00072  #endif
    00073 #else
    00074
    00075 # ifdef HAVE_VSNPRINTF  // This is the secondary method
    00076  #ifndef __GLIBC__
    00077   extern int vsnprintf(char *,size_t,const char*,va_list)ETL_NO_THROW;
    00078  #endif
    00079 # endif
    00080
    00081 #endif
    00082
    00083 #ifdef HAVE_VSSCANF
    00084  #ifndef __GLIBC__
    00085   extern int vsscanf(const char *,const char *,va_list)ETL_NO_THROW;
    00086  #endif
    00087 #else
    00088 #define ETL_NO_VSTRSCANF
    00089 #ifdef HAVE_SSCANF
    00090  #ifndef __GLIBC__
    00091   extern int sscanf(const char *buf, const char *format, ...)ETL_NO_THROW;
    00092  #endif
    00093 #endif
    00094 #endif
    00095
    00096 #include <unistd.h>
    00097
    00098 _ETL_END_CDECLS
    00099
    00100 /* === C L A S S E S & S T R U C T S ======================================= */
    00101
    00102 _ETL_BEGIN_NAMESPACE
    00103
    00104 inline std::string
    00105 vstrprintf(const char *format, va_list args)
    00106 {
    00107 #ifdef HAVE_VASPRINTF   // This is the preferred method (and safest)
    00108     char *buffer;
    00109     std::string ret;
    00110     int i=vasprintf(&buffer,format,args);
    00111     if (i>-1)
    00112     {
    00113         ret=buffer;
    00114         free(buffer);
    00115     }
    00116     return ret;
    00117 #else
    00118 #ifdef HAVE_VSNPRINTF   // This is the secondary method (Safe, but bulky)
    00119 #warning etl::vstrprintf() has a maximum size of ETL_STRPRINTF_MAX_LENGTH in this configuration.
    00120 #ifdef ETL_THREAD_SAFE
    00121     char buffer[ETL_STRPRINTF_MAX_LENGTH];
    00122 #else
    00123     static char buffer[ETL_STRPRINTF_MAX_LENGTH];
    00124 #endif
    00125     vsnprintf(buffer,sizeof(buffer),format,args);
    00126     return buffer;
    00127 #else                   // This is the worst method (UNSAFE, but "works")
    00128 #warning Potential for Buffer-overflow bug using vsprintf
    00129 #define ETL_UNSAFE_STRPRINTF    (true)
    00130 // Here, we are doubling the size of the buffer to make this case
    00131 // slightly more safe.
    00132 #ifdef ETL_THREAD_SAFE
    00133     char buffer[ETL_STRPRINTF_MAX_LENGTH*2];
    00134 #else
    00135     static char buffer[ETL_STRPRINTF_MAX_LENGTH*2];
    00136 #endif
    00137     vsprintf(buffer,format,args);
    00138     return buffer;
    00139 #endif
    00140 #endif
    00141 }
    00142
    00143 inline std::string
    00144 strprintf(const char *format, ...)
    00145 {
    00146     va_list args;
    00147     va_start(args,format);
    00148     return vstrprintf(format,args);
    00149 }
    00150
    00151 #ifndef ETL_NO_VSTRSCANF
    00152 inline int
    00153 vstrscanf(const std::string &data, const char*format, va_list args)
    00154 {
    00155     return vsscanf(data.c_str(),format,args);
    00156 }
    00157
    00158 inline int
    00159 strscanf(const std::string &data, const char*format, ...)
    00160 {
    00161     va_list args;
    00162     va_start(args,format);
    00163     return vstrscanf(data, format,args);
    00164 }
    00165 #else
    00166
    00167 #if defined (HAVE_SSCANF) && defined (__GNUC__)
    00168 #define strscanf(data,format,...) sscanf(data.c_str(),format,__VA_ARGS__)
    00169 #endif
    00170 #endif
    00171
    00172
    00173 #define stratof(X) (atof((X).c_str()))
    00174 #define stratoi(X) (atoi((X).c_str()))
    00175
    00176 inline std::string
    00177 basename(const std::string &str)
    00178 {
    00179     std::string::const_iterator iter;
    00180
    00181     if(str.size() == 1 && str[0] == ETL_DIRECTORY_SEPARATOR)
    00182         return str;
    00183
    00184     if(str.end()[-1]==ETL_DIRECTORY_SEPARATOR)
    00185         iter=str.end()-2;
    00186     else
    00187         iter=str.end()-1;
    00188
    00189     for(;iter!=str.begin();iter--)
    00190         if(*iter==ETL_DIRECTORY_SEPARATOR)
    00191             break;
    00192
    00193     if (*iter==ETL_DIRECTORY_SEPARATOR)
    00194         iter++;
    00195
    00196     if(str.end()[-1]==ETL_DIRECTORY_SEPARATOR)
    00197         return std::string(iter,str.end()-1);
    00198
    00199     return std::string(iter,str.end());
    00200 }
    00201
    00202 inline std::string
    00203 dirname(const std::string &str)
    00204 {
    00205     std::string::const_iterator iter;
    00206
    00207     if(str.size() == 1 && str[0] == ETL_DIRECTORY_SEPARATOR)
    00208         return str;
    00209
    00210     if(str.end()[-1]==ETL_DIRECTORY_SEPARATOR)
    00211         iter=str.end()-2;
    00212     else
    00213         iter=str.end()-1;
    00214
    00215     for(;iter!=str.begin();iter--)
    00216         if(*iter==ETL_DIRECTORY_SEPARATOR)
    00217             break;
    00218
    00219     if(iter==str.begin())
    00220     {
    00221        if (*iter==ETL_DIRECTORY_SEPARATOR)
    00222            return "/";
    00223        else
    00224            return ".";
    00225     }
    00226
    00227     return std::string(str.begin(),iter);
    00228 }
    00229
    00230 // filename_extension("/f.e/d.c") => ".c"
    00231 inline std::string
    00232 filename_extension(const std::string &str)
    00233 {
    00234     std::string base = basename(str);
    00235     std::string::size_type pos = base.find_last_of('.');
    00236     if (pos == std::string::npos) return std::string();
    00237     return base.substr(pos);
    00238 }
    00239
    00240 // filename_sans_extension("/f.e/d.c") => "/f.e/d"
    00241 inline std::string
    00242 filename_sans_extension(const std::string &str)
    00243 {
    00244     std::string base = basename(str);
    00245     std::string::size_type pos = base.find_last_of('.');
    00246     if (pos == std::string::npos) return str;
    00247     std::string dir = dirname(str);
    00248     if (dir == ".") return base.substr(0,pos);
    00249     return dir + ETL_DIRECTORY_SEPARATOR + base.substr(0,pos);
    00250 }
    00251
    00252 inline bool
    00253 is_absolute_path(const std::string &path)
    00254 {
    00255 #ifdef WIN32
    00256     if(path.size()>=3 && path[1]==':' && (path[2]=='\\' || path[2]=='/'))
    00257         return true;
    00258 #endif
    00259     if(!path.empty() && path[0]==ETL_DIRECTORY_SEPARATOR)
    00260         return true;
    00261     return false;
    00262 }
    00263
    00264 inline std::string
    00265 unix_to_local_path(const std::string &path)
    00266 {
    00267     std::string ret;
    00268     std::string::const_iterator iter;
    00269     for(iter=path.begin();iter!=path.end();iter++)
    00270         switch(*iter)
    00271         {
    00272         case '/':
    00273             ret+=ETL_DIRECTORY_SEPARATOR;
    00274             break;
    00275         case '~':
    00276             ret+='~';
    00277             break;
    00278         default:
    00279             ret+=*iter;
    00280             break;
    00281         }
    00282     return ret;
    00283 }
    00284
    00285 inline std::string
    00286 current_working_directory()
    00287 {
    00288     char dir[256];
    00289     std::string ret(getcwd(dir,sizeof(dir)));
    00290     return ret;
    00291 }
    00292
    00293 inline std::string
    00294 get_root_from_path(std::string path)
    00295 {
    00296     std::string ret;
    00297     std::string::const_iterator iter;
    00298
    00299     for(iter=path.begin();iter!=path.end();++iter)
    00300     {
    00301         if(*iter==ETL_DIRECTORY_SEPARATOR)
    00302             break;
    00303         ret+=*iter;
    00304     }
    00305     //if(iter!=path.end())
    00306         ret+=ETL_DIRECTORY_SEPARATOR;
    00307     return ret;
    00308 }
    00309
    00310 inline std::string
    00311 remove_root_from_path(std::string path)
    00312 {
    00313     while(!path.empty())
    00314     {
    00315         if(path[0]==ETL_DIRECTORY_SEPARATOR)
    00316         {
    00317             path.erase(path.begin());
    00318             return path;
    00319         }
    00320         path.erase(path.begin());
    00321     }
    00322     return path;
    00323 }
    00324
    00325 inline std::string
    00326 cleanup_path(std::string path)
    00327 {
    00328     std::string ret;
    00329
    00330     while(basename(path)=="."&&path.size()!=1)path=dirname(path);
    00331
    00332     while(!path.empty())
    00333     {
    00334         std::string dir(get_root_from_path(path));
    00335         if((dir=="../" || dir=="..\\") && ret.size())
    00336         {
    00337             ret=dirname(ret);
    00338             if (*(ret.end()-1)!=ETL_DIRECTORY_SEPARATOR)
    00339                 ret+=ETL_DIRECTORY_SEPARATOR;
    00340         }
    00341         else if((dir!="./" && dir!=".\\") && dir!=".")
    00342             ret+=dir;
    00343         path=remove_root_from_path(path);
    00344     }
    00345     if (ret.size()==0)ret+='.';
    00346
    00347     // Remove any trailing directory separators
    00348     if(ret.size() && ret[ret.size()-1]==ETL_DIRECTORY_SEPARATOR)
    00349         ret.erase(ret.begin()+ret.size()-1);
    00350     return ret;
    00351 }
    00352
    00353 inline std::string
    00354 absolute_path(std::string path)
    00355 {
    00356     std::string ret(current_working_directory());
    00357
    00358     if(path.empty())
    00359         return cleanup_path(ret);
    00360     if(is_absolute_path(path))
    00361         return cleanup_path(path);
    00362     return cleanup_path(ret+ETL_DIRECTORY_SEPARATOR+path);
    00363 }
    00364
    00365 inline std::string
    00366 relative_path(std::string curr_path,std::string dest_path)
    00367 {
    00368     // If dest_path is already a relative path,
    00369     // then there is no need to do anything.
    00370     if(!is_absolute_path(dest_path))
    00371         dest_path=absolute_path(dest_path);
    00372     else
    00373         dest_path=cleanup_path(dest_path);
    00374
    00375     if(!is_absolute_path(curr_path))
    00376         curr_path=absolute_path(curr_path);
    00377     else
    00378         curr_path=cleanup_path(curr_path);
    00379
    00380 #ifdef WIN32
    00381     // If we are on windows and the dest path is on a different drive,
    00382     // then there is no way to make a relative path to it.
    00383     if(dest_path.size()>=3 && dest_path[1]==':' && dest_path[0]!=curr_path[0])
    00384         return dest_path;
    00385 #endif
    00386
    00387     if(curr_path==dirname(dest_path))
    00388         return basename(dest_path);
    00389
    00390     while(!dest_path.empty() && !curr_path.empty() && get_root_from_path(dest_path)==get_root_from_path(curr_path))
    00391     {
    00392         dest_path=remove_root_from_path(dest_path);
    00393         curr_path=remove_root_from_path(curr_path);
    00394     }
    00395
    00396     while(!curr_path.empty())
    00397     {
    00398         dest_path=std::string("..")+ETL_DIRECTORY_SEPARATOR+dest_path;
    00399         curr_path=remove_root_from_path(curr_path);
    00400     }
    00401
    00402     return dest_path;
    00403 }
    00404
    00405 _ETL_END_NAMESPACE
    00406
    00407 /* === E N D =============================================================== */
    00408
    00409 #endif