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

idep_fdepitr.cxx

Go to the documentation of this file.
00001 // idep_fdepitr.c
00002 #include "idep_filedepiter.h"
00003 
00004 #include <ctype.h>      // isspace()
00005 #include <cstring>     // strcspn()
00006 #include <memory>     // memcpy()
00007 #include <iostream>
00008 #include <fstream>    // ifstream
00009 #include <cassert> 
00010 
00011                 // -*-*-*- static functions -*-*-*-
00012 
00013 enum { MAX_LINE_LENGTH  = 2048 };       // Arbitrary maximum length for
00014                                         // line containing an include 
00015                                         // directive.  Note that other 
00016                                         // lines may be longer.
00017 
00018 static int loadBuf(std::istream& in, char *buf, int bufSize) 
00019 {
00020     enum { END_OF_INPUT = -1, SUCCESS = 0, OVERFLOWN = 1 };
00021  
00022     // The getline (std::istream) method returns the line as a string but extracts
00023     // the trailing '\n'  only if there is space to spare in the buffer.  We
00024     // need to test for this condition by placing a non-null character in the 
00025     // last position of the array before loading it.  If the last character is 
00026     // null after the read then the newline was NOT extracted.
00027  
00028     int nearEnd = bufSize - 1;
00029  
00030     buf[nearEnd] = '\n'; // anything but '\0'
00031  
00032     if (in.getline(buf, bufSize).fail()) {
00033         return END_OF_INPUT;    // nothing left
00034     }
00035  
00036     if ('\0' == buf[nearEnd]) { // line was too long
00037         char c;
00038         while (in && !in.get(c).eof() && c != '\n') { 
00039             // skip to next line
00040         }
00041         return OVERFLOWN;        // buffer contains null-terminated string
00042     }
00043 
00044     return SUCCESS; 
00045 }
00046 
00047 const char *extractDependency(char *buffer) 
00048 {
00049     // We assume we have a null terminated string that possibly contains a 
00050     // valid include directive.  We will assume that such a directive has 
00051     // the following syntax:
00052     // 
00053     // ^#[ \t]*"include"[ \t ]*[<"][ \t]*{filename}[>" \t\n]
00054     //                                   ~~~~~~~~~~
00055     // i.e.,                             ^want this
00056     //  1. The first character on the line MUST be a '#'
00057     //  2. This character may be followed by any number of spaces or tabs.
00058     //  3. The next non-whitespace char must be an 'i' followed by "nclude".
00059     //  4. This string may be followed by any number of spaces or tabs.
00060     //  5. The next character must be either a '<' or a '"'. 
00061     //  6. This character may be followed by any number of spaces or tabs.
00062     //  7. The {filename} follows and is terminated by whitespace, '>', or '"'.
00063     //
00064     // If an include directive is found, the buffer is modified and a pointer 
00065     // to the included filename is returned; otherwise 0 is returned. 
00066 
00067     if ('#' != buffer[0]) {                             // 1.
00068         return 0;
00069     }
00070 
00071     char *p = buffer;           
00072     while (isspace(*++p)) {                             // 2.
00073     }                           
00074 
00075     if ('i' != *p) {                                    // 3a.
00076         return 0;
00077     }
00078 
00079     static char KEY[] = "include";
00080     if (0 != strncmp(p, "include", sizeof KEY - 1)) {   // 3b.
00081         return 0;
00082     }
00083     p += sizeof KEY - 1;        // advance over KEY
00084 
00085     while (isspace(*p)) {                               // 4.
00086         ++p;
00087     }                           
00088 
00089     if ('<' != *p && '"' != *p) {                       // 5.
00090         return 0;
00091     }
00092     ++p;                        
00093 
00094     while (isspace(*p)) {                               // 6.
00095         ++p;
00096     }                           
00097 
00098     // At this point, p points to the start of the file name
00099     // all we need to do is detect the end of the string. 
00100 
00101     int length = strcspn(p, " \t\">"); 
00102     p[length] = 0;                                      // 7.
00103 
00104     return p;
00105 }
00106 
00107                 // -*-*-*- idep_FileDepIter_i -*-*-*-
00108 
00109 struct idep_FileDepIter_i {
00110     std::ifstream d_file;
00111     char d_buf[MAX_LINE_LENGTH];
00112     const char *d_header_p;
00113     int d_isValidFile;
00114     
00115     idep_FileDepIter_i(const char *fileName);
00116 };
00117 
00118 idep_FileDepIter_i::idep_FileDepIter_i(const char *fileName)
00119 : d_file(fileName)
00120 , d_header_p(d_buf)             // buffer is not yet initialized
00121 {
00122     d_isValidFile = !!d_file;   // depends on result of initialization
00123 }
00124 
00125                 // -*-*-*- idep_FileDepIter -*-*-*-
00126 
00127 idep_FileDepIter::idep_FileDepIter(const char *fileName)
00128 : d_this(new idep_FileDepIter_i(fileName))
00129 {
00130     if (!isValidFile()) {       
00131         d_this->d_header_p = 0; // iteration state is invalid
00132     }
00133     ++*this; // load first occurrence
00134 }
00135 
00136 idep_FileDepIter::~idep_FileDepIter()
00137 {
00138     delete d_this;
00139 }
00140 
00141 void idep_FileDepIter::reset() 
00142 {
00143     if (isValidFile()) {
00144         d_this->d_file.seekg(std::ios::beg); // rewind to beginning of file
00145         d_this->d_file.clear(d_this->d_file.rdstate() & std::ios::badbit); 
00146         d_this->d_header_p = d_this->d_buf;
00147     }
00148     ++*this; // load first occurrence
00149 }
00150 
00151 void idep_FileDepIter::operator++() 
00152 { 
00153     d_this->d_header_p = 0;
00154     while (loadBuf(d_this->d_file, d_this->d_buf, sizeof d_this->d_buf) >= 0) {
00155         if ((d_this->d_header_p = extractDependency(d_this->d_buf))) { // `=' ok
00156             break;
00157         }
00158     };
00159 }    
00160 
00161 int idep_FileDepIter::isValidFile() const 
00162 { 
00163     return d_this->d_isValidFile;
00164 }
00165 
00166 idep_FileDepIter::operator const void *() const 
00167 { 
00168     return d_this->d_header_p ? this : 0;
00169 }
00170 
00171 const char *idep_FileDepIter::operator ()() const 
00172 { 
00173     return d_this->d_header_p;
00174 }

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