file_system.cc

Go to the documentation of this file.
00001 /*
00002    The lestes compiler suite
00003    Copyright (C) 2002, 2003, 2004, 2005 Miroslav Tichy
00004    Copyright (C) 2002, 2003, 2004, 2005 Petr Zika
00005    Copyright (C) 2002, 2003, 2004, 2005 Vojtech Hala
00006    Copyright (C) 2002, 2003, 2004, 2005 Jiri Kosina
00007    Copyright (C) 2002, 2003, 2004, 2005 Pavel Sanda
00008    Copyright (C) 2002, 2003, 2004, 2005 Jan Zouhar
00009    Copyright (C) 2002, 2003, 2004, 2005 Rudolf Thomas
00010 
00011    This program is free software; you can redistribute it and/or modify
00012    it under the terms of the GNU General Public License as published by
00013    the Free Software Foundation; version 2 of the License.
00014 
00015    This program is distributed in the hope that it will be useful,
00016    but WITHOUT ANY WARRANTY; without even the implied warranty of
00017    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018    GNU General Public License for more details.
00019 
00020    See the full text of the GNU General Public License version 2, and
00021    the limitations in the file doc/LICENSE.
00022 
00023    By accepting the license the licensee waives any and all claims
00024    against the copyright holder(s) related in whole or in part to the
00025    work, its use, and/or the inability to use it.
00026  
00027  */
00028 /*! \file
00029   \brief File system binding.
00030   
00031   Definition of file_system class providing access to the file system.
00032   \author pt
00033 */
00034 #include <lestes/common.hh>
00035 #include <lestes/std/list.hh>
00036 #include <lestes/std/istream_wrapper.hh>
00037 #include <lestes/lang/cplus/lex/file_system.hh>
00038 #include <lestes/lang/cplus/lex/named_istream.hh>
00039 
00040 #include <fstream>
00041 #include <iostream>
00042 
00043 package(lestes);
00044 package(lang);
00045 package(cplus);
00046 package(lex);
00047 
00048 using namespace ::std;
00049 
00050 /*!
00051   Creates the object.
00052 */
00053 file_system::file_system(void):
00054         search_paths(lstrings_type::create())
00055 {
00056         // an extra path starting from base
00057         search_paths->push_back(lstring(""));
00058 }
00059 
00060 /*!
00061   Splits string into sequence of parts separated by delimiter.
00062   If delimiter is found at the beginning, or at the end of the string,
00063   or two delimiters are adjacent, an empty string is added to the appropriate place.
00064   So empty string results in empty sequence, while string containing sole
00065   delimiter results in sequence containing two empty strings.
00066   \param str  The string to split.
00067   \param delimiter  The delimiter to separate the parts.
00068   \return  The sequence of parts, in the original order, without the delimiters.
00069 */
00070 ptr< file_system::lstrings_type > file_system::split(const lstring &str, hchar delimiter)
00071 {
00072         ptr< lstrings_type > v = lstrings_type::create();
00073         
00074         lstring::size_type len = str.length();
00075         
00076         // no data means no output
00077         if (!len) return v;
00078         
00079         lstring::size_type i, j;
00080 
00081         i = 0;
00082         
00083         // the condition is set so that find is called even after
00084         // the delimiter was found at the end of the string
00085         while (i <= len) {
00086                 j = str.find(delimiter,i);
00087                 if (j == lstring::npos)
00088                         // pretend delimiter just after the end
00089                         j = len;
00090 
00091                 // the part starts at i and ends at j - 1
00092                 v->push_back(str.substr(i,j-i));
00093                 // skip the delimiter
00094                 i = j + 1;
00095         }
00096 
00097         return v;
00098 }
00099 
00100 /*!
00101   Classifies the name according to its properties.
00102   Distinguishes relative and absolute path and file names.
00103   \param str  The string to classify.
00104   \return  The kind of name represented by the string.
00105 */
00106 file_system::name_type file_system::classify_name(const lstring &name)
00107 {
00108         ptr<lstrings_type> parts = split(name,'/');
00109         ulint len = parts->size();
00110         
00111         if (!len) return NM_PATH_REL;
00112 
00113         bool absolute = parts->at(0).length() == 0;
00114         bool pathname = parts->at(len - 1).length() == 0;
00115         
00116         // check nonempty directory names
00117         for (ulint i = 1; i < len - 1; i++) {
00118                 if (parts->at(i).length() == 0)
00119                         return NM_INVALID;
00120         }
00121 
00122         if (absolute) {
00123                 return pathname ? NM_PATH_ABS : NM_FILE_ABS;
00124         }
00125           
00126         return pathname ? NM_PATH_REL : NM_FILE_REL;
00127 }
00128 
00129 /*!
00130   Opens a stream for the given file name or standard input.
00131   Relative file name is searched for in the working directory.
00132   \param name  Absolute or relative file name, "" used for stdin.
00133   \return  The opened stream or NULL for error (file not found or not accessible).
00134 */
00135 ptr<named_istream> file_system::open_file(const lstring &name)
00136 {
00137         if (name.length() == 0) {
00138                 ptr<istream_wrapper> iw = istream_wrapper::create(&::std::cin,false);
00139                 return named_istream::create(iw,"","<stdin>");
00140         }
00141         
00142         name_type nt = classify_name(name);
00143         
00144         if (nt != NM_FILE_REL && nt != NM_FILE_ABS)
00145                 return NULL;
00146         
00147         fstream *f = new fstream();
00148         bool error = false;
00149         try {
00150                 f->open(name.c_str(),ios_base::in);
00151                 error = f->fail();
00152         } catch (...) {
00153                 error = true;
00154         }
00155 
00156         if (error) {
00157                 delete f;
00158                 return NULL;
00159         }
00160 
00161         ptr<istream_wrapper> iw = istream_wrapper::create(f,true);
00162         
00163         return named_istream::create(iw,name,name);
00164 }
00165 
00166 /*
00167 fstream *named_istream::open_fstream(const lstring &full_name)
00168 {
00169         
00170 }
00171 */
00172 /* 
00173   TODO pt different signature
00174         
00175         !
00176   Opens a stream for a given file name.
00177   Relative file name is searched for using the given paths and parent path.
00178   \param a_parent  The parent stream providing additional search path information. 
00179   \param name  Absolute or relative file name.
00180   \param system  Flag set to true for system header.
00181   \return  The opened stream or NULL fo error (file not found or not accessible).
00182 */
00183 //ptr<named_stream> file_system::find_file(const ptr<named_stream> &a_parent, const lstring &name, bool system)
00184 
00185 
00186 
00187 
00188 /*!
00189   Opens a stream for the given file name.
00190   Relative names are searched for in search paths if system is set to true, otherwise 
00191   in the given path, and in the search paths in this order.
00192   \param base_path  Absolute or relative path for the search.
00193   \param name  Absolute or relative file name of the file to open.
00194   \param system  Flag set to true for system header.
00195   \return  The opened stream or NULL for error (invalid name, file not found or not accessible).
00196 */
00197 ptr<named_istream> file_system::find_file(const lstring &base_path, const lstring &name, bool system)
00198 {
00199         name_type nt = classify_name(base_path);
00200         lassert(nt == NM_PATH_REL || nt == NM_PATH_ABS);
00201         
00202         nt = classify_name(name);
00203         
00204         if (nt == NM_FILE_ABS)
00205                 return open_file(name);
00206 
00207         if (nt != NM_FILE_REL)
00208                 return NULL;
00209         
00210         lstrings_type::iterator it = search_paths->begin(), end = search_paths->end();
00211         
00212         if (system) {
00213                 // skip the placeholder
00214                 ++it;
00215         } else {
00216                 // extra entry to enable uniform processing
00217                 (*search_paths)[0] = base_path;
00218         }
00219         
00220         fstream *f = new fstream();
00221         
00222         for ( ; it != end; ++it) {
00223                 
00224                 lstring full_name(*it);
00225                 full_name.append(name);
00226 
00227                 bool error = false;
00228 
00229                 try {
00230                         f->open(full_name.c_str(),ios_base::in);
00231                         error = f->fail();
00232                 } catch (...) {
00233                         error = true;
00234                 }
00235 
00236                 if (!error) {
00237                         ptr<istream_wrapper> iw = istream_wrapper::create(f,true);
00238                         return named_istream::create(iw,full_name,full_name);
00239                 }
00240         }
00241         
00242         // the resource is not in use
00243         delete f;
00244 
00245         // failure
00246         return NULL;
00247 }
00248 
00249 /*!
00250   Adds search path for file searching.
00251   \param a_path  A path to add.
00252   \return false  If the path is invalid.
00253 */
00254 bool file_system::add_search_path(const lstring &a_path)
00255 {
00256         name_type nt = classify_name(a_path);
00257         lstring path(a_path); 
00258         
00259         switch (nt) {
00260                 case NM_INVALID:
00261                         return false;
00262                 case NM_FILE_REL:
00263                 case NM_FILE_ABS:
00264                         path.append("/");
00265                         // fall through
00266                 case NM_PATH_REL:
00267                 case NM_PATH_ABS:
00268                         search_paths->push_back(path);
00269                         break;
00270                 default:
00271                         lassert2(false,"You should never get here");
00272         }
00273         return true;
00274 }
00275 
00276 /*!
00277   Marks the object.
00278 */
00279 void file_system::gc_mark(void)
00280 {
00281         search_paths.gc_mark();
00282 	::lestes::std::object::gc_mark();
00283 }
00284 
00285 /*!
00286   Returns new instance.
00287   \return  The new instance.
00288 */
00289 ptr<file_system> file_system::create(void)
00290 {
00291         return new file_system();
00292 }
00293 
00294 end_package(lex);
00295 end_package(cplus);
00296 end_package(lang);
00297 end_package(lestes);
00298 
00299 /* vim: set ft=lestes : */

Generated on Mon Feb 12 18:22:33 2007 for lestes by doxygen 1.5.1-20070107