00001
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>
00011 #include <cstring>
00012 #include <fstream>
00013 #include <iostream>
00014 #include <cassert>
00015
00016
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
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()) {
00062 while (it && '\n' != *it()) {
00063 ++it;
00064 }
00065 continue;
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
00115
00116
00117
00118
00119
00120
00121 static idep_BinRel *s_dependencies_p;
00122 static idep_NameIndexMap *s_files_p;
00123 static idep_NameArray *s_includes_p;
00124 static int s_recurse;
00125 static std::ostream *s_err_p;
00126
00127 static int getDep (int index)
00128 {
00129 enum { BAD = -1, GOOD = 0 } status = GOOD;
00130
00131 idep_String buffer;
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
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
00168
00169 struct idep_CompileDep_i {
00170 idep_NameArray d_includeDirectories;
00171 idep_NameArray d_rootFiles;
00172
00173 idep_NameIndexMap *d_fileNames_p;
00174 idep_BinRel *d_dependencies_p;
00175 int d_numRootFiles;
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
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]) {
00211 d_this->d_includeDirectories.append(dirName);
00212 }
00213 else {
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
00244 std::cin.clear();
00245 }
00246 }
00247
00248 int idep_CompileDep::calculate(std::ostream& orr, int recursionFlag)
00249 {
00250 enum { BAD = -1, GOOD = 0 } status = GOOD;
00251
00252
00253 delete d_this->d_fileNames_p;
00254 delete d_this->d_dependencies_p;
00255
00256
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
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
00286
00287
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
00296
00297
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
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
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
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
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
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