sbuild-util.cc

Go to the documentation of this file.
00001 /* Copyright © 2005-2006  Roger Leigh <rleigh@debian.org>
00002  *
00003  * schroot is free software; you can redistribute it and/or modify it
00004  * under the terms of the GNU General Public License as published by
00005  * the Free Software Foundation; either version 2 of the License, or
00006  * (at your option) any later version.
00007  *
00008  * schroot is distributed in the hope that it will be useful, but
00009  * WITHOUT ANY WARRANTY; without even the implied warranty of
00010  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011  * General Public License for more details.
00012  *
00013  * You should have received a copy of the GNU General Public License
00014  * along with this program; if not, write to the Free Software
00015  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00016  * MA  02111-1307  USA
00017  *
00018  *********************************************************************/
00019 
00020 #include <config.h>
00021 
00022 #include "sbuild-error.h"
00023 #include "sbuild-util.h"
00024 
00025 #include <sys/types.h>
00026 #include <sys/stat.h>
00027 #include <unistd.h>
00028 
00029 using namespace sbuild;
00030 
00031 namespace
00032 {
00033 
00041   std::string remove_duplicates (std::string const& str,
00042                                  char               dup)
00043   {
00044     std::string ret;
00045 
00046     for (std::string::size_type pos = 0;
00047          pos < str.length();
00048          ++pos)
00049       {
00050         ret += str[pos];
00051         if (str[pos] == dup)
00052           {
00053             while (pos + 1 < str.length() &&
00054                    str[pos + 1] == dup)
00055               ++pos;
00056           }
00057       }
00058 
00059     return ret;
00060   }
00061 
00062 }
00063 
00064 std::string
00065 sbuild::basename (std::string name,
00066                   char        separator)
00067 {
00068   // Remove trailing separators
00069   std::string::size_type cur = name.length();
00070   while (cur - 1 != 0 && name[cur - 1] == separator)
00071     --cur;
00072   name.resize(cur);
00073 
00074   // Find last separator
00075   std::string::size_type pos = name.rfind(separator);
00076 
00077   std::string ret;
00078   if (pos == std::string::npos)
00079     ret = name; // No separators
00080   else if (pos == 0 && name.length() == 1 && name[0] == separator)
00081     ret = separator; // Only separators
00082   else
00083     ret = name.substr(pos + 1); // Basename only
00084 
00085   return remove_duplicates(ret, separator);
00086 }
00087 
00088 std::string
00089 sbuild::dirname (std::string name,
00090                  char        separator)
00091 {
00092   // Remove trailing separators
00093   std::string::size_type cur = name.length();
00094   while (cur - 1 != 0 && name[cur - 1] == separator)
00095     --cur;
00096   name.resize(cur);
00097 
00098   // Find last separator
00099   std::string::size_type pos = name.rfind(separator);
00100 
00101   std::string ret;
00102   if (pos == std::string::npos)
00103     ret = "."; // No directory components
00104   else if (pos == 0)
00105     ret = separator;
00106   else
00107     ret = name.substr(0, pos); // Dirname part
00108 
00109   return remove_duplicates(ret, separator);
00110 }
00111 
00112 std::string
00113 sbuild::normalname (std::string name,
00114                     char        separator)
00115 {
00116   // Remove trailing separators
00117   std::string::size_type cur = name.length();
00118   while (cur - 1 != 0 && name[cur - 1] == separator)
00119     --cur;
00120   name.resize(cur);
00121 
00122   return remove_duplicates(name, separator);
00123 }
00124 
00125 bool
00126 sbuild::is_absname (std::string const& name)
00127 {
00128   if (name.empty() || name[0] != '/')
00129     return false;
00130   else
00131     return true;
00132 }
00133 
00134 std::string
00135 sbuild::string_list_to_string (sbuild::string_list const& list,
00136                                std::string const&         separator)
00137 {
00138   std::string ret;
00139 
00140   for (string_list::const_iterator cur = list.begin();
00141        cur != list.end();
00142        ++cur)
00143     {
00144       ret += *cur;
00145       if (cur + 1 != list.end())
00146         ret += separator;
00147     }
00148 
00149   return ret;
00150 }
00151 
00152 string_list
00153 sbuild::split_string (std::string const& value,
00154                       std::string const& separator)
00155 {
00156   string_list ret;
00157 
00158   // Skip any separators at the start
00159   std::string::size_type last_pos =
00160     value.find_first_not_of(separator, 0);
00161   // Find first separator.
00162   std::string::size_type pos = value.find_first_of(separator, last_pos);
00163 
00164   while (pos !=std::string::npos || last_pos != std::string::npos)
00165     {
00166       // Add to list
00167       ret.push_back(value.substr(last_pos, pos - last_pos));
00168       // Find next
00169       last_pos = value.find_first_not_of(separator, pos);
00170       pos = value.find_first_of(separator, last_pos);
00171     }
00172 
00173   return ret;
00174 }
00175 
00176 std::wstring
00177 sbuild::widen_string (std::string const& str,
00178                       std::locale        locale)
00179 {
00180   typedef std::codecvt<wchar_t, char, mbstate_t> codecvt_type;
00181   codecvt_type const& cvt = std::use_facet<codecvt_type>(locale);
00182   mbstate_t state;
00183   const char *cbegin = str.data(), *cend = str.data() + str.size(), *cnext;
00184   wchar_t *wcnext;
00185   wchar_t wcbuf[80];
00186   std::wstring ret;
00187 
00188   std::memset(&state, 0, sizeof(mbstate_t));
00189 
00190   while (1)
00191     {
00192       std::codecvt_base::result res =
00193         cvt.in(state,
00194                cbegin, cend, cnext,
00195                wcbuf, wcbuf + (sizeof(wcbuf) / sizeof(wcbuf[0])), wcnext);
00196 
00197       if (res == std::codecvt_base::ok || res == std::codecvt_base::partial)
00198         {
00199           ret += std::wstring(wcbuf, wcnext);
00200           if (cend == cnext)
00201             break;
00202         }
00203       else if (res == std::codecvt_base::noconv)
00204         {
00205           ret += std::wstring(cbegin, cend);
00206           break;
00207         }
00208       else if (res == std::codecvt_base::error)
00209         {
00210           throw std::runtime_error
00211             ("A character set conversion failed.  Please report this bug.");
00212           break;
00213         }
00214       else
00215         break;
00216 
00217       cbegin = cnext;
00218     }
00219 
00220   return ret;
00221 }
00222 
00223 std::string
00224 sbuild::narrow_string (std::wstring const& str,
00225                        std::locale         locale)
00226 {
00227   typedef std::codecvt<wchar_t, char, mbstate_t> codecvt_type;
00228   codecvt_type const& cvt = std::use_facet<codecvt_type>(locale);
00229   mbstate_t state;
00230   const wchar_t *wcbegin = str.data(), *wcend = str.data() + str.size(), *wcnext;
00231   char *cnext;
00232   char cbuf[80];
00233   std::string ret;
00234 
00235   std::memset(&state, 0, sizeof(mbstate_t));
00236 
00237   while (1)
00238     {
00239       std::codecvt_base::result res =
00240         cvt.out(state,
00241                 wcbegin, wcend, wcnext,
00242                 cbuf, cbuf + (sizeof(cbuf) / sizeof(cbuf[0])), cnext);
00243 
00244       if (res == std::codecvt_base::ok || res == std::codecvt_base::partial)
00245         {
00246           ret += std::string(cbuf, cnext);
00247           if (wcend == wcnext)
00248             break;
00249         }
00250       else if (res == std::codecvt_base::noconv)
00251         {
00252           ret += std::string(wcbegin, wcend);
00253           break;
00254         }
00255       else if (res == std::codecvt_base::error)
00256         {
00257           throw std::runtime_error
00258             ("A character set conversion failed.  Please report this bug.");
00259           break;
00260         }
00261       else
00262         break;
00263 
00264       wcbegin = wcnext;
00265     }
00266 
00267   return ret;
00268 }
00269 
00270 std::string
00271 sbuild::find_program_in_path (std::string const& program,
00272                               std::string const& path,
00273                               std::string const& prefix)
00274 {
00275   if (program.find_first_of('/') != std::string::npos)
00276     return program;
00277 
00278   string_list dirs = split_string(path, std::string(1, ':'));
00279 
00280   for (string_list::const_iterator dir = dirs.begin();
00281        dir != dirs.end();
00282        ++dir)
00283     {
00284       std::string realname = *dir + '/' + program;
00285       std::string absname;
00286       if (prefix.length() > 0)
00287         {
00288           absname = prefix;
00289           if (dir->length() > 0 && (*dir)[0] != '/')
00290             absname += '/';
00291         }
00292       absname += realname;
00293 
00294       struct stat statbuf;
00295       if (stat(absname.c_str(), &statbuf) == 0)
00296         {
00297           if (S_ISREG(statbuf.st_mode) &&
00298               access (absname.c_str(), X_OK) == 0)
00299             return realname;
00300         }
00301     }
00302 
00303   return "";
00304 }
00305 
00306 char **
00307 sbuild::string_list_to_strv (string_list const& str)
00308 {
00309   char **ret = new char *[str.size() + 1];
00310 
00311   for (string_list::size_type i = 0;
00312        i < str.size();
00313        ++i)
00314     {
00315       ret[i] = new char[str[i].length() + 1];
00316       std::strcpy(ret[i], str[i].c_str());
00317     }
00318   ret[str.size()] = 0;
00319 
00320   return ret;
00321 }
00322 
00323 
00324 void
00325 sbuild::strv_delete (char **strv)
00326 {
00327   for (char **pos = strv; pos != 0 && *pos != 0; ++pos)
00328     delete *pos;
00329   delete[] strv;
00330 }
00331 
00332 int
00333 sbuild::exec (std::string const& file,
00334               string_list const& command,
00335               environment const& env)
00336 {
00337   char **argv = string_list_to_strv(command);
00338   char **envp = env.get_strv();
00339   int status;
00340 
00341   if ((status = execve(file.c_str(), argv, envp)) != 0)
00342     {
00343       strv_delete(argv);
00344       strv_delete(envp);
00345     }
00346 
00347   return status;
00348 }

Generated on Sat Jan 27 16:11:03 2007 for schroot by  doxygen 1.5.1