Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

idep_cdep.cxx

Go to the documentation of this file.
00001 // idep_cdep.c
00002 #include "idep_compiledep.h"
00003 #include "idep_namearray.h"
00004 #include "idep_nameindexmap.h"
00005 #include "idep_binrel.h"
00006 #include "idep_string.h"
00007 #include "idep_filedepiter.h"
00008 #include "idep_tokeniter.h"
00009 
00010 #include <ctype.h>    // isascii() isspace()
00011 #include <cstring>    // strlen()
00012 #include <fstream>    // ifstream
00013 #include <iostream>   
00014 #include <cassert>
00015 
00016                 // -*-*-*- static functions -*-*-*-
00017 
00018 static std::ostream& err(std::ostream& orr) 
00019 {
00020     return orr << "Error: ";
00021 }
00022 
00023 static const char *stripDotSlash(const char *originalPath)
00024 {
00025     if (originalPath) {
00026         while ('.' == originalPath[0] && '/' == originalPath[1]) {
00027             originalPath += 2;
00028         }
00029     }
00030     return originalPath;
00031 }
00032 
00033 static int isAbsolutePath(const char *originalPath)
00034 {
00035     return '/' == *originalPath;
00036 }
00037 
00038 static int isAsciiFile(const char *fileName)
00039 {
00040     enum { NO = 0, YES = 1 };
00041     std::ifstream in(fileName);
00042     if (!in) {
00043         return NO;
00044     }
00045 
00046     // check for non-ascii characters
00047     char c;
00048     while (in && !in.get(c).eof()) {
00049        if (!isascii(c)) {
00050           return NO;
00051        }
00052     }
00053     return YES;
00054 }
00055 
00056 typedef void (idep_CompileDep::*Func)(const char *);
00057 static void loadFromStream(std::istream& in, idep_CompileDep *dep, Func add) 
00058 { 
00059     assert(in);
00060     for (idep_TokenIter it(in); it; ++it) {
00061         if ('#' == *it()) {                     // strip comment if any
00062              while (it && '\n' != *it()) { 
00063                 ++it;
00064             }
00065             continue;                           // either !it or '\n' 
00066         }
00067         if ('\n' != *it()) {            
00068             (dep->*add)(it());
00069         }
00070     }
00071 }
00072 
00073 static int loadFromFile(const char *file, idep_CompileDep *dep, Func add) 
00074 {
00075     enum { BAD = -1, GOOD = 0 };
00076     if (!isAsciiFile(file)) {
00077         return BAD;
00078     }
00079     std::ifstream in(file);
00080     assert(in);
00081     loadFromStream(in, dep, add); 
00082     return GOOD;
00083 }
00084 
00085 static const char *search(idep_String *s, const char *includeDir, 
00086                                                             const char *file) 
00087 {
00088     assert(!isAbsolutePath(file));
00089     (*s = includeDir) += file;
00090     const char *dirFile = stripDotSlash(*s);
00091     return std::ifstream(dirFile) ? dirFile : 0;
00092 }
00093 
00094 static const char *search(idep_String *s, const idep_NameArray& a, 
00095                                                             const char *file)
00096 {
00097     if (isAbsolutePath(file)) {
00098         *s = file;
00099         const char *absFile = *s;
00100         return std::ifstream(absFile) ? absFile : 0;
00101     }
00102 
00103     const char *dirFile = 0;
00104     for (int i = 0; i < a.length(); ++i) {
00105         dirFile = search(s, a[i], file);
00106         if (dirFile) {
00107             break;
00108         }
00109     }
00110 
00111     return dirFile;
00112 }
00113 
00114                 // -*-*-*- static recursive functions -*-*-*-
00115 
00116 // The following temporary, file-scope pointer variables are used 
00117 // only during the recursive calls of a single static function, getDep()
00118 // in order to avoid the unnecessary time and space costs of passing 
00119 // several invariant arguments on the program stack.
00120 
00121 static idep_BinRel *s_dependencies_p;   // set just before first call to getDep
00122 static idep_NameIndexMap *s_files_p;    // set just before first call to getDep
00123 static idep_NameArray *s_includes_p;    // set just before first call to getDep
00124 static int s_recurse;                   // set just before first call to getDep
00125 static std::ostream *s_err_p;                // set just before first call to getDep
00126 
00127 static int getDep (int index) 
00128 {
00129     enum { BAD = -1, GOOD = 0 } status = GOOD;
00130      
00131     idep_String buffer; // string buffer, do not use directly
00132     idep_FileDepIter it((*s_files_p)[index]);
00133 
00134     for (; it; ++it) {
00135         const char *dirFile = search(&buffer, *s_includes_p, it());
00136         if (!dirFile) {
00137             err(*s_err_p) << "include directory for file \""
00138                  << it() << "\" not specified." << std::endl; 
00139             status = BAD;
00140             continue;
00141         }
00142 
00143         int length = s_files_p->length();
00144         int otherIndex = s_files_p->entry(dirFile);
00145 
00146         if (s_files_p->length() > length) {
00147             // first time looking at this file
00148             s_dependencies_p->appendEntry();
00149                 
00150             if (s_recurse && getDep(otherIndex)) {
00151                 status = BAD;
00152             }
00153         }
00154 
00155         s_dependencies_p->set(index, otherIndex, 1);
00156     }
00157 
00158     if (!it.isValidFile()) {
00159        err(*s_err_p) << "unable to open file \""
00160          << (*s_files_p)[index] << "\" for read access." << std::endl; 
00161         status = BAD;
00162     }
00163 
00164     return status;
00165 }
00166                     
00167                 // -*-*-*- idep_CompileDep_i -*-*-*-
00168 
00169 struct idep_CompileDep_i {
00170     idep_NameArray d_includeDirectories;      // e.g., ".", "/usr/include"
00171     idep_NameArray d_rootFiles;               // files to be analyzed
00172 
00173     idep_NameIndexMap *d_fileNames_p;         // keys for relation
00174     idep_BinRel *d_dependencies_p;            // compile-time dependencies
00175     int d_numRootFiles;                       // number of roots in relation
00176 
00177     idep_CompileDep_i();
00178     ~idep_CompileDep_i();
00179 };
00180 
00181 idep_CompileDep_i::idep_CompileDep_i() 
00182 : d_fileNames_p(0)
00183 , d_dependencies_p(0)
00184 , d_numRootFiles(-1)
00185 {
00186 }
00187 
00188 idep_CompileDep_i::~idep_CompileDep_i() 
00189 {
00190     delete d_fileNames_p;
00191     delete d_dependencies_p;
00192 }
00193 
00194                 // -*-*-*- idep_CompileDep -*-*-*-
00195 
00196 idep_CompileDep::idep_CompileDep() 
00197 : d_this(new idep_CompileDep_i)
00198 {
00199 }
00200 
00201 idep_CompileDep::~idep_CompileDep()
00202 {
00203     delete d_this;
00204 }
00205 
00206 void idep_CompileDep::addIncludeDirectory(const char *dirName)
00207 {
00208     if (*dirName) {
00209         int len = strlen(dirName);
00210         if ('/' == dirName[len-1]) {            // already ends in '/'
00211             d_this->d_includeDirectories.append(dirName);               
00212         }
00213         else {                                  // add trailing '/'
00214             char *buf = new char[len+2];
00215             memcpy(buf, dirName, len);
00216             buf[len] = '/';
00217             buf[len+1] = '\0';
00218             d_this->d_includeDirectories.append(buf);           
00219             delete [] buf;
00220         }
00221     }
00222 }
00223 
00224 int idep_CompileDep::readIncludeDirectories(const char *file)
00225 {
00226     return loadFromFile(file, this, &idep_CompileDep::addIncludeDirectory); 
00227 }
00228 
00229 void idep_CompileDep::addRootFile(const char *fileName)
00230 {
00231     d_this->d_rootFiles.append(fileName);               
00232 }
00233 
00234 int idep_CompileDep::readRootFiles(const char *file)
00235 {
00236     return loadFromFile(file, this, &idep_CompileDep::addRootFile); 
00237 }
00238 
00239 void idep_CompileDep::inputRootFiles()
00240 {
00241     if (std::cin) {
00242         loadFromStream(std::cin, this, &idep_CompileDep::addRootFile); 
00243         // cin.clear(0);             // reset eof for standard input
00244         std::cin.clear();             // reset eof for standard input
00245     }
00246 }
00247 
00248 int idep_CompileDep::calculate(std::ostream& orr, int recursionFlag)
00249 {
00250     enum { BAD = -1, GOOD = 0 } status = GOOD;
00251 
00252     // clean up any previous calculation artifacts
00253     delete d_this->d_fileNames_p;       
00254     delete d_this->d_dependencies_p;
00255 
00256     // allocate new data structures for this calculation
00257     d_this->d_fileNames_p = new idep_NameIndexMap;
00258     d_this->d_dependencies_p = new idep_BinRel;     
00259     d_this->d_numRootFiles = 0;
00260 
00261 
00262     // place all root files at the start of the relation
00263     int i;
00264     for (i = 0; i < d_this->d_rootFiles.length(); ++i) {
00265         idep_String s;
00266         const char *file = d_this->d_rootFiles[i];
00267         const char *dirFile = search(&s, d_this->d_includeDirectories, file);
00268 
00269         if (!dirFile) {
00270             err(orr) << "root file \"" << file 
00271                     << "\" not found." << std::endl;
00272             status = BAD;
00273         }
00274         else if (d_this->d_fileNames_p->add(dirFile) < 0) { 
00275             err(orr) << "root file \"" << file 
00276                     << "\" redundantly specified." << std::endl;
00277             status = BAD;
00278         }
00279         else {
00280             ++d_this->d_numRootFiles;
00281             d_this->d_dependencies_p->appendEntry();
00282         }
00283     }
00284         
00285     // We must now investigate the compile-time dependencies for each 
00286     // translation unit recursively.  First we will set up several
00287     // file-scope pointers to reduce recursive overhead.
00288 
00289     s_dependencies_p = d_this->d_dependencies_p;
00290     s_files_p = d_this->d_fileNames_p;
00291     s_includes_p = &d_this->d_includeDirectories;
00292     s_recurse = recursionFlag;
00293     s_err_p = &orr;
00294 
00295     // Each translation unit forms the root of a tree of dependencies.
00296     // We will visit each node only once, recording the results as we go.
00297     // Initially, only the translation units are present in the relation.
00298 
00299     for (i = 0; i < d_this->d_numRootFiles; ++i) {
00300         const char *name = (*d_this->d_fileNames_p)[i];
00301         if (getDep(i)) {
00302             err(orr) << "could not determine all dependencies for \""
00303                     << name << "\"." << std::endl;
00304             status = BAD;
00305         }
00306     }
00307 
00308     if (recursionFlag) {
00309         d_this->d_dependencies_p->makeTransitive();
00310     }
00311 
00312     return status;
00313 }
00314 
00315                 // -*-*-*- free operators -*-*-*-
00316 
00317 std::ostream &operator<<(std::ostream& o, const idep_CompileDep&(dep)) 
00318 {
00319     const char *INDENT = "    ";
00320     for (idep_RootFileIter rit(dep); rit; ++rit) {
00321         idep_NameArray a;
00322         o << rit() << std::endl;
00323         for (idep_HeaderFileIter hit(rit); hit; ++hit) {
00324             if (isAbsolutePath(hit())) {
00325                 a.append(hit());
00326             }  
00327             else {
00328                 o << INDENT << hit() << std::endl;
00329             }
00330         }
00331         for (int i = 0; i < a.length(); ++i) {
00332            o << INDENT << a[i] << std::endl;
00333         }
00334         o << std::endl;
00335     }
00336     return o;
00337 }
00338 
00339                 // -*-*-*- idep_RootFileIter_i -*-*-*-
00340 
00341 struct idep_RootFileIter_i {
00342     const idep_CompileDep_i& d_dep;
00343     int d_index;
00344 
00345     idep_RootFileIter_i(const idep_CompileDep_i& dep);
00346 };
00347 
00348 idep_RootFileIter_i::idep_RootFileIter_i(const idep_CompileDep_i& dep)
00349 : d_dep(dep)
00350 , d_index(0)
00351 {
00352 }
00353 
00354                 // -*-*-*- idep_RootFileIter -*-*-*-
00355 
00356 idep_RootFileIter::idep_RootFileIter(const idep_CompileDep& dep) 
00357 : d_this(new idep_RootFileIter_i(*dep.d_this))
00358 {
00359 }
00360 
00361 idep_RootFileIter::~idep_RootFileIter()
00362 {
00363     delete d_this;
00364 }
00365 
00366 void idep_RootFileIter::operator++() 
00367 {
00368     assert(*this);
00369     ++d_this->d_index;
00370 }
00371  
00372 idep_RootFileIter::operator const void *() const
00373 {
00374     return d_this->d_index < d_this->d_dep.d_numRootFiles ? this : 0;
00375 }
00376  
00377 const char *idep_RootFileIter::operator()() const
00378 {
00379     return (*d_this->d_dep.d_fileNames_p)[d_this->d_index];
00380 }
00381 
00382                 // -*-*-*- idep_HeaderFileIter_i -*-*-*-
00383 
00384 struct idep_HeaderFileIter_i {
00385     const idep_RootFileIter_i& d_iter;
00386     int d_index;
00387 
00388     idep_HeaderFileIter_i(const idep_RootFileIter_i& iter);
00389 };
00390 
00391 idep_HeaderFileIter_i::idep_HeaderFileIter_i(const idep_RootFileIter_i& iter) 
00392 : d_iter(iter)
00393 , d_index(-1)
00394 {
00395 }
00396 
00397                 // -*-*-*- idep_HeaderFileIter -*-*-*-
00398 
00399 idep_HeaderFileIter::idep_HeaderFileIter(const idep_RootFileIter& iter) 
00400 : d_this(new idep_HeaderFileIter_i(*iter.d_this))
00401 {
00402     ++*this;
00403 }
00404 
00405 idep_HeaderFileIter::~idep_HeaderFileIter()
00406 {
00407     delete d_this;
00408 }
00409 
00410 
00411 void idep_HeaderFileIter::operator++() 
00412 {
00413     assert(*this);
00414     idep_BinRel *rel = d_this->d_iter.d_dep.d_dependencies_p;
00415     
00416     do {
00417         ++d_this->d_index;
00418     }
00419     while (   d_this->d_index < rel->length() 
00420            && !rel->get(d_this->d_iter.d_index, d_this->d_index)
00421     );
00422 }
00423  
00424 idep_HeaderFileIter::operator const void *() const
00425 {
00426     idep_BinRel *rel = d_this->d_iter.d_dep.d_dependencies_p;
00427     return d_this->d_index < rel->length() ? this : 0;
00428 }
00429  
00430 const char *idep_HeaderFileIter::operator()() const
00431 {
00432     return (*d_this->d_iter.d_dep.d_fileNames_p)[d_this->d_index];
00433 }
00434 

Generated on Mon Feb 15 11:06:48 2010 for loon by  doxygen 1.3.9.1