メインページ   クラス階層   構成   ファイル一覧   構成メンバ   ファイルメンバ  

file-ops.cc

解説を見る。
00001 /*
00002 
00003 Copyright (C) 1996, 1997 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 2, or (at your option) any
00010 later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, write to the Free
00019 Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include <cerrno>
00028 #include <cstdio>
00029 #include <cstdlib>
00030 #include <cstring>
00031 
00032 #include <iostream>
00033 #include <vector>
00034 
00035 #ifdef HAVE_SYS_TYPES_H
00036 #include <sys/types.h>
00037 #endif
00038 
00039 #ifdef HAVE_UNISTD_H
00040 #include <unistd.h>
00041 #endif
00042 
00043 #include "file-ops.h"
00044 #include "oct-env.h"
00045 #include "oct-passwd.h"
00046 #include "pathlen.h"
00047 #include "statdefs.h"
00048 #include "str-vec.h"
00049 
00050 #define NOT_SUPPORTED(nm) \
00051   nm ": not supported on this system"
00052 
00053 #if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) \
00054      && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
00055 char file_ops::dir_sep_char = '\\';
00056 std::string file_ops::dir_sep_str ("\\");
00057 #else
00058 char file_ops::dir_sep_char = '/';
00059 std::string file_ops::dir_sep_str ("/");
00060 #endif
00061 
00062 #if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) \
00063      && defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
00064 std::string file_ops::dir_sep_chars ("/\\");
00065 #else
00066 std::string file_ops::dir_sep_chars (file_ops::dir_sep_str);
00067 #endif
00068 
00069 // We provide a replacement for mkdir().
00070 
00071 int
00072 file_ops::mkdir (const std::string& name, mode_t mode)
00073 {
00074   std::string msg;
00075   return mkdir (name, mode, msg);
00076 }
00077 
00078 int
00079 file_ops::mkdir (const std::string& name, mode_t mode, std::string& msg)
00080 {
00081   msg = std::string ();
00082 
00083   int status = -1;
00084 
00085 #if defined (HAVE_MKDIR)
00086 
00087 #if defined (MKDIR_TAKES_ONE_ARG)
00088   status = ::mkdir (name.c_str ());
00089 #else
00090   status = ::mkdir (name.c_str (), mode);
00091 #endif
00092 
00093   if (status < 0)
00094     {
00095       using namespace std;
00096       msg = ::strerror (errno);
00097     }
00098 #else
00099   msg = NOT_SUPPORTED ("mkdir");
00100 #endif
00101 
00102   return status;
00103 }
00104 
00105 // I don't know how to emulate this on systems that don't provide it.
00106 
00107 int
00108 file_ops::mkfifo (const std::string& name, mode_t mode)
00109 {
00110   std::string msg;
00111   return mkfifo (name, mode, msg);
00112 }
00113 
00114 int
00115 file_ops::mkfifo (const std::string& name, mode_t mode, std::string& msg)
00116 {
00117   msg = std::string ();
00118 
00119   int status = -1;
00120 
00121 #if defined (HAVE_MKFIFO)
00122   status = ::mkfifo (name.c_str (), mode);
00123 
00124   if (status < 0)
00125     {
00126       using namespace std;
00127       msg = ::strerror (errno);
00128     }
00129 #else
00130   msg = NOT_SUPPORTED ("mkfifo");
00131 #endif
00132 
00133   return status;
00134 }
00135 
00136 // I don't know how to emulate this on systems that don't provide it.
00137 
00138 int
00139 file_ops::link (const std::string& old_name, const std::string& new_name)
00140 {
00141   std::string msg;
00142   return link (old_name, new_name, msg);
00143 }
00144 
00145 int
00146 file_ops::link (const std::string& old_name,
00147                 const std::string& new_name, std::string& msg)
00148 {
00149   msg = std::string ();
00150 
00151   int status = -1;
00152 
00153 #if defined (HAVE_LINK)
00154   status = ::link (old_name.c_str (), new_name.c_str ());
00155 
00156   if (status < 0)
00157     {
00158       using namespace std;
00159       msg = ::strerror (errno);
00160     }
00161 #else
00162   msg = NOT_SUPPORTED ("link");
00163 #endif
00164 
00165   return status;
00166 }
00167 
00168 // I don't know how to emulate this on systems that don't provide it.
00169 
00170 int
00171 file_ops::symlink (const std::string& old_name, const std::string& new_name)
00172 {
00173   std::string msg;
00174   return symlink (old_name, new_name, msg);
00175 }
00176 
00177 int
00178 file_ops::symlink (const std::string& old_name,
00179                    const std::string& new_name, std::string& msg)
00180 {
00181   msg = std::string ();
00182 
00183   int status = -1;
00184 
00185 #if defined (HAVE_SYMLINK)
00186 
00187   OCTAVE_LOCAL_BUFFER (char, old_nm, old_name.length ());
00188   OCTAVE_LOCAL_BUFFER (char, new_nm, new_name.length ());
00189 
00190   strcpy (old_nm, old_name.c_str ());
00191   strcpy (new_nm, new_name.c_str ());
00192 
00193   status = ::symlink (old_nm, new_nm);
00194 
00195   if (status < 0)
00196     {
00197       using namespace std;
00198       msg = ::strerror (errno);
00199     }
00200 #else
00201   msg = NOT_SUPPORTED ("symlink");
00202 #endif
00203 
00204   return status;
00205 }
00206 
00207 // We provide a replacement for rename().
00208 
00209 int
00210 file_ops::readlink (const std::string& path, std::string& result)
00211 {
00212   std::string msg;
00213   return readlink (path, result, msg);
00214 }
00215 
00216 int
00217 file_ops::readlink (const std::string& path, std::string& result,
00218                     std::string& msg)
00219 {
00220   int status = -1;
00221 
00222   msg = std::string ();
00223 
00224 #if defined (HAVE_READLINK)
00225   char buf[MAXPATHLEN+1];
00226 
00227   OCTAVE_LOCAL_BUFFER (char, p, path.length ());
00228 
00229   strcpy (p, path.c_str ());
00230 
00231   status = ::readlink (p, buf, MAXPATHLEN);
00232 
00233   if (status < 0)
00234     {
00235       using namespace std;
00236       msg = ::strerror (errno);
00237     }
00238   else
00239     {
00240       buf[status] = '\0';
00241       result = std::string (buf);
00242       status = 0;
00243     }
00244 #else
00245   msg = NOT_SUPPORTED ("rename");
00246 #endif
00247 
00248   return status;
00249 }
00250 
00251 // We provide a replacement for rename().
00252 
00253 int
00254 file_ops::rename (const std::string& from, const std::string& to)
00255 {
00256   std::string msg;
00257   return rename (from, to, msg);
00258 }
00259 
00260 int
00261 file_ops::rename (const std::string& from, const std::string& to,
00262                   std::string& msg)
00263 {
00264   int status = -1;
00265 
00266   msg = std::string ();
00267 
00268 #if defined (HAVE_RENAME)
00269   status = ::rename (from.c_str (), to.c_str ());
00270 
00271   if (status < 0)
00272     {
00273       using namespace std;
00274       msg = ::strerror (errno);
00275     }
00276 #else
00277   msg = NOT_SUPPORTED ("rename");
00278 #endif
00279 
00280   return status;
00281 }
00282 
00283 // We provide a replacement for rmdir().
00284 
00285 int
00286 file_ops::rmdir (const std::string& name)
00287 {
00288   std::string msg;
00289   return rmdir (name, msg);
00290 }
00291 
00292 int
00293 file_ops::rmdir (const std::string& name, std::string& msg)
00294 {
00295   msg = std::string ();
00296 
00297   int status = -1;
00298 
00299 #if defined (HAVE_RMDIR)
00300   status = ::rmdir (name.c_str ());
00301 
00302   if (status < 0)
00303     {
00304       using namespace std;
00305       msg = ::strerror (errno);
00306     }
00307 #else
00308   msg = NOT_SUPPORTED ("rmdir");
00309 #endif
00310 
00311   return status;
00312 }
00313 
00314 // We provide a replacement for tempnam().
00315 
00316 std::string
00317 file_ops::tempnam (const std::string& dir, const std::string& pfx)
00318 {
00319   std::string msg;
00320   return tempnam (dir, pfx, msg);
00321 }
00322 
00323 std::string
00324 file_ops::tempnam (const std::string& dir, const std::string& pfx,
00325                    std::string& msg)
00326 {
00327   msg = std::string ();
00328 
00329   std::string retval;
00330   
00331   const char *pdir = dir.empty () ? 0 : dir.c_str ();
00332 
00333   const char *ppfx = pfx.empty () ? 0 : pfx.c_str ();
00334 
00335   char *tmp = ::tempnam (pdir, ppfx);
00336 
00337   if (tmp)
00338     {
00339       retval = tmp;
00340 
00341       ::free (tmp);
00342     }
00343   else
00344     {
00345       using namespace std;
00346       msg = ::strerror (errno);
00347     }
00348 
00349   return retval;
00350 }
00351 
00352 // The following tilde-expansion code was stolen and adapted from
00353 // readline.
00354 
00355 // The default value of tilde_additional_prefixes.  This is set to
00356 // whitespace preceding a tilde so that simple programs which do not
00357 // perform any word separation get desired behaviour.
00358 static const char *default_prefixes[] = { " ~", "\t~", ":~", 0 };
00359 
00360 // The default value of tilde_additional_suffixes.  This is set to
00361 // whitespace or newline so that simple programs which do not perform
00362 // any word separation get desired behaviour.
00363 static const char *default_suffixes[] = { " ", "\n", ":", 0 };
00364 
00365 // If non-null, this contains the address of a function that the
00366 // application wants called before trying the standard tilde
00367 // expansions.  The function is called with the text sans tilde, and
00368 // returns a malloc()'ed string which is the expansion, or a NULL
00369 // pointer if the expansion fails.
00370 file_ops::tilde_expansion_hook file_ops::tilde_expansion_preexpansion_hook = 0;
00371 
00372 // If non-null, this contains the address of a function to call if the
00373 // standard meaning for expanding a tilde fails.  The function is
00374 // called with the text (sans tilde, as in "foo"), and returns a
00375 // malloc()'ed string which is the expansion, or a NULL pointer if
00376 // there is no expansion.
00377 file_ops::tilde_expansion_hook file_ops::tilde_expansion_failure_hook = 0;
00378 
00379 // When non-null, this is a NULL terminated array of strings which are
00380 // duplicates for a tilde prefix.  Bash uses this to expand `=~' and
00381 // `:~'.
00382 string_vector file_ops::tilde_additional_prefixes = default_prefixes;
00383 
00384 // When non-null, this is a NULL terminated array of strings which
00385 // match the end of a username, instead of just "/".  Bash sets this
00386 // to `:' and `=~'.
00387 string_vector file_ops::tilde_additional_suffixes = default_suffixes;
00388 
00389 // Find the start of a tilde expansion in S, and return the index
00390 // of the tilde which starts the expansion.  Place the length of the
00391 // text which identified this tilde starter in LEN, excluding the
00392 // tilde itself.
00393 
00394 static size_t
00395 tilde_find_prefix (const std::string& s, size_t& len)
00396 {
00397   len = 0;
00398 
00399   size_t s_len = s.length ();
00400 
00401   if (s_len == 0 || s[0] == '~')
00402     return 0;
00403 
00404   string_vector prefixes = file_ops::tilde_additional_prefixes;
00405 
00406   if (! prefixes.empty ())
00407     {
00408       for (size_t i = 0; i < s_len; i++)
00409         {
00410           for (int j = 0; j < prefixes.length (); j++)
00411             {
00412               size_t pfx_len = prefixes[j].length ();
00413 
00414               if (prefixes[j].compare (s.substr (i, pfx_len)) == 0)
00415                 {
00416                   len = pfx_len - 1;
00417                   return i + len;
00418                 }
00419             }
00420         }
00421     }
00422 
00423   return s_len;
00424 }
00425 
00426 // Find the end of a tilde expansion in S, and return the index
00427 // of the character which ends the tilde definition.
00428 
00429 static size_t
00430 tilde_find_suffix (const std::string& s)
00431 {
00432   size_t s_len = s.length ();
00433 
00434   string_vector suffixes = file_ops::tilde_additional_suffixes;
00435 
00436   size_t i = 0;
00437 
00438   for ( ; i < s_len; i++)
00439     {
00440       if (s[i] == file_ops::dir_sep_char)
00441         break;
00442 
00443       if (! suffixes.empty ())
00444         {
00445           for (int j = 0; j < suffixes.length (); j++)
00446             {
00447               size_t sfx_len = suffixes[j].length ();
00448 
00449               if (suffixes[j].compare (s.substr (i, sfx_len)) == 0)
00450                 return i;
00451             }
00452         }
00453     }
00454 
00455   return i;
00456 }
00457 
00458 // Take FNAME and return the tilde prefix we want expanded.
00459 
00460 static std::string
00461 isolate_tilde_prefix (const std::string& fname)
00462 {
00463   size_t f_len = fname.length ();
00464 
00465   size_t len = 1;
00466 
00467   while (len < f_len && fname[len] != file_ops::dir_sep_char)
00468     len++;
00469 
00470   return fname.substr (1, len);
00471 }
00472 
00473 // Do the work of tilde expansion on FILENAME.  FILENAME starts with a
00474 // tilde.
00475 
00476 static std::string
00477 tilde_expand_word (const std::string& filename)
00478 {
00479   size_t f_len = filename.length ();
00480 
00481   if (f_len == 0 || filename[0] != '~')
00482     return filename;
00483 
00484   // A leading `~/' or a bare `~' is *always* translated to the value
00485   // of $HOME or the home directory of the current user, regardless of
00486   // any preexpansion hook.
00487 
00488   if (f_len == 1 || filename[1] == file_ops::dir_sep_char)
00489     return octave_env::get_home_directory () + filename.substr (1);
00490 
00491   std::string username = isolate_tilde_prefix (filename);
00492 
00493   size_t user_len = username.length ();
00494 
00495   std::string dirname;
00496 
00497   if (file_ops::tilde_expansion_preexpansion_hook)
00498     {
00499       std::string expansion
00500         = file_ops::tilde_expansion_preexpansion_hook (username);
00501 
00502       if (! expansion.empty ())
00503         return expansion + filename.substr (user_len+1);
00504     }
00505 
00506   // No preexpansion hook, or the preexpansion hook failed.  Look in the
00507   // password database.
00508 
00509   octave_passwd pw = octave_passwd::getpwnam (username);
00510 
00511   if (! pw)
00512     {
00513       // If the calling program has a special syntax for expanding tildes,
00514       // and we couldn't find a standard expansion, then let them try.
00515 
00516       if (file_ops::tilde_expansion_failure_hook)
00517         {
00518           std::string expansion
00519             = file_ops::tilde_expansion_failure_hook (username);
00520 
00521           if (! expansion.empty ())
00522             dirname = expansion + filename.substr (user_len+1);
00523         }
00524 
00525       // If we don't have a failure hook, or if the failure hook did not
00526       // expand the tilde, return a copy of what we were passed.
00527 
00528       if (dirname.length () == 0)
00529         dirname = filename;
00530     }
00531   else
00532     dirname = pw.dir () + filename.substr (user_len+1);
00533 
00534   return dirname;
00535 }
00536 
00537 // If NAME has a leading ~ or ~user, Unix-style, expand it to the
00538 // user's home directory.  If no ~, or no <pwd.h>, just return NAME.
00539 
00540 std::string
00541 file_ops::tilde_expand (const std::string& name)
00542 {
00543   std::string result;
00544 
00545   size_t name_len = name.length ();
00546 
00547   // Scan through S expanding tildes as we come to them.
00548 
00549   size_t pos = 0;
00550 
00551   while (1)
00552     {
00553       if (pos > name_len)
00554         break;
00555 
00556       size_t len;
00557 
00558       // Make START point to the tilde which starts the expansion.
00559 
00560       size_t start = tilde_find_prefix (name.substr (pos), len);
00561 
00562       result.append (name.substr (pos, start));
00563 
00564       // Advance STRING to the starting tilde.
00565 
00566       pos += start;
00567 
00568       // Make FINI be the index of one after the last character of the
00569       // username.
00570 
00571       size_t fini = tilde_find_suffix (name.substr (pos));
00572 
00573       // If both START and FINI are zero, we are all done.
00574 
00575       if (! (start || fini))
00576         break;
00577 
00578       // Expand the entire tilde word, and copy it into RESULT.
00579 
00580       std::string tilde_word = name.substr (pos, fini);
00581 
00582       pos += fini;
00583 
00584       std::string expansion = tilde_expand_word (tilde_word);
00585 
00586       result.append (expansion);
00587     }
00588 
00589   return result;
00590 }
00591 
00592 // A vector version of the above.
00593 
00594 string_vector
00595 file_ops::tilde_expand (const string_vector& names)
00596 {
00597   string_vector retval;
00598 
00599   int n = names.length ();
00600 
00601   retval.resize (n);
00602 
00603   for (int i = 0; i < n; i++)
00604     retval[i] = file_ops::tilde_expand (names[i]);
00605 
00606   return retval;
00607 }
00608 
00609 int
00610 file_ops::umask (mode_t mode)
00611 {
00612 #if defined (HAVE_UMASK)
00613   return ::umask (mode);
00614 #else
00615   return 0;
00616 #endif
00617 }
00618 
00619 int
00620 file_ops::unlink (const std::string& name)
00621 {
00622   std::string msg;
00623   return unlink (name, msg);
00624 }
00625 
00626 int
00627 file_ops::unlink (const std::string& name, std::string& msg)
00628 {
00629   msg = std::string ();
00630 
00631   int status = -1;
00632 
00633 #if defined (HAVE_UNLINK)
00634   status = ::unlink (name.c_str ());
00635 
00636   if (status < 0)
00637     {
00638       using namespace std;
00639       msg = ::strerror (errno);
00640     }
00641 #else
00642   msg = NOT_SUPPORTED ("unlink");
00643 #endif
00644 
00645   return status;
00646 }
00647 
00648 bool
00649 file_ops::is_dir_sep (char c)
00650 {
00651   return dir_sep_chars.find (c) != NPOS;
00652 }
00653 
00654 /*
00655 ;;; Local Variables: ***
00656 ;;; mode: C++ ***
00657 ;;; End: ***
00658 */

Wed Dec 29 11:51:34 2004に生成されました。 doxygen1.2.18
SEO [PR] 爆速!無料ブログ 無料ホームページ開設 無料ライブ放送