depend.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <ctype.h>
00027 #include <limits.h>
00028 #include <unistd.h>
00029 #include <map>
00030 #include <set>
00031 #include <stack>
00032 
00033 #ifndef PATH_MAX
00034 
00035 # define PATH_MAX 260
00036 #endif
00037 
00039 struct StringCompare {
00046   bool operator () (const char *a, const char *b) const
00047   {
00048     return strcmp(a, b) < 0;
00049   }
00050 };
00052 typedef std::set<const char*, StringCompare> StringSet;
00054 typedef std::map<const char*, StringSet*, StringCompare> StringMap;
00056 typedef std::pair<const char*, StringSet*> StringMapItem;
00057 
00059 static StringSet _include_dirs;
00061 static StringMap _files;
00063 static StringMap _headers;
00065 static StringSet _defines;
00066 
00070 class File {
00071 public:
00077   File(const char *filename) : filename(filename)
00078   {
00079     this->fp = fopen(filename, "r");
00080     if (this->fp == NULL) {
00081       fprintf(stdout, "Could not open %s for reading\n", filename);
00082       exit(1);
00083     }
00084     this->dirname = strdup(filename);
00085     char *last = strrchr(this->dirname, '/');
00086     if (last != NULL) {
00087       *last = '\0';
00088     } else {
00089       *this->dirname = '\0';
00090     }
00091   }
00092 
00094   ~File()
00095   {
00096     fclose(this->fp);
00097     free(this->dirname);
00098   }
00099 
00105   char GetChar() const
00106   {
00107     int c = fgetc(this->fp);
00108     return (c == EOF) ? '\0' : c;
00109   }
00110 
00115   const char *GetDirname() const
00116   {
00117     return this->dirname;
00118   }
00119 
00120 private:
00121   FILE *fp;             
00122   char *dirname;        
00123   const char *filename; 
00124 };
00125 
00127 enum Token {
00128   TOKEN_UNKNOWN,    
00129   TOKEN_END,        
00130   TOKEN_EOL,        
00131   TOKEN_SHARP,      
00132   TOKEN_LOCAL,      
00133   TOKEN_GLOBAL,     
00134   TOKEN_IDENTIFIER, 
00135   TOKEN_DEFINE,     
00136   TOKEN_IF,         
00137   TOKEN_IFDEF,      
00138   TOKEN_IFNDEF,     
00139   TOKEN_ELIF,       
00140   TOKEN_ELSE,       
00141   TOKEN_ENDIF,      
00142   TOKEN_UNDEF,      
00143   TOKEN_OR,         
00144   TOKEN_AND,        
00145   TOKEN_DEFINED,    
00146   TOKEN_OPEN,       
00147   TOKEN_CLOSE,      
00148   TOKEN_NOT,        
00149   TOKEN_ZERO,       
00150   TOKEN_INCLUDE,    
00151 };
00152 
00154 typedef std::map<const char*, Token, StringCompare> KeywordList;
00155 
00159 class Lexer {
00160 public:
00165   Lexer(const File *file) : file(file), current_char('\0'), string(NULL), token(TOKEN_UNKNOWN)
00166   {
00167     this->keywords["define"]  = TOKEN_DEFINE;
00168     this->keywords["defined"] = TOKEN_DEFINED;
00169     this->keywords["if"]      = TOKEN_IF;
00170     this->keywords["ifdef"]   = TOKEN_IFDEF;
00171     this->keywords["ifndef"]  = TOKEN_IFNDEF;
00172     this->keywords["include"] = TOKEN_INCLUDE;
00173     this->keywords["elif"]    = TOKEN_ELIF;
00174     this->keywords["else"]    = TOKEN_ELSE;
00175     this->keywords["endif"]   = TOKEN_ENDIF;
00176     this->keywords["undef"]   = TOKEN_UNDEF;
00177 
00178     /* Initialise currently read character. */
00179     this->Next();
00180 
00181     /* Allocate the buffer. */
00182     this->buf_len = 32;
00183     this->buf = (char*)malloc(sizeof(*this->buf) * this->buf_len);
00184   }
00185 
00187   ~Lexer()
00188   {
00189     free(this->buf);
00190   }
00191 
00195   void Next()
00196   {
00197     this->current_char = this->file->GetChar();
00198   }
00199 
00204   Token GetToken() const
00205   {
00206     return this->token;
00207   }
00208 
00213   const char *GetString() const
00214   {
00215     return this->string;
00216   }
00217 
00222   void Lex()
00223   {
00224     for (;;) {
00225       free(this->string);
00226       this->string = NULL;
00227       this->token  = TOKEN_UNKNOWN;
00228 
00229       switch (this->current_char) {
00230         /* '\0' means End-Of-File */
00231         case '\0': this->token = TOKEN_END; return;
00232 
00233         /* Skip some chars, as they don't do anything */
00234         case '\t': this->Next(); break;
00235         case '\r': this->Next(); break;
00236         case ' ':  this->Next(); break;
00237 
00238         case '\\':
00239           this->Next();
00240           if (this->current_char == '\n') this->Next();
00241           break;
00242 
00243         case '\n':
00244           this->token = TOKEN_EOL;
00245           this->Next();
00246           return;
00247 
00248         case '#':
00249           this->token = TOKEN_SHARP;
00250           this->Next();
00251           return;
00252 
00253         case '"':
00254           this->ReadString('"', TOKEN_LOCAL);
00255           this->Next();
00256           return;
00257 
00258         case '<':
00259           this->ReadString('>', TOKEN_GLOBAL);
00260           this->Next();
00261           return;
00262 
00263         case '&':
00264           this->Next();
00265           if (this->current_char == '&') {
00266             this->Next();
00267             this->token = TOKEN_AND;
00268             return;
00269           }
00270           break;
00271 
00272         case '|':
00273           this->Next();
00274           if (this->current_char == '|') {
00275             this->Next();
00276             this->token = TOKEN_OR;
00277             return;
00278           }
00279           break;
00280 
00281         case '(':
00282           this->Next();
00283           this->token = TOKEN_OPEN;
00284           return;
00285 
00286         case ')':
00287           this->Next();
00288           this->token = TOKEN_CLOSE;
00289           return;
00290 
00291         case '!':
00292           this->Next();
00293           if (this->current_char != '=') {
00294             this->token = TOKEN_NOT;
00295             return;
00296           }
00297           break;
00298 
00299         /* Possible begin of comment */
00300         case '/':
00301           this->Next();
00302           switch (this->current_char) {
00303             case '*': {
00304               this->Next();
00305               char previous_char = '\0';
00306               while ((this->current_char != '/' || previous_char != '*') && this->current_char != '\0') {
00307                 previous_char = this->current_char;
00308                 this->Next();
00309               }
00310               this->Next();
00311               break;
00312             }
00313             case '/': while (this->current_char != '\n' && this->current_char != '\0') this->Next(); break;
00314             default: break;
00315           }
00316           break;
00317 
00318         default:
00319           if (isalpha(this->current_char) || this->current_char == '_') {
00320             /* If the name starts with a letter, it is an identifier */
00321             this->ReadIdentifier();
00322             return;
00323           }
00324           if (isdigit(this->current_char)) {
00325             bool zero = this->current_char == '0';
00326             this->Next();
00327             if (this->current_char == 'x' || this->current_char == 'X') Next();
00328             while (isdigit(this->current_char) || this->current_char == '.' || (this->current_char >= 'a' && this->current_char <= 'f') || (this->current_char >= 'A' && this->current_char <= 'F')) {
00329               zero &= this->current_char == '0';
00330               this->Next();
00331             }
00332             if (zero) this->token = TOKEN_ZERO;
00333             return;
00334           }
00335           this->Next();
00336           break;
00337       }
00338     }
00339   }
00340 
00341 private:
00347   Token FindKeyword(const char *name) const
00348   {
00349     KeywordList::const_iterator it = this->keywords.find(name);
00350     if (it == this->keywords.end()) return TOKEN_IDENTIFIER;
00351     return (*it).second;
00352   }
00353 
00357   void ReadIdentifier()
00358   {
00359     size_t count = 0;
00360 
00361     /* Read the rest of the identifier */
00362     do {
00363       this->buf[count++] = this->current_char;
00364       this->Next();
00365 
00366       if (count >= buf_len) {
00367         /* Scale the buffer if required */
00368         this->buf_len *= 2;
00369         this->buf = (char *)realloc(this->buf, sizeof(*this->buf) * this->buf_len);
00370       }
00371     } while ((isalpha(this->current_char) || this->current_char == '_' || isdigit(this->current_char)));
00372     this->buf[count] = '\0';
00373 
00374     free(this->string);
00375     this->string = strdup(this->buf);
00376     this->token = FindKeyword(this->string);
00377   }
00378 
00384   void ReadString(char end, Token token)
00385   {
00386     size_t count = 0;
00387     this->Next();
00388     while (this->current_char != end && this->current_char != ')' && this->current_char != '\n' && this->current_char != '\0') {
00389       this->buf[count++] = this->current_char;
00390       this->Next();
00391 
00392       if (count >= this->buf_len) {
00393         /* Scale the buffer if required */
00394         this->buf_len *= 2;
00395         this->buf = (char *)realloc(this->buf, sizeof(*this->buf) * this->buf_len);
00396       }
00397     }
00398     this->buf[count] = '\0';
00399     free(this->string);
00400     this->string = strdup(this->buf);
00401     this->token = token;
00402   }
00403 
00404   const File *file;     
00405   char current_char;    
00406   char *string;         
00407   Token token;          
00408   char *buf;            
00409   size_t buf_len;       
00410   KeywordList keywords; 
00411 };
00412 
00423 const char *GeneratePath(const char *dirname, const char *filename, bool local)
00424 {
00425   if (local) {
00426     if (access(filename, R_OK) == 0) return strdup(filename);
00427 
00428     char path[PATH_MAX];
00429     strcpy(path, dirname);
00430     const char *p = filename;
00431     /* Remove '..' from the begin of the filename. */
00432     while (*p == '.') {
00433       if (*(++p) == '.') {
00434         char *s = strrchr(path, '/');
00435         if (s != NULL) *s = '\0';
00436         p += 2;
00437       }
00438     }
00439     strcat(path, "/");
00440     strcat(path, p);
00441 
00442     if (access(path, R_OK) == 0) return strdup(path);
00443   }
00444 
00445   for (StringSet::iterator it = _include_dirs.begin(); it != _include_dirs.end(); it++) {
00446     char path[PATH_MAX];
00447     strcpy(path, *it);
00448     const char *p = filename;
00449     /* Remove '..' from the begin of the filename. */
00450     while (*p == '.') {
00451       if (*(++p) == '.') {
00452         char *s = strrchr(path, '/');
00453         if (s != NULL) *s = '\0';
00454         p += 2;
00455       }
00456     }
00457     strcat(path, "/");
00458     strcat(path, p);
00459 
00460     if (access(path, R_OK) == 0) return strdup(path);
00461   }
00462 
00463   return NULL;
00464 }
00465 
00473 bool ExpressionDefined(Lexer *lexer, StringSet *defines, bool verbose);
00474 
00482 bool ExpressionOr(Lexer *lexer, StringSet *defines, bool verbose);
00483 
00492 bool ExpressionNot(Lexer *lexer, StringSet *defines, bool verbose)
00493 {
00494   if (lexer->GetToken() == TOKEN_NOT) {
00495     if (verbose) fprintf(stderr, "!");
00496     lexer->Lex();
00497     bool value = !ExpressionDefined(lexer, defines, verbose);
00498     if (verbose) fprintf(stderr, "[%d]", value);
00499     return value;
00500   }
00501 
00502   if (lexer->GetToken() == TOKEN_OPEN) {
00503     if (verbose) fprintf(stderr, "(");
00504     lexer->Lex();
00505     bool value = ExpressionOr(lexer, defines, verbose);
00506     if (verbose) fprintf(stderr, ")[%d]", value);
00507     lexer->Lex();
00508     return value;
00509   }
00510 
00511   if (lexer->GetToken() == TOKEN_ZERO) {
00512     if (verbose) fprintf(stderr, "0");
00513     lexer->Lex();
00514     if (verbose) fprintf(stderr, "[0]");
00515     return false;
00516   }
00517 
00518   bool first = true;
00519   while (lexer->GetToken() == TOKEN_UNKNOWN || lexer->GetToken() == TOKEN_IDENTIFIER) {
00520     if (verbose && first) fprintf(stderr, "<assumed true>");
00521     first = false;
00522     lexer->Lex();
00523   }
00524 
00525   return true;
00526 }
00527 
00535 bool ExpressionDefined(Lexer *lexer, StringSet *defines, bool verbose)
00536 {
00537   bool value = ExpressionNot(lexer, defines, verbose);
00538 
00539   if (lexer->GetToken() != TOKEN_DEFINED) return value;
00540   lexer->Lex();
00541   if (verbose) fprintf(stderr, "defined");
00542   bool open = (lexer->GetToken() == TOKEN_OPEN);
00543   if (open) lexer->Lex();
00544   if (verbose) fprintf(stderr, open ? "(" : " ");
00545   if (lexer->GetToken() == TOKEN_IDENTIFIER) {
00546     if (verbose) fprintf(stderr, "%s", lexer->GetString());
00547     value = defines->find(lexer->GetString()) != defines->end();
00548   }
00549   if (open) {
00550     if (verbose) fprintf(stderr, ")");
00551     lexer->Lex();
00552   }
00553   lexer->Lex();
00554   if (verbose) fprintf(stderr, "[%d]", value);
00555   return value;
00556 }
00557 
00565 bool ExpressionAnd(Lexer *lexer, StringSet *defines, bool verbose)
00566 {
00567   bool value = ExpressionDefined(lexer, defines, verbose);
00568 
00569   for (;;) {
00570     if (lexer->GetToken() != TOKEN_AND) return value;
00571     if (verbose) fprintf(stderr, " && ");
00572     lexer->Lex();
00573     value = value && ExpressionDefined(lexer, defines, verbose);
00574   }
00575 }
00576 
00584 bool ExpressionOr(Lexer *lexer, StringSet *defines, bool verbose)
00585 {
00586   bool value = ExpressionAnd(lexer, defines, verbose);
00587 
00588   for (;;) {
00589     if (lexer->GetToken() != TOKEN_OR) return value;
00590     if (verbose) fprintf(stderr, " || ");
00591     lexer->Lex();
00592     value = value || ExpressionAnd(lexer, defines, verbose);
00593   }
00594 }
00595 
00597 enum Ignore {
00598   NOT_IGNORE,         
00599   IGNORE_UNTIL_ELSE,  
00600   IGNORE_UNTIL_ENDIF, 
00601 };
00602 
00610 void ScanFile(const char *filename, const char *ext, bool header, bool verbose)
00611 {
00612   static StringSet defines;
00613   static std::stack<Ignore> ignore;
00614   /* Copy in the default defines (parameters of depend) */
00615   if (!header) {
00616     for (StringSet::iterator it = _defines.begin(); it != _defines.end(); it++) {
00617       defines.insert(strdup(*it));
00618     }
00619   }
00620 
00621   File file(filename);
00622   Lexer lexer(&file);
00623 
00624   /* Start the lexing! */
00625   lexer.Lex();
00626 
00627   while (lexer.GetToken() != TOKEN_END) {
00628     switch (lexer.GetToken()) {
00629       /* We reached the end of the file... yay, we're done! */
00630       case TOKEN_END: break;
00631 
00632       /* The line started with a # (minus whitespace) */
00633       case TOKEN_SHARP:
00634         lexer.Lex();
00635         switch (lexer.GetToken()) {
00636           case TOKEN_INCLUDE:
00637             if (verbose) fprintf(stderr, "%s #include ", filename);
00638             lexer.Lex();
00639             switch (lexer.GetToken()) {
00640               case TOKEN_LOCAL:
00641               case TOKEN_GLOBAL: {
00642                 if (verbose) fprintf(stderr, "%s", lexer.GetString());
00643                 if (!ignore.empty() && ignore.top() != NOT_IGNORE) {
00644                   if (verbose) fprintf(stderr, " (ignored)");
00645                   break;
00646                 }
00647                 const char *h = GeneratePath(file.GetDirname(), lexer.GetString(), lexer.GetToken() == TOKEN_LOCAL);
00648                 if (h != NULL) {
00649                   StringMap::iterator it = _headers.find(h);
00650                   if (it == _headers.end()) {
00651                     it = (_headers.insert(StringMapItem(strdup(h), new StringSet()))).first;
00652                     if (verbose) fprintf(stderr, "\n");
00653                     ScanFile(h, ext, true, verbose);
00654                   }
00655                   StringMap::iterator curfile;
00656                   if (header) {
00657                     curfile = _headers.find(filename);
00658                   } else {
00659                     /* Replace the extension with the provided extension of '.o'. */
00660                     char path[PATH_MAX];
00661                     strcpy(path, filename);
00662                     *(strrchr(path, '.')) = '\0';
00663                     strcat(path, ext != NULL ? ext : ".o");
00664                     curfile = _files.find(path);
00665                     if (curfile == _files.end()) {
00666                       curfile = (_files.insert(StringMapItem(strdup(path), new StringSet()))).first;
00667                     }
00668                   }
00669                   if (it != _headers.end()) {
00670                     for (StringSet::iterator header = it->second->begin(); header != it->second->end(); header++) {
00671                       if (curfile->second->find(*header) == curfile->second->end()) curfile->second->insert(strdup(*header));
00672                     }
00673                   }
00674                   if (curfile->second->find(h) == curfile->second->end()) curfile->second->insert(strdup(h));
00675                   free((void*)h);
00676                 }
00677               }
00678               /* FALL THROUGH */
00679               default: break;
00680             }
00681             break;
00682 
00683           case TOKEN_DEFINE:
00684             if (verbose) fprintf(stderr, "%s #define ", filename);
00685             lexer.Lex();
00686             if (lexer.GetToken() == TOKEN_IDENTIFIER) {
00687               if (verbose) fprintf(stderr, "%s", lexer.GetString());
00688               if (!ignore.empty() && ignore.top() != NOT_IGNORE) {
00689                 if (verbose) fprintf(stderr, " (ignored)");
00690                 break;
00691               }
00692               if (defines.find(lexer.GetString()) == defines.end()) defines.insert(strdup(lexer.GetString()));
00693               lexer.Lex();
00694             }
00695             break;
00696 
00697           case TOKEN_UNDEF:
00698             if (verbose) fprintf(stderr, "%s #undef ", filename);
00699             lexer.Lex();
00700             if (lexer.GetToken() == TOKEN_IDENTIFIER) {
00701               if (verbose) fprintf(stderr, "%s", lexer.GetString());
00702               if (!ignore.empty() && ignore.top() != NOT_IGNORE) {
00703                 if (verbose) fprintf(stderr, " (ignored)");
00704                 break;
00705               }
00706               StringSet::iterator it = defines.find(lexer.GetString());
00707               if (it != defines.end()) {
00708                 free((void*)*it);
00709                 defines.erase(it);
00710               }
00711               lexer.Lex();
00712             }
00713             break;
00714 
00715           case TOKEN_ENDIF:
00716             if (verbose) fprintf(stderr, "%s #endif", filename);
00717             lexer.Lex();
00718             if (!ignore.empty()) ignore.pop();
00719             if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not ");
00720             break;
00721 
00722           case TOKEN_ELSE: {
00723             if (verbose) fprintf(stderr, "%s #else", filename);
00724             lexer.Lex();
00725             Ignore last = ignore.empty() ? NOT_IGNORE : ignore.top();
00726             if (!ignore.empty()) ignore.pop();
00727             if (ignore.empty() || ignore.top() == NOT_IGNORE) {
00728               ignore.push(last == IGNORE_UNTIL_ELSE ? NOT_IGNORE : IGNORE_UNTIL_ENDIF);
00729             } else {
00730               ignore.push(IGNORE_UNTIL_ENDIF);
00731             }
00732             if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not ");
00733             break;
00734           }
00735 
00736           case TOKEN_ELIF: {
00737             if (verbose) fprintf(stderr, "%s #elif ", filename);
00738             lexer.Lex();
00739             Ignore last = ignore.empty() ? NOT_IGNORE : ignore.top();
00740             if (!ignore.empty()) ignore.pop();
00741             if (ignore.empty() || ignore.top() == NOT_IGNORE) {
00742               bool value = ExpressionOr(&lexer, &defines, verbose);
00743               ignore.push(last == IGNORE_UNTIL_ELSE ? (value ? NOT_IGNORE : IGNORE_UNTIL_ELSE) : IGNORE_UNTIL_ENDIF);
00744             } else {
00745               ignore.push(IGNORE_UNTIL_ENDIF);
00746             }
00747             if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not ");
00748             break;
00749           }
00750 
00751           case TOKEN_IF: {
00752             if (verbose) fprintf(stderr, "%s #if ", filename);
00753             lexer.Lex();
00754             if (ignore.empty() || ignore.top() == NOT_IGNORE) {
00755               bool value = ExpressionOr(&lexer, &defines, verbose);
00756               ignore.push(value ? NOT_IGNORE : IGNORE_UNTIL_ELSE);
00757             } else {
00758               ignore.push(IGNORE_UNTIL_ENDIF);
00759             }
00760             if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not ");
00761             break;
00762           }
00763 
00764           case TOKEN_IFDEF:
00765             if (verbose) fprintf(stderr, "%s #ifdef ", filename);
00766             lexer.Lex();
00767             if (lexer.GetToken() == TOKEN_IDENTIFIER) {
00768               bool value = defines.find(lexer.GetString()) != defines.end();
00769               if (verbose) fprintf(stderr, "%s[%d]", lexer.GetString(), value);
00770               if (ignore.empty() || ignore.top() == NOT_IGNORE) {
00771                 ignore.push(value ? NOT_IGNORE : IGNORE_UNTIL_ELSE);
00772               } else {
00773                 ignore.push(IGNORE_UNTIL_ENDIF);
00774               }
00775             }
00776             if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not ");
00777             break;
00778 
00779           case TOKEN_IFNDEF:
00780             if (verbose) fprintf(stderr, "%s #ifndef ", filename);
00781             lexer.Lex();
00782             if (lexer.GetToken() == TOKEN_IDENTIFIER) {
00783               bool value = defines.find(lexer.GetString()) != defines.end();
00784               if (verbose) fprintf(stderr, "%s[%d]", lexer.GetString(), value);
00785               if (ignore.empty() || ignore.top() == NOT_IGNORE) {
00786                 ignore.push(!value ? NOT_IGNORE : IGNORE_UNTIL_ELSE);
00787               } else {
00788                 ignore.push(IGNORE_UNTIL_ENDIF);
00789               }
00790             }
00791             if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not ");
00792             break;
00793 
00794           default:
00795             if (verbose) fprintf(stderr, "%s #<unknown>", filename);
00796             lexer.Lex();
00797             break;
00798         }
00799         if (verbose) fprintf(stderr, "\n");
00800         /* FALL THROUGH */
00801       default:
00802         /* Ignore the rest of the garbage on this line */
00803         while (lexer.GetToken() != TOKEN_EOL && lexer.GetToken() != TOKEN_END) lexer.Lex();
00804         lexer.Lex();
00805         break;
00806     }
00807   }
00808 
00809   if (!header) {
00810     for (StringSet::iterator it = defines.begin(); it != defines.end(); it++) {
00811       free((void*)*it);
00812     }
00813     defines.clear();
00814     while (!ignore.empty()) ignore.pop();
00815   }
00816 }
00817 
00824 int main(int argc, char *argv[])
00825 {
00826   bool ignorenext = true;
00827   char *filename = NULL;
00828   char *ext = NULL;
00829   char *delimiter = NULL;
00830   bool append = false;
00831   bool verbose = false;
00832 
00833   for (int i = 0; i < argc; i++) {
00834     if (ignorenext) {
00835       ignorenext = false;
00836       continue;
00837     }
00838     if (argv[i][0] == '-') {
00839       /* Append */
00840       if (strncmp(argv[i], "-a", 2) == 0) append = true;
00841       /* Include dir */
00842       if (strncmp(argv[i], "-I", 2) == 0) {
00843         if (argv[i][2] == '\0') {
00844           i++;
00845           _include_dirs.insert(strdup(argv[i]));
00846         } else {
00847           _include_dirs.insert(strdup(&argv[i][2]));
00848         }
00849         continue;
00850       }
00851       /* Define */
00852       if (strncmp(argv[i], "-D", 2) == 0) {
00853         char *p = strchr(argv[i], '=');
00854         if (p != NULL) *p = '\0';
00855         _defines.insert(strdup(&argv[i][2]));
00856         continue;
00857       }
00858       /* Output file */
00859       if (strncmp(argv[i], "-f", 2) == 0) {
00860         if (filename != NULL) continue;
00861         filename = strdup(&argv[i][2]);
00862         continue;
00863       }
00864       /* Object file extension */
00865       if (strncmp(argv[i], "-o", 2) == 0) {
00866         if (ext != NULL) continue;
00867         ext = strdup(&argv[i][2]);
00868         continue;
00869       }
00870       /* Starting string delimiter */
00871       if (strncmp(argv[i], "-s", 2) == 0) {
00872         if (delimiter != NULL) continue;
00873         delimiter = strdup(&argv[i][2]);
00874         continue;
00875       }
00876       /* Verbose */
00877       if (strncmp(argv[i], "-v", 2) == 0) verbose = true;
00878       continue;
00879     }
00880     ScanFile(argv[i], ext, false, verbose);
00881   }
00882 
00883   /* Default output file is Makefile */
00884   if (filename == NULL) filename = strdup("Makefile");
00885 
00886   /* Default delimiter string */
00887   if (delimiter == NULL) delimiter = strdup("# DO NOT DELETE");
00888 
00889   char backup[PATH_MAX];
00890   strcpy(backup, filename);
00891   strcat(backup, ".bak");
00892 
00893   char *content = NULL;
00894   long size = 0;
00895 
00896   /* Read in the current file; so we can overwrite everything from the
00897    * end of non-depend data marker down till the end. */
00898   FILE *src = fopen(filename, "rb");
00899   if (src != NULL) {
00900     fseek(src, 0, SEEK_END);
00901     size = ftell(src);
00902     rewind(src);
00903     content = (char*)malloc(size * sizeof(*content));
00904     fread(content, 1, size, src);
00905     fclose(src);
00906   }
00907 
00908   FILE *dst = fopen(filename, "w");
00909   bool found_delimiter = false;
00910 
00911   if (size != 0) {
00912     src = fopen(backup, "wb");
00913     fwrite(content, 1, size, src);
00914     fclose(src);
00915 
00916     /* Then append it to the real file. */
00917     src = fopen(backup, "rb");
00918     while (fgets(content, size, src) != NULL) {
00919       fputs(content, dst);
00920       if (!strncmp(content, delimiter, strlen(delimiter))) found_delimiter = true;
00921       if (!append && found_delimiter) break;
00922     }
00923     fclose(src);
00924   }
00925   if (!found_delimiter) fprintf(dst, "\n%s\n", delimiter);
00926 
00927   for (StringMap::iterator it = _files.begin(); it != _files.end(); it++) {
00928     for (StringSet::iterator h = it->second->begin(); h != it->second->end(); h++) {
00929       fprintf(dst, "%s: %s\n", it->first, *h);
00930     }
00931   }
00932 
00933   /* Clean up our mess. */
00934   fclose(dst);
00935 
00936   free(delimiter);
00937   free(filename);
00938   free(ext);
00939   free(content);
00940 
00941   for (StringMap::iterator it = _files.begin(); it != _files.end(); it++) {
00942     for (StringSet::iterator h = it->second->begin(); h != it->second->end(); h++) {
00943       free((void*)*h);
00944     }
00945     it->second->clear();
00946     delete it->second;
00947     free((void*)it->first);
00948   }
00949   _files.clear();
00950 
00951   for (StringMap::iterator it = _headers.begin(); it != _headers.end(); it++) {
00952     for (StringSet::iterator h = it->second->begin(); h != it->second->end(); h++) {
00953       free((void*)*h);
00954     }
00955     it->second->clear();
00956     delete it->second;
00957     free((void*)it->first);
00958   }
00959   _headers.clear();
00960 
00961   for (StringSet::iterator it = _defines.begin(); it != _defines.end(); it++) {
00962     free((void*)*it);
00963   }
00964   _defines.clear();
00965 
00966   for (StringSet::iterator it = _include_dirs.begin(); it != _include_dirs.end(); it++) {
00967     free((void*)*it);
00968   }
00969   _include_dirs.clear();
00970 
00971   return 0;
00972 }

Generated on Fri Jun 3 05:18:50 2011 for OpenTTD by  doxygen 1.6.1