00001
00002
00003
00004
00005
00006
00007
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
00037 static inline void free(const void *ptr)
00038 {
00039 free(const_cast<void *>(ptr));
00040 }
00041
00042 #ifndef PATH_MAX
00043
00044 # define PATH_MAX 260
00045 #endif
00046
00048 struct StringCompare {
00055 bool operator () (const char *a, const char *b) const
00056 {
00057 return strcmp(a, b) < 0;
00058 }
00059 };
00061 typedef std::set<const char*, StringCompare> StringSet;
00063 typedef std::map<const char*, StringSet*, StringCompare> StringMap;
00065 typedef std::pair<const char*, StringSet*> StringMapItem;
00066
00068 static StringSet _include_dirs;
00070 static StringMap _files;
00072 static StringMap _headers;
00074 static StringSet _defines;
00075
00079 class File {
00080 public:
00086 File(const char *filename)
00087 {
00088 this->fp = fopen(filename, "r");
00089 if (this->fp == NULL) {
00090 fprintf(stdout, "Could not open %s for reading\n", filename);
00091 exit(1);
00092 }
00093 this->dirname = strdup(filename);
00094 char *last = strrchr(this->dirname, '/');
00095 if (last != NULL) {
00096 *last = '\0';
00097 } else {
00098 *this->dirname = '\0';
00099 }
00100 }
00101
00103 ~File()
00104 {
00105 fclose(this->fp);
00106 free(this->dirname);
00107 }
00108
00114 char GetChar() const
00115 {
00116 int c = fgetc(this->fp);
00117 return (c == EOF) ? '\0' : c;
00118 }
00119
00124 const char *GetDirname() const
00125 {
00126 return this->dirname;
00127 }
00128
00129 private:
00130 FILE *fp;
00131 char *dirname;
00132 };
00133
00135 enum Token {
00136 TOKEN_UNKNOWN,
00137 TOKEN_END,
00138 TOKEN_EOL,
00139 TOKEN_SHARP,
00140 TOKEN_LOCAL,
00141 TOKEN_GLOBAL,
00142 TOKEN_IDENTIFIER,
00143 TOKEN_DEFINE,
00144 TOKEN_IF,
00145 TOKEN_IFDEF,
00146 TOKEN_IFNDEF,
00147 TOKEN_ELIF,
00148 TOKEN_ELSE,
00149 TOKEN_ENDIF,
00150 TOKEN_UNDEF,
00151 TOKEN_OR,
00152 TOKEN_AND,
00153 TOKEN_DEFINED,
00154 TOKEN_OPEN,
00155 TOKEN_CLOSE,
00156 TOKEN_NOT,
00157 TOKEN_ZERO,
00158 TOKEN_INCLUDE,
00159 };
00160
00162 typedef std::map<const char*, Token, StringCompare> KeywordList;
00163
00167 class Lexer {
00168 public:
00173 Lexer(const File *file) : file(file), current_char('\0'), string(NULL), token(TOKEN_UNKNOWN)
00174 {
00175 this->keywords["define"] = TOKEN_DEFINE;
00176 this->keywords["defined"] = TOKEN_DEFINED;
00177 this->keywords["if"] = TOKEN_IF;
00178 this->keywords["ifdef"] = TOKEN_IFDEF;
00179 this->keywords["ifndef"] = TOKEN_IFNDEF;
00180 this->keywords["include"] = TOKEN_INCLUDE;
00181 this->keywords["elif"] = TOKEN_ELIF;
00182 this->keywords["else"] = TOKEN_ELSE;
00183 this->keywords["endif"] = TOKEN_ENDIF;
00184 this->keywords["undef"] = TOKEN_UNDEF;
00185
00186
00187 this->Next();
00188
00189
00190 this->buf_len = 32;
00191 this->buf = (char*)malloc(sizeof(*this->buf) * this->buf_len);
00192 }
00193
00195 ~Lexer()
00196 {
00197 free(this->buf);
00198 }
00199
00203 void Next()
00204 {
00205 this->current_char = this->file->GetChar();
00206 }
00207
00212 Token GetToken() const
00213 {
00214 return this->token;
00215 }
00216
00221 const char *GetString() const
00222 {
00223 return this->string;
00224 }
00225
00230 void Lex()
00231 {
00232 for (;;) {
00233 free(this->string);
00234 this->string = NULL;
00235 this->token = TOKEN_UNKNOWN;
00236
00237 switch (this->current_char) {
00238
00239 case '\0': this->token = TOKEN_END; return;
00240
00241
00242 case '\t': this->Next(); break;
00243 case '\r': this->Next(); break;
00244 case ' ': this->Next(); break;
00245
00246 case '\\':
00247 this->Next();
00248 if (this->current_char == '\n') this->Next();
00249 break;
00250
00251 case '\n':
00252 this->token = TOKEN_EOL;
00253 this->Next();
00254 return;
00255
00256 case '#':
00257 this->token = TOKEN_SHARP;
00258 this->Next();
00259 return;
00260
00261 case '"':
00262 this->ReadString('"', TOKEN_LOCAL);
00263 this->Next();
00264 return;
00265
00266 case '<':
00267 this->ReadString('>', TOKEN_GLOBAL);
00268 this->Next();
00269 return;
00270
00271 case '&':
00272 this->Next();
00273 if (this->current_char == '&') {
00274 this->Next();
00275 this->token = TOKEN_AND;
00276 return;
00277 }
00278 break;
00279
00280 case '|':
00281 this->Next();
00282 if (this->current_char == '|') {
00283 this->Next();
00284 this->token = TOKEN_OR;
00285 return;
00286 }
00287 break;
00288
00289 case '(':
00290 this->Next();
00291 this->token = TOKEN_OPEN;
00292 return;
00293
00294 case ')':
00295 this->Next();
00296 this->token = TOKEN_CLOSE;
00297 return;
00298
00299 case '!':
00300 this->Next();
00301 if (this->current_char != '=') {
00302 this->token = TOKEN_NOT;
00303 return;
00304 }
00305 break;
00306
00307
00308 case '/':
00309 this->Next();
00310 switch (this->current_char) {
00311 case '*': {
00312 this->Next();
00313 char previous_char = '\0';
00314 while ((this->current_char != '/' || previous_char != '*') && this->current_char != '\0') {
00315 previous_char = this->current_char;
00316 this->Next();
00317 }
00318 this->Next();
00319 break;
00320 }
00321 case '/': while (this->current_char != '\n' && this->current_char != '\0') this->Next(); break;
00322 default: break;
00323 }
00324 break;
00325
00326 default:
00327 if (isalpha(this->current_char) || this->current_char == '_') {
00328
00329 this->ReadIdentifier();
00330 return;
00331 }
00332 if (isdigit(this->current_char)) {
00333 bool zero = this->current_char == '0';
00334 this->Next();
00335 if (this->current_char == 'x' || this->current_char == 'X') Next();
00336 while (isdigit(this->current_char) || this->current_char == '.' || (this->current_char >= 'a' && this->current_char <= 'f') || (this->current_char >= 'A' && this->current_char <= 'F')) {
00337 zero &= this->current_char == '0';
00338 this->Next();
00339 }
00340 if (zero) this->token = TOKEN_ZERO;
00341 return;
00342 }
00343 this->Next();
00344 break;
00345 }
00346 }
00347 }
00348
00349 private:
00355 Token FindKeyword(const char *name) const
00356 {
00357 KeywordList::const_iterator it = this->keywords.find(name);
00358 if (it == this->keywords.end()) return TOKEN_IDENTIFIER;
00359 return (*it).second;
00360 }
00361
00365 void ReadIdentifier()
00366 {
00367 size_t count = 0;
00368
00369
00370 do {
00371 this->buf[count++] = this->current_char;
00372 this->Next();
00373
00374 if (count >= buf_len) {
00375
00376 this->buf_len *= 2;
00377 this->buf = (char *)realloc(this->buf, sizeof(*this->buf) * this->buf_len);
00378 }
00379 } while ((isalpha(this->current_char) || this->current_char == '_' || isdigit(this->current_char)));
00380 this->buf[count] = '\0';
00381
00382 free(this->string);
00383 this->string = strdup(this->buf);
00384 this->token = FindKeyword(this->string);
00385 }
00386
00392 void ReadString(char end, Token token)
00393 {
00394 size_t count = 0;
00395 this->Next();
00396 while (this->current_char != end && this->current_char != ')' && this->current_char != '\n' && this->current_char != '\0') {
00397 this->buf[count++] = this->current_char;
00398 this->Next();
00399
00400 if (count >= this->buf_len) {
00401
00402 this->buf_len *= 2;
00403 this->buf = (char *)realloc(this->buf, sizeof(*this->buf) * this->buf_len);
00404 }
00405 }
00406 this->buf[count] = '\0';
00407 free(this->string);
00408 this->string = strdup(this->buf);
00409 this->token = token;
00410 }
00411
00412 const File *file;
00413 char current_char;
00414 char *string;
00415 Token token;
00416 char *buf;
00417 size_t buf_len;
00418 KeywordList keywords;
00419 };
00420
00431 const char *GeneratePath(const char *dirname, const char *filename, bool local)
00432 {
00433 if (local) {
00434 if (access(filename, R_OK) == 0) return strdup(filename);
00435
00436 char path[PATH_MAX];
00437 strcpy(path, dirname);
00438 const char *p = filename;
00439
00440 while (*p == '.') {
00441 if (*(++p) == '.') {
00442 char *s = strrchr(path, '/');
00443 if (s != NULL) *s = '\0';
00444 p += 2;
00445 }
00446 }
00447 strcat(path, "/");
00448 strcat(path, p);
00449
00450 if (access(path, R_OK) == 0) return strdup(path);
00451 }
00452
00453 for (StringSet::iterator it = _include_dirs.begin(); it != _include_dirs.end(); it++) {
00454 char path[PATH_MAX];
00455 strcpy(path, *it);
00456 const char *p = filename;
00457
00458 while (*p == '.') {
00459 if (*(++p) == '.') {
00460 char *s = strrchr(path, '/');
00461 if (s != NULL) *s = '\0';
00462 p += 2;
00463 }
00464 }
00465 strcat(path, "/");
00466 strcat(path, p);
00467
00468 if (access(path, R_OK) == 0) return strdup(path);
00469 }
00470
00471 return NULL;
00472 }
00473
00481 bool ExpressionDefined(Lexer *lexer, StringSet *defines, bool verbose);
00482
00490 bool ExpressionOr(Lexer *lexer, StringSet *defines, bool verbose);
00491
00500 bool ExpressionNot(Lexer *lexer, StringSet *defines, bool verbose)
00501 {
00502 if (lexer->GetToken() == TOKEN_NOT) {
00503 if (verbose) fprintf(stderr, "!");
00504 lexer->Lex();
00505 bool value = !ExpressionDefined(lexer, defines, verbose);
00506 if (verbose) fprintf(stderr, "[%d]", value);
00507 return value;
00508 }
00509
00510 if (lexer->GetToken() == TOKEN_OPEN) {
00511 if (verbose) fprintf(stderr, "(");
00512 lexer->Lex();
00513 bool value = ExpressionOr(lexer, defines, verbose);
00514 if (verbose) fprintf(stderr, ")[%d]", value);
00515 lexer->Lex();
00516 return value;
00517 }
00518
00519 if (lexer->GetToken() == TOKEN_ZERO) {
00520 if (verbose) fprintf(stderr, "0");
00521 lexer->Lex();
00522 if (verbose) fprintf(stderr, "[0]");
00523 return false;
00524 }
00525
00526 bool first = true;
00527 while (lexer->GetToken() == TOKEN_UNKNOWN || lexer->GetToken() == TOKEN_IDENTIFIER) {
00528 if (verbose && first) fprintf(stderr, "<assumed true>");
00529 first = false;
00530 lexer->Lex();
00531 }
00532
00533 return true;
00534 }
00535
00543 bool ExpressionDefined(Lexer *lexer, StringSet *defines, bool verbose)
00544 {
00545 bool value = ExpressionNot(lexer, defines, verbose);
00546
00547 if (lexer->GetToken() != TOKEN_DEFINED) return value;
00548 lexer->Lex();
00549 if (verbose) fprintf(stderr, "defined");
00550 bool open = (lexer->GetToken() == TOKEN_OPEN);
00551 if (open) lexer->Lex();
00552 if (verbose) fprintf(stderr, open ? "(" : " ");
00553 if (lexer->GetToken() == TOKEN_IDENTIFIER) {
00554 if (verbose) fprintf(stderr, "%s", lexer->GetString());
00555 value = defines->find(lexer->GetString()) != defines->end();
00556 }
00557 if (open) {
00558 if (verbose) fprintf(stderr, ")");
00559 lexer->Lex();
00560 }
00561 lexer->Lex();
00562 if (verbose) fprintf(stderr, "[%d]", value);
00563 return value;
00564 }
00565
00573 bool ExpressionAnd(Lexer *lexer, StringSet *defines, bool verbose)
00574 {
00575 bool value = ExpressionDefined(lexer, defines, verbose);
00576
00577 for (;;) {
00578 if (lexer->GetToken() != TOKEN_AND) return value;
00579 if (verbose) fprintf(stderr, " && ");
00580 lexer->Lex();
00581 value = value && ExpressionDefined(lexer, defines, verbose);
00582 }
00583 }
00584
00592 bool ExpressionOr(Lexer *lexer, StringSet *defines, bool verbose)
00593 {
00594 bool value = ExpressionAnd(lexer, defines, verbose);
00595
00596 for (;;) {
00597 if (lexer->GetToken() != TOKEN_OR) return value;
00598 if (verbose) fprintf(stderr, " || ");
00599 lexer->Lex();
00600 value = value || ExpressionAnd(lexer, defines, verbose);
00601 }
00602 }
00603
00605 enum Ignore {
00606 NOT_IGNORE,
00607 IGNORE_UNTIL_ELSE,
00608 IGNORE_UNTIL_ENDIF,
00609 };
00610
00618 void ScanFile(const char *filename, const char *ext, bool header, bool verbose)
00619 {
00620 static StringSet defines;
00621 static std::stack<Ignore> ignore;
00622
00623 if (!header) {
00624 for (StringSet::iterator it = _defines.begin(); it != _defines.end(); it++) {
00625 defines.insert(strdup(*it));
00626 }
00627 }
00628
00629 File file(filename);
00630 Lexer lexer(&file);
00631
00632
00633 lexer.Lex();
00634
00635 while (lexer.GetToken() != TOKEN_END) {
00636 switch (lexer.GetToken()) {
00637
00638 case TOKEN_END: break;
00639
00640
00641 case TOKEN_SHARP:
00642 lexer.Lex();
00643 switch (lexer.GetToken()) {
00644 case TOKEN_INCLUDE:
00645 if (verbose) fprintf(stderr, "%s #include ", filename);
00646 lexer.Lex();
00647 switch (lexer.GetToken()) {
00648 case TOKEN_LOCAL:
00649 case TOKEN_GLOBAL: {
00650 if (verbose) fprintf(stderr, "%s", lexer.GetString());
00651 if (!ignore.empty() && ignore.top() != NOT_IGNORE) {
00652 if (verbose) fprintf(stderr, " (ignored)");
00653 break;
00654 }
00655 const char *h = GeneratePath(file.GetDirname(), lexer.GetString(), lexer.GetToken() == TOKEN_LOCAL);
00656 if (h != NULL) {
00657 StringMap::iterator it = _headers.find(h);
00658 if (it == _headers.end()) {
00659 it = (_headers.insert(StringMapItem(strdup(h), new StringSet()))).first;
00660 if (verbose) fprintf(stderr, "\n");
00661 ScanFile(h, ext, true, verbose);
00662 }
00663 StringMap::iterator curfile;
00664 if (header) {
00665 curfile = _headers.find(filename);
00666 } else {
00667
00668 char path[PATH_MAX];
00669 strcpy(path, filename);
00670 *(strrchr(path, '.')) = '\0';
00671 strcat(path, ext != NULL ? ext : ".o");
00672 curfile = _files.find(path);
00673 if (curfile == _files.end()) {
00674 curfile = (_files.insert(StringMapItem(strdup(path), new StringSet()))).first;
00675 }
00676 }
00677 if (it != _headers.end()) {
00678 for (StringSet::iterator header = it->second->begin(); header != it->second->end(); header++) {
00679 if (curfile->second->find(*header) == curfile->second->end()) curfile->second->insert(strdup(*header));
00680 }
00681 }
00682 if (curfile->second->find(h) == curfile->second->end()) curfile->second->insert(strdup(h));
00683 free(h);
00684 }
00685 }
00686
00687 default: break;
00688 }
00689 break;
00690
00691 case TOKEN_DEFINE:
00692 if (verbose) fprintf(stderr, "%s #define ", filename);
00693 lexer.Lex();
00694 if (lexer.GetToken() == TOKEN_IDENTIFIER) {
00695 if (verbose) fprintf(stderr, "%s", lexer.GetString());
00696 if (!ignore.empty() && ignore.top() != NOT_IGNORE) {
00697 if (verbose) fprintf(stderr, " (ignored)");
00698 break;
00699 }
00700 if (defines.find(lexer.GetString()) == defines.end()) defines.insert(strdup(lexer.GetString()));
00701 lexer.Lex();
00702 }
00703 break;
00704
00705 case TOKEN_UNDEF:
00706 if (verbose) fprintf(stderr, "%s #undef ", filename);
00707 lexer.Lex();
00708 if (lexer.GetToken() == TOKEN_IDENTIFIER) {
00709 if (verbose) fprintf(stderr, "%s", lexer.GetString());
00710 if (!ignore.empty() && ignore.top() != NOT_IGNORE) {
00711 if (verbose) fprintf(stderr, " (ignored)");
00712 break;
00713 }
00714 StringSet::iterator it = defines.find(lexer.GetString());
00715 if (it != defines.end()) {
00716 free(*it);
00717 defines.erase(it);
00718 }
00719 lexer.Lex();
00720 }
00721 break;
00722
00723 case TOKEN_ENDIF:
00724 if (verbose) fprintf(stderr, "%s #endif", filename);
00725 lexer.Lex();
00726 if (!ignore.empty()) ignore.pop();
00727 if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not ");
00728 break;
00729
00730 case TOKEN_ELSE: {
00731 if (verbose) fprintf(stderr, "%s #else", filename);
00732 lexer.Lex();
00733 Ignore last = ignore.empty() ? NOT_IGNORE : ignore.top();
00734 if (!ignore.empty()) ignore.pop();
00735 if (ignore.empty() || ignore.top() == NOT_IGNORE) {
00736 ignore.push(last == IGNORE_UNTIL_ELSE ? NOT_IGNORE : IGNORE_UNTIL_ENDIF);
00737 } else {
00738 ignore.push(IGNORE_UNTIL_ENDIF);
00739 }
00740 if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not ");
00741 break;
00742 }
00743
00744 case TOKEN_ELIF: {
00745 if (verbose) fprintf(stderr, "%s #elif ", filename);
00746 lexer.Lex();
00747 Ignore last = ignore.empty() ? NOT_IGNORE : ignore.top();
00748 if (!ignore.empty()) ignore.pop();
00749 if (ignore.empty() || ignore.top() == NOT_IGNORE) {
00750 bool value = ExpressionOr(&lexer, &defines, verbose);
00751 ignore.push(last == IGNORE_UNTIL_ELSE ? (value ? NOT_IGNORE : IGNORE_UNTIL_ELSE) : IGNORE_UNTIL_ENDIF);
00752 } else {
00753 ignore.push(IGNORE_UNTIL_ENDIF);
00754 }
00755 if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not ");
00756 break;
00757 }
00758
00759 case TOKEN_IF: {
00760 if (verbose) fprintf(stderr, "%s #if ", filename);
00761 lexer.Lex();
00762 if (ignore.empty() || ignore.top() == NOT_IGNORE) {
00763 bool value = ExpressionOr(&lexer, &defines, verbose);
00764 ignore.push(value ? NOT_IGNORE : IGNORE_UNTIL_ELSE);
00765 } else {
00766 ignore.push(IGNORE_UNTIL_ENDIF);
00767 }
00768 if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not ");
00769 break;
00770 }
00771
00772 case TOKEN_IFDEF:
00773 if (verbose) fprintf(stderr, "%s #ifdef ", filename);
00774 lexer.Lex();
00775 if (lexer.GetToken() == TOKEN_IDENTIFIER) {
00776 bool value = defines.find(lexer.GetString()) != defines.end();
00777 if (verbose) fprintf(stderr, "%s[%d]", lexer.GetString(), value);
00778 if (ignore.empty() || ignore.top() == NOT_IGNORE) {
00779 ignore.push(value ? NOT_IGNORE : IGNORE_UNTIL_ELSE);
00780 } else {
00781 ignore.push(IGNORE_UNTIL_ENDIF);
00782 }
00783 }
00784 if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not ");
00785 break;
00786
00787 case TOKEN_IFNDEF:
00788 if (verbose) fprintf(stderr, "%s #ifndef ", filename);
00789 lexer.Lex();
00790 if (lexer.GetToken() == TOKEN_IDENTIFIER) {
00791 bool value = defines.find(lexer.GetString()) != defines.end();
00792 if (verbose) fprintf(stderr, "%s[%d]", lexer.GetString(), value);
00793 if (ignore.empty() || ignore.top() == NOT_IGNORE) {
00794 ignore.push(!value ? NOT_IGNORE : IGNORE_UNTIL_ELSE);
00795 } else {
00796 ignore.push(IGNORE_UNTIL_ENDIF);
00797 }
00798 }
00799 if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not ");
00800 break;
00801
00802 default:
00803 if (verbose) fprintf(stderr, "%s #<unknown>", filename);
00804 lexer.Lex();
00805 break;
00806 }
00807 if (verbose) fprintf(stderr, "\n");
00808
00809 default:
00810
00811 while (lexer.GetToken() != TOKEN_EOL && lexer.GetToken() != TOKEN_END) lexer.Lex();
00812 lexer.Lex();
00813 break;
00814 }
00815 }
00816
00817 if (!header) {
00818 for (StringSet::iterator it = defines.begin(); it != defines.end(); it++) {
00819 free(*it);
00820 }
00821 defines.clear();
00822 while (!ignore.empty()) ignore.pop();
00823 }
00824 }
00825
00832 int main(int argc, char *argv[])
00833 {
00834 bool ignorenext = true;
00835 char *filename = NULL;
00836 char *ext = NULL;
00837 char *delimiter = NULL;
00838 bool append = false;
00839 bool verbose = false;
00840
00841 for (int i = 0; i < argc; i++) {
00842 if (ignorenext) {
00843 ignorenext = false;
00844 continue;
00845 }
00846 if (argv[i][0] == '-') {
00847
00848 if (strncmp(argv[i], "-a", 2) == 0) append = true;
00849
00850 if (strncmp(argv[i], "-I", 2) == 0) {
00851 if (argv[i][2] == '\0') {
00852 i++;
00853 _include_dirs.insert(strdup(argv[i]));
00854 } else {
00855 _include_dirs.insert(strdup(&argv[i][2]));
00856 }
00857 continue;
00858 }
00859
00860 if (strncmp(argv[i], "-D", 2) == 0) {
00861 char *p = strchr(argv[i], '=');
00862 if (p != NULL) *p = '\0';
00863 _defines.insert(strdup(&argv[i][2]));
00864 continue;
00865 }
00866
00867 if (strncmp(argv[i], "-f", 2) == 0) {
00868 if (filename != NULL) continue;
00869 filename = strdup(&argv[i][2]);
00870 continue;
00871 }
00872
00873 if (strncmp(argv[i], "-o", 2) == 0) {
00874 if (ext != NULL) continue;
00875 ext = strdup(&argv[i][2]);
00876 continue;
00877 }
00878
00879 if (strncmp(argv[i], "-s", 2) == 0) {
00880 if (delimiter != NULL) continue;
00881 delimiter = strdup(&argv[i][2]);
00882 continue;
00883 }
00884
00885 if (strncmp(argv[i], "-v", 2) == 0) verbose = true;
00886 continue;
00887 }
00888 ScanFile(argv[i], ext, false, verbose);
00889 }
00890
00891
00892 if (filename == NULL) filename = strdup("Makefile");
00893
00894
00895 if (delimiter == NULL) delimiter = strdup("# DO NOT DELETE");
00896
00897 char backup[PATH_MAX];
00898 strcpy(backup, filename);
00899 strcat(backup, ".bak");
00900
00901 char *content = NULL;
00902 long size = 0;
00903
00904
00905
00906 FILE *src = fopen(filename, "rb");
00907 if (src != NULL) {
00908 fseek(src, 0, SEEK_END);
00909 size = ftell(src);
00910 rewind(src);
00911 content = (char*)malloc(size * sizeof(*content));
00912 if (fread(content, 1, size, src) != (size_t)size) {
00913 fprintf(stderr, "Could not read %s\n", filename);
00914 exit(-2);
00915 }
00916 fclose(src);
00917 }
00918
00919 FILE *dst = fopen(filename, "w");
00920 bool found_delimiter = false;
00921
00922 if (size != 0) {
00923 src = fopen(backup, "wb");
00924 if (fwrite(content, 1, size, src) != (size_t)size) {
00925 fprintf(stderr, "Could not write %s\n", filename);
00926 exit(-2);
00927 }
00928 fclose(src);
00929
00930
00931 src = fopen(backup, "rb");
00932 while (fgets(content, size, src) != NULL) {
00933 fputs(content, dst);
00934 if (!strncmp(content, delimiter, strlen(delimiter))) found_delimiter = true;
00935 if (!append && found_delimiter) break;
00936 }
00937 fclose(src);
00938 }
00939 if (!found_delimiter) fprintf(dst, "\n%s\n", delimiter);
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 fprintf(dst, "%s: %s\n", it->first, *h);
00944 }
00945 }
00946
00947
00948 fclose(dst);
00949
00950 free(delimiter);
00951 free(filename);
00952 free(ext);
00953 free(content);
00954
00955 for (StringMap::iterator it = _files.begin(); it != _files.end(); it++) {
00956 for (StringSet::iterator h = it->second->begin(); h != it->second->end(); h++) {
00957 free(*h);
00958 }
00959 it->second->clear();
00960 delete it->second;
00961 free(it->first);
00962 }
00963 _files.clear();
00964
00965 for (StringMap::iterator it = _headers.begin(); it != _headers.end(); it++) {
00966 for (StringSet::iterator h = it->second->begin(); h != it->second->end(); h++) {
00967 free(*h);
00968 }
00969 it->second->clear();
00970 delete it->second;
00971 free(it->first);
00972 }
00973 _headers.clear();
00974
00975 for (StringSet::iterator it = _defines.begin(); it != _defines.end(); it++) {
00976 free(*it);
00977 }
00978 _defines.clear();
00979
00980 for (StringSet::iterator it = _include_dirs.begin(); it != _include_dirs.end(); it++) {
00981 free(*it);
00982 }
00983 _include_dirs.clear();
00984
00985 return 0;
00986 }