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

idep_adep.cxx

Go to the documentation of this file.
00001 // idep_adep.c
00002 #include "idep_aliasdep.h"
00003 #include "idep_namearray.h"
00004 #include "idep_nameindexmap.h"
00005 #include "idep_filedepiter.h"
00006 #include "idep_tokeniter.h"
00007 #include "idep_aliastable.h"
00008 #include "idep_aliasutil.h"
00009 
00010 #include <ctype.h>  // isascii() isspace()
00011 #include <cstring>  // strlen() strrchr()
00012 #include <fstream>  // ifstream
00013 #include <memory>   // memcpy()
00014 #include <iostream>
00015 #include <cassert>
00016 
00017                 // -*-*-*- static functions -*-*-*-
00018 
00019 static std::ostream& warn(std::ostream& ing)
00020 {
00021   return ing << "Warning: ";
00022 }
00023 
00024 static std::ostream& err(std::ostream& orr) 
00025 {
00026   return orr << "Error: ";
00027 }
00028 
00029 /*
00030 static const char *stripDotSlash(const char *originalPath)
00031 {
00032     if (originalPath) {
00033         while ('.' == originalPath[0] && '/' == originalPath[1]) {
00034             originalPath += 2;
00035         }
00036     }
00037     return originalPath;
00038 }
00039 */
00040 
00041 static const char *stripDir(const char *s)
00042 {
00043     if (s) {
00044         const char *slash = strrchr(s, '/');
00045         return slash ? slash + 1 : s; 
00046     }
00047     return s;   // input was null
00048 }
00049 
00050 static int isAsciiFile(const char *fileName)
00051 {
00052     enum { NO = 0, YES = 1 };
00053     std::ifstream in(fileName);
00054     if (!in) {
00055         return NO;
00056     }
00057 
00058     // check for non-ascii characters
00059     char c;
00060     while (in && !in.get(c).eof()) {
00061        if (!isascii(c)) {
00062           return NO;
00063        }
00064     }
00065     return YES;
00066 }
00067 
00068 typedef void (idep_AliasDep::*Func)(const char *);
00069 static void loadFromStream(std::istream& in, idep_AliasDep *dep, Func add) 
00070 { 
00071     assert(in);
00072     for (idep_TokenIter it(in); it; ++it) {
00073         if ('#' == *it()) {                     // strip comment if any
00074              while (it && '\n' != *it()) {
00075                 ++it;
00076             }
00077             continue;                           // either !it or '\n'
00078         }
00079         if ('\n' != *it()) {
00080             (dep->*add)(it());
00081         }
00082     }
00083 }
00084 
00085 static int loadFromFile(const char *file, idep_AliasDep *dep, Func add) 
00086 {
00087     enum { BAD = -1, GOOD = 0 };
00088     if (!isAsciiFile(file)) {
00089         return BAD;
00090     }
00091     std::ifstream in(file);
00092     assert(in);
00093     loadFromStream(in, dep, add); 
00094     return GOOD;
00095 }
00096 
00097 static char *newStrCpy(const char *name)
00098 {
00099     int size = strlen(name) + 1;
00100     char *buf = new char[size];
00101     memcpy(buf, name, size);
00102     return buf;
00103 }
00104 
00105 static char *removeSuffix(char *dirPath)
00106 {
00107     char *dot = strrchr(dirPath, '.');
00108     if (dot && !strchr(dot, '/')) {     // if '.' found in final path segment
00109         dot[0] = '\0';                  // eliminate suffix ("a/.b" -> "a/") 
00110     }
00111     return dirPath;
00112 }
00113 
00114                 // -*-*-*- idep_AliasDepIntArray -*-*-*-
00115 
00116 class idep_AliasDepIntArray {   // auxiliary class to manage array memory
00117     int *d_array_p;
00118     int d_length;               
00119     idep_AliasDepIntArray(const idep_AliasDepIntArray&);
00120     idep_AliasDepIntArray& operator=(const idep_AliasDepIntArray&);
00121   public:
00122     idep_AliasDepIntArray(int length) : // does not zero the memory!
00123                         d_array_p(new int[length]), d_length(length) {} 
00124     ~idep_AliasDepIntArray() { delete [] d_array_p; }
00125     int& operator[](int i) { return d_array_p[i]; }
00126     int length() const { return d_length; }
00127 };
00128 
00129 static void zero(idep_AliasDepIntArray *a) // non-primitive operation on array
00130 { 
00131     for (int i = 0; i < a->length(); ++i) { 
00132         (*a)[i] = 0; 
00133     }
00134 }
00135 
00136                 // -*-*-*- idep_AliasDepString -*-*-*-
00137 
00138 class idep_AliasDepString {     // auxiliary class to manage modifiable char *
00139     char *d_string_p;
00140     idep_AliasDepString(const idep_AliasDepString&);
00141     idep_AliasDepString& operator=(const idep_AliasDepString&);
00142   public:
00143     idep_AliasDepString(const char *s) : d_string_p(newStrCpy(s)){}
00144     ~idep_AliasDepString() { delete [] d_string_p; }
00145     operator char *() { return d_string_p; }
00146 };
00147 
00148                 // -*-*-*- idep_AliasDep_i -*-*-*-
00149 
00150 struct idep_AliasDep_i {
00151     idep_NameIndexMap d_ignoreNames;          // e.g., idep_compiledep.t.c
00152     idep_AliasTable d_aliases;                // e.g., my_inta -> my_intarray
00153     idep_NameIndexMap d_fileNames;            // files to be analyzed
00154 };
00155 
00156                 // -*-*-*- idep_AliasDep -*-*-*-
00157 
00158 idep_AliasDep::idep_AliasDep() 
00159 : d_this(new idep_AliasDep_i)
00160 {
00161 }
00162 
00163 idep_AliasDep::~idep_AliasDep()
00164 {
00165     delete d_this;
00166 }
00167 
00168 void idep_AliasDep::addIgnoreName(const char *fileName)
00169 {
00170     d_this->d_ignoreNames.add(fileName);                
00171 }
00172 
00173 int idep_AliasDep::readIgnoreNames(const char *file)
00174 {
00175     return loadFromFile(file, this, &idep_AliasDep::addIgnoreName); 
00176 }
00177 
00178 const char *idep_AliasDep::addAlias(const char *alias, const char *component)
00179 {
00180     return d_this->d_aliases.add(alias, component) < 0 ?
00181                                         d_this->d_aliases.lookup(alias) : 0;
00182 }
00183  
00184 int idep_AliasDep::readAliases(std::ostream& orr, const char *file)
00185 {
00186     return idep_AliasUtil::readAliases(&d_this->d_aliases, orr, file);
00187 }
00188 
00189 void idep_AliasDep::addFileName(const char *fileName)
00190 {
00191     d_this->d_fileNames.add(fileName);          
00192 }
00193 
00194 int idep_AliasDep::readFileNames(const char *file)
00195 {
00196     return loadFromFile(file, this, &idep_AliasDep::addFileName); 
00197 }
00198 
00199 void idep_AliasDep::inputFileNames()
00200 {
00201     if (std::cin) {
00202         loadFromStream(std::cin, this, &idep_AliasDep::addFileName); 
00203         std::cin.clear(std::ios::iostate(0)); // reset eof for standard input
00204     }
00205 }
00206 
00207 int idep_AliasDep::unpaired(std::ostream& out, 
00208                             std::ostream& ing, 
00209                             int suffixFlag) const
00210 {
00211     int maxLength = d_this->d_fileNames.length();
00212     idep_AliasDepIntArray hits(maxLength);  // records num files per component
00213     idep_AliasDepIntArray cmap(maxLength);  // map component to (last) file
00214     zero(&hits); 
00215     idep_NameIndexMap components;
00216     int numComponents = 0;
00217 
00218     idep_NameIndexMap printNames;   // Used to sort names for ease of use
00219                                     // during cut and past in the editor.
00220 
00221     int i;
00222     for (i = 0; i < maxLength; ++i) {
00223         idep_AliasDepString s(d_this->d_fileNames[i]);
00224 
00225         if (d_this->d_ignoreNames.lookup(s) >= 0) {
00226             continue; // ignore this file
00227         }
00228         removeSuffix(s);
00229 
00230         const char *componentName = d_this->d_aliases.lookup(s);
00231         if (!componentName) {
00232             componentName = s;
00233         }
00234 
00235         int componentIndex = components.entry(componentName);
00236         if (components.length() > numComponents) {      // new component
00237             ++numComponents;
00238             
00239         }
00240 
00241         assert(components.length() == numComponents);
00242 
00243         ++hits[componentIndex];
00244         cmap[componentIndex] = i; // overwrite with most recent index
00245     }
00246 
00247     for (i = 0; i < numComponents; ++i) {
00248         assert(hits[i] > 0);
00249         if (1 == hits[i]) {
00250             printNames.add(suffixFlag ? d_this->d_fileNames[cmap[i]] 
00251                                       : components[i]); 
00252         }
00253         if (hits[i] > 2) { 
00254             warn(ing) << "component \"" << components[i] 
00255                       << "\" consists of " << hits[i] << " files." 
00256                       << std::endl;
00257         }
00258     }
00259 
00260     // Because of library .o file name-length limitations it is often the
00261     // header which has the longer name representing the true name of the
00262     // component.  If the suffixFlag is 0, we will sort into almost
00263     // lexicographic order except that the shorter of two initially identical
00264     // names will *follow* rather than precede longer.  This ordering will 
00265     // facilitate cut and past when creating an alias file by hand in a
00266     // text editor. 
00267 
00268     int numUnpaired = printNames.length();
00269     idep_AliasDepIntArray smap(numUnpaired); 
00270     for (i = 0; i < numUnpaired; ++i) {
00271         smap[i] = i;                            // identity mapping to start
00272     }
00273 
00274     for (i = 1; i < numUnpaired; ++i) {
00275         for (int j = 0; j < numUnpaired; ++j) {
00276             int swap;
00277             if (suffixFlag) {
00278                 swap = strcmp(printNames[smap[i]], printNames[smap[j]]) < 0;
00279             }
00280             else {
00281                 int li = strlen(printNames[smap[i]]);
00282                 int lj = strlen(printNames[smap[j]]);
00283                 int len = li < lj ? li : lj;    // min length
00284                 int cmp = strncmp(printNames[smap[i]], 
00285                                   printNames[smap[j]], len); 
00286                 swap = cmp < 0 || 0 == cmp && li > lj;  // longer first if tie
00287             }
00288             if (swap) {                                 // swap if necessary
00289                 int tmp = smap[i];                
00290                 smap[i] = smap[j];
00291                 smap[j] = tmp;
00292             }
00293         }
00294     }
00295 
00296     // print out names in (almost) lexicographic order (if suffixFlag set to 0)
00297 
00298     for (i = 0; i < numUnpaired; ++i) {
00299         out << printNames[smap[i]] << std::endl;
00300     }
00301 
00302     return printNames.length();
00303 }
00304 
00305 static const char *th(int n) 
00306 {
00307     return 1 == n ? "st" : 2 == n ? "nd" : 3 == n ? "rd" : "th";
00308 }
00309 
00310 int idep_AliasDep::verify(std::ostream& orr) const
00311 {
00312     enum { IOERROR = -1, GOOD = 0 } status = GOOD;
00313     int errorCount = 0; // keep track of the number of readable faulty files
00314 
00315     int length = d_this->d_fileNames.length();
00316     for (int i = 0; i < length; ++i) {
00317         const char *path = d_this->d_fileNames[i];
00318         idep_AliasDepString c(path);
00319 
00320         if (d_this->d_ignoreNames.lookup(c) >= 0) {
00321             continue; // ignore this file
00322         }
00323 
00324         // strip off suffix and path from component file name and check aliases
00325         removeSuffix(c);
00326         const char *actualComponent = stripDir(c);
00327         const char *compAlias = d_this->d_aliases.lookup(actualComponent);
00328         const char *component = compAlias ? compAlias : actualComponent;
00329 
00330         int directiveIndex = 0;
00331         idep_FileDepIter it(path);
00332         for (; it; ++it) {
00333 
00334             ++directiveIndex;
00335 
00336             // strip off suffix and path from header name and check aliases
00337             idep_AliasDepString h(it());
00338             removeSuffix(h);
00339             const char *actualHeader = stripDir(h);
00340             const char *headerAlias = d_this->d_aliases.lookup(actualHeader);
00341             const char *header = headerAlias ? headerAlias : actualHeader;
00342 
00343             if (0 == strcmp(component, header)) { // if the same, we found it
00344                 break;
00345             }
00346         }
00347 
00348         if (!it.isValidFile()) { // if the file was never valid to begin with
00349             err(orr) << "unable to open file \""
00350                     << path << "\" for read access." << std::endl;
00351             status = IOERROR;
00352         }
00353         else if (!it) {                         // header not found
00354             err(orr) << "corresponding include directive for \"" << path 
00355                     << "\" not found."
00356                     << std::endl;
00357             ++errorCount;
00358         }
00359         else if (1 != directiveIndex) {         // header found but not first
00360             err(orr) << '"' << path 
00361                     << "\" contains corresponding include as " 
00362                     << directiveIndex << th(directiveIndex)
00363                     << " directive." << std::endl;
00364             ++errorCount;
00365         }
00366 
00367         // else there is nothing wrong here
00368     }
00369 
00370     return status == GOOD ? errorCount : status;        
00371 }
00372 
00373 
00374 int idep_AliasDep::extract(std::ostream& out, std::ostream& orr) const
00375 {
00376     enum { IOERROR = -1, GOOD = 0 } status = GOOD;
00377     enum { INVALID_INDEX = -1 };
00378     int errorCount = 0; // keep track of number of readable faulty files
00379 
00380     idep_NameIndexMap uniqueHeaders;       // used to detect multiple .c files
00381     int length = d_this->d_fileNames.length();
00382     idep_AliasDepIntArray hits(length);    // records frequency of headers
00383     zero(&hits); 
00384     idep_AliasDepIntArray hmap(length);    // index header file index in table
00385     idep_AliasDepIntArray verified(length);// verifies that guess was correct
00386     zero(&verified); 
00387     
00388     int i;
00389     for (i = 0; i < length; ++i) {
00390         hmap[i] = INVALID_INDEX;   // set valid when a suitable header is found
00391 
00392         const char *path = d_this->d_fileNames[i];
00393         idep_AliasDepString c(path);
00394 
00395         if (d_this->d_ignoreNames.lookup(c) >= 0) {
00396             continue; // ignore this file
00397         }
00398 
00399         // strip off suffix and path from component file name and check aliases
00400         removeSuffix(c);
00401         const char *actualComponent = stripDir(c);
00402         const char *compAlias = d_this->d_aliases.lookup(actualComponent);
00403         const char *component = compAlias ? compAlias : actualComponent;
00404 
00405         idep_FileDepIter it(path);      // hook up with first dependency.
00406 
00407         if (!it.isValidFile()) {        // unable to read file
00408             err(orr) << "unable to open file \""
00409                     << path << "\" for read access." << std::endl;
00410             status = IOERROR;
00411             continue;                   // nothing more we can do here
00412         }
00413 
00414         if (!it) {                      // no include directives
00415             err(orr) << '"' << path 
00416                     << "\" contains no include directives." << std::endl;
00417             ++errorCount;
00418             continue;                   // nothing more we can do here
00419         }
00420 
00421         // strip off suffix and path from header name and check aliases
00422         idep_AliasDepString h(it());
00423         removeSuffix(h);
00424         const char *actualHeader = stripDir(h);
00425         const char *headerAlias = d_this->d_aliases.lookup(actualHeader);
00426         const char *header = headerAlias ? headerAlias : actualHeader;
00427 
00428         if (0 == strcmp(component, header)) { 
00429 
00430             // At this point, we have the component name and header name
00431             // that match either because the root names were matching or 
00432             // because we found an alias that made it work.  Record this 
00433             // fact in the verified array.
00434 
00435             verified[i] = 1;
00436         }
00437         else {
00438 
00439             // We suspect this may be an alias pair, but we are not sure.
00440             // We will check to see if an alias involving this .c file
00441             // already exists.  If so, that will override and we will
00442             // not regenerate the alias.
00443 
00444             if (compAlias) {
00445                 continue;               // nothing more we can do here
00446             }
00447         }
00448 
00449         // We have no reason *not* to think this is a valid match (yet).
00450         // Record this header as being associated with the this .c file.
00451 
00452         int hIndex = uniqueHeaders.entry(header); // obtaine index of header
00453         ++hits[hIndex];                           // record frequency
00454         hmap[i] = hIndex;                         // set .c -> header index
00455     }
00456 
00457     const int FW = 25;
00458     const char *const ARROW = ">- probably correct -> ";
00459 
00460     // For each unique header, if more than one .c file names this header
00461     // int its first include directive, output a warning to the error stream.
00462 
00463     for (i = 0; i < uniqueHeaders.length(); ++i) {
00464         if (hits[i] > 1) {
00465             warn(orr) << hits[i] << " files specify \"" << uniqueHeaders[i]
00466                  << "\" as their first include directive:" << std::endl;
00467             for (int j = 0; j < length; ++j) {
00468                 if (i ==  hmap[j]) {
00469                     orr.width(FW);
00470                     orr << (verified[j] ? ARROW : "");
00471                     orr << '"' << stripDir(d_this->d_fileNames[j])
00472                        << '"' << std::endl;
00473                 }
00474             }
00475             orr << std::endl;
00476         }
00477     }
00478 
00479     // Print the non-redundant header / implementation file aliases to
00480     // the specified output stream.
00481 
00482     for (i = 0; i < length; ++i) {
00483         if (hmap[i] >= 0 && !verified[i]) {
00484            // strip off suffix and path from component file name
00485            idep_AliasDepString c(d_this->d_fileNames[i]);
00486            removeSuffix(c);
00487            out << uniqueHeaders[hmap[i]] << ' ' << c << std::endl;
00488         }
00489     }
00490 
00491     return status == GOOD ? errorCount : status;        
00492 }
00493 

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