depend.cpp

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

Generated on Sun Nov 14 14:41:50 2010 for OpenTTD by  doxygen 1.6.1