OpenTTD
depend.cpp
Go to the documentation of this file.
1 /* $Id: depend.cpp 26060 2013-11-23 13:16:45Z rubidium $ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * 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.
6  * 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.
7  * 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/>.
8  */
9 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <limits.h>
28 #include <unistd.h>
29 #include <map>
30 #include <set>
31 #include <stack>
32 #include <cassert>
33 
42 #define lengthof(x) (sizeof(x) / sizeof(x[0]))
43 
50 #define lastof(x) (&x[lengthof(x) - 1])
51 
68 char *strecpy(char *dst, const char *src, const char *last)
69 {
70  assert(dst <= last);
71  while (dst != last && *src != '\0') {
72  *dst++ = *src++;
73  }
74  *dst = '\0';
75 
76  if (dst == last && *src != '\0') {
77  fprintf(stderr, "String too long for destination buffer\n");
78  exit(-3);
79  }
80  return dst;
81 }
82 
99 static char *strecat(char *dst, const char *src, const char *last)
100 {
101  assert(dst <= last);
102  while (*dst != '\0') {
103  if (dst == last) return dst;
104  dst++;
105  }
106 
107  return strecpy(dst, src, last);
108 }
109 
114 static inline void free(const void *ptr)
115 {
116  free(const_cast<void *>(ptr));
117 }
118 
119 #ifndef PATH_MAX
120 
121 # define PATH_MAX 260
122 #endif
123 
125 struct StringCompare {
132  bool operator () (const char *a, const char *b) const
133  {
134  return strcmp(a, b) < 0;
135  }
136 };
138 typedef std::set<const char*, StringCompare> StringSet;
140 typedef std::map<const char*, StringSet*, StringCompare> StringMap;
142 typedef std::pair<const char*, StringSet*> StringMapItem;
143 
152 
156 class File {
157 public:
163  File(const char *filename)
164  {
165  this->fp = fopen(filename, "r");
166  if (this->fp == NULL) {
167  fprintf(stdout, "Could not open %s for reading\n", filename);
168  exit(1);
169  }
170  this->dirname = strdup(filename);
171  char *last = strrchr(this->dirname, '/');
172  if (last != NULL) {
173  *last = '\0';
174  } else {
175  *this->dirname = '\0';
176  }
177  }
178 
181  {
182  fclose(this->fp);
183  free(this->dirname);
184  }
185 
191  char GetChar() const
192  {
193  int c = fgetc(this->fp);
194  return (c == EOF) ? '\0' : c;
195  }
196 
201  const char *GetDirname() const
202  {
203  return this->dirname;
204  }
205 
206 private:
207  FILE *fp;
208  char *dirname;
209 };
210 
212 enum Token {
236 };
237 
239 typedef std::map<const char*, Token, StringCompare> KeywordList;
240 
244 class Lexer {
245 public:
250  Lexer(const File *file) : file(file), current_char('\0'), string(NULL), token(TOKEN_UNKNOWN)
251  {
252  this->keywords["define"] = TOKEN_DEFINE;
253  this->keywords["defined"] = TOKEN_DEFINED;
254  this->keywords["if"] = TOKEN_IF;
255  this->keywords["ifdef"] = TOKEN_IFDEF;
256  this->keywords["ifndef"] = TOKEN_IFNDEF;
257  this->keywords["include"] = TOKEN_INCLUDE;
258  this->keywords["elif"] = TOKEN_ELIF;
259  this->keywords["else"] = TOKEN_ELSE;
260  this->keywords["endif"] = TOKEN_ENDIF;
261  this->keywords["undef"] = TOKEN_UNDEF;
262 
263  /* Initialise currently read character. */
264  this->Next();
265 
266  /* Allocate the buffer. */
267  this->buf_len = 32;
268  this->buf = (char*)malloc(sizeof(*this->buf) * this->buf_len);
269  }
270 
273  {
274  free(this->buf);
275  }
276 
280  void Next()
281  {
282  this->current_char = this->file->GetChar();
283  }
284 
289  Token GetToken() const
290  {
291  return this->token;
292  }
293 
298  const char *GetString() const
299  {
300  return this->string;
301  }
302 
307  void Lex()
308  {
309  for (;;) {
310  free(this->string);
311  this->string = NULL;
312  this->token = TOKEN_UNKNOWN;
313 
314  switch (this->current_char) {
315  /* '\0' means End-Of-File */
316  case '\0': this->token = TOKEN_END; return;
317 
318  /* Skip some chars, as they don't do anything */
319  case '\t': this->Next(); break;
320  case '\r': this->Next(); break;
321  case ' ': this->Next(); break;
322 
323  case '\\':
324  this->Next();
325  if (this->current_char == '\n') this->Next();
326  break;
327 
328  case '\n':
329  this->token = TOKEN_EOL;
330  this->Next();
331  return;
332 
333  case '#':
334  this->token = TOKEN_SHARP;
335  this->Next();
336  return;
337 
338  case '"':
339  this->ReadString('"', TOKEN_LOCAL);
340  this->Next();
341  return;
342 
343  case '<':
344  this->ReadString('>', TOKEN_GLOBAL);
345  this->Next();
346  return;
347 
348  case '&':
349  this->Next();
350  if (this->current_char == '&') {
351  this->Next();
352  this->token = TOKEN_AND;
353  return;
354  }
355  break;
356 
357  case '|':
358  this->Next();
359  if (this->current_char == '|') {
360  this->Next();
361  this->token = TOKEN_OR;
362  return;
363  }
364  break;
365 
366  case '(':
367  this->Next();
368  this->token = TOKEN_OPEN;
369  return;
370 
371  case ')':
372  this->Next();
373  this->token = TOKEN_CLOSE;
374  return;
375 
376  case '!':
377  this->Next();
378  if (this->current_char != '=') {
379  this->token = TOKEN_NOT;
380  return;
381  }
382  break;
383 
384  /* Possible begin of comment */
385  case '/':
386  this->Next();
387  switch (this->current_char) {
388  case '*': {
389  this->Next();
390  char previous_char = '\0';
391  while ((this->current_char != '/' || previous_char != '*') && this->current_char != '\0') {
392  previous_char = this->current_char;
393  this->Next();
394  }
395  this->Next();
396  break;
397  }
398  case '/': while (this->current_char != '\n' && this->current_char != '\0') this->Next(); break;
399  default: break;
400  }
401  break;
402 
403  default:
404  if (isalpha(this->current_char) || this->current_char == '_') {
405  /* If the name starts with a letter, it is an identifier */
406  this->ReadIdentifier();
407  return;
408  }
409  if (isdigit(this->current_char)) {
410  bool zero = this->current_char == '0';
411  this->Next();
412  if (this->current_char == 'x' || this->current_char == 'X') Next();
413  while (isdigit(this->current_char) || this->current_char == '.' || (this->current_char >= 'a' && this->current_char <= 'f') || (this->current_char >= 'A' && this->current_char <= 'F')) {
414  zero &= this->current_char == '0';
415  this->Next();
416  }
417  if (zero) this->token = TOKEN_ZERO;
418  return;
419  }
420  this->Next();
421  break;
422  }
423  }
424  }
425 
426 private:
432  Token FindKeyword(const char *name) const
433  {
434  KeywordList::const_iterator it = this->keywords.find(name);
435  if (it == this->keywords.end()) return TOKEN_IDENTIFIER;
436  return (*it).second;
437  }
438 
443  {
444  size_t count = 0;
445 
446  /* Read the rest of the identifier */
447  do {
448  this->buf[count++] = this->current_char;
449  this->Next();
450 
451  if (count >= buf_len) {
452  /* Scale the buffer if required */
453  this->buf_len *= 2;
454  this->buf = (char *)realloc(this->buf, sizeof(*this->buf) * this->buf_len);
455  }
456  } while ((isalpha(this->current_char) || this->current_char == '_' || isdigit(this->current_char)));
457  this->buf[count] = '\0';
458 
459  free(this->string);
460  this->string = strdup(this->buf);
461  this->token = FindKeyword(this->string);
462  }
463 
469  void ReadString(char end, Token token)
470  {
471  size_t count = 0;
472  this->Next();
473  while (this->current_char != end && this->current_char != ')' && this->current_char != '\n' && this->current_char != '\0') {
474  this->buf[count++] = this->current_char;
475  this->Next();
476 
477  if (count >= this->buf_len) {
478  /* Scale the buffer if required */
479  this->buf_len *= 2;
480  this->buf = (char *)realloc(this->buf, sizeof(*this->buf) * this->buf_len);
481  }
482  }
483  this->buf[count] = '\0';
484  free(this->string);
485  this->string = strdup(this->buf);
486  this->token = token;
487  }
488 
489  const File *file;
491  char *string;
493  char *buf;
494  size_t buf_len;
496 };
497 
508 const char *GeneratePath(const char *dirname, const char *filename, bool local)
509 {
510  if (local) {
511  if (access(filename, R_OK) == 0) return strdup(filename);
512 
513  char path[PATH_MAX];
514  strecpy(path, dirname, lastof(path));
515  const char *p = filename;
516  /* Remove '..' from the begin of the filename. */
517  while (*p == '.') {
518  if (*(++p) == '.') {
519  char *s = strrchr(path, '/');
520  if (s != NULL) *s = '\0';
521  p += 2;
522  }
523  }
524  strecat(path, "/", lastof(path));
525  strecat(path, p, lastof(path));
526 
527  if (access(path, R_OK) == 0) return strdup(path);
528  }
529 
530  for (StringSet::iterator it = _include_dirs.begin(); it != _include_dirs.end(); it++) {
531  char path[PATH_MAX];
532  strecpy(path, *it, lastof(path));
533  const char *p = filename;
534  /* Remove '..' from the begin of the filename. */
535  while (*p == '.') {
536  if (*(++p) == '.') {
537  char *s = strrchr(path, '/');
538  if (s != NULL) *s = '\0';
539  p += 2;
540  }
541  }
542  strecat(path, "/", lastof(path));
543  strecat(path, p, lastof(path));
544 
545  if (access(path, R_OK) == 0) return strdup(path);
546  }
547 
548  return NULL;
549 }
550 
558 bool ExpressionDefined(Lexer *lexer, StringSet *defines, bool verbose);
559 
567 bool ExpressionOr(Lexer *lexer, StringSet *defines, bool verbose);
568 
577 bool ExpressionNot(Lexer *lexer, StringSet *defines, bool verbose)
578 {
579  if (lexer->GetToken() == TOKEN_NOT) {
580  if (verbose) fprintf(stderr, "!");
581  lexer->Lex();
582  bool value = !ExpressionDefined(lexer, defines, verbose);
583  if (verbose) fprintf(stderr, "[%d]", value);
584  return value;
585  }
586 
587  if (lexer->GetToken() == TOKEN_OPEN) {
588  if (verbose) fprintf(stderr, "(");
589  lexer->Lex();
590  bool value = ExpressionOr(lexer, defines, verbose);
591  if (verbose) fprintf(stderr, ")[%d]", value);
592  lexer->Lex();
593  return value;
594  }
595 
596  if (lexer->GetToken() == TOKEN_ZERO) {
597  if (verbose) fprintf(stderr, "0");
598  lexer->Lex();
599  if (verbose) fprintf(stderr, "[0]");
600  return false;
601  }
602 
603  bool first = true;
604  while (lexer->GetToken() == TOKEN_UNKNOWN || lexer->GetToken() == TOKEN_IDENTIFIER) {
605  if (verbose && first) fprintf(stderr, "<assumed true>");
606  first = false;
607  lexer->Lex();
608  }
609 
610  return true;
611 }
612 
620 bool ExpressionDefined(Lexer *lexer, StringSet *defines, bool verbose)
621 {
622  bool value = ExpressionNot(lexer, defines, verbose);
623 
624  if (lexer->GetToken() != TOKEN_DEFINED) return value;
625  lexer->Lex();
626  if (verbose) fprintf(stderr, "defined");
627  bool open = (lexer->GetToken() == TOKEN_OPEN);
628  if (open) lexer->Lex();
629  if (verbose) fprintf(stderr, open ? "(" : " ");
630  if (lexer->GetToken() == TOKEN_IDENTIFIER) {
631  if (verbose) fprintf(stderr, "%s", lexer->GetString());
632  value = defines->find(lexer->GetString()) != defines->end();
633  }
634  if (open) {
635  if (verbose) fprintf(stderr, ")");
636  lexer->Lex();
637  }
638  lexer->Lex();
639  if (verbose) fprintf(stderr, "[%d]", value);
640  return value;
641 }
642 
650 bool ExpressionAnd(Lexer *lexer, StringSet *defines, bool verbose)
651 {
652  bool value = ExpressionDefined(lexer, defines, verbose);
653 
654  for (;;) {
655  if (lexer->GetToken() != TOKEN_AND) return value;
656  if (verbose) fprintf(stderr, " && ");
657  lexer->Lex();
658  value = value && ExpressionDefined(lexer, defines, verbose);
659  }
660 }
661 
669 bool ExpressionOr(Lexer *lexer, StringSet *defines, bool verbose)
670 {
671  bool value = ExpressionAnd(lexer, defines, verbose);
672 
673  for (;;) {
674  if (lexer->GetToken() != TOKEN_OR) return value;
675  if (verbose) fprintf(stderr, " || ");
676  lexer->Lex();
677  value = value || ExpressionAnd(lexer, defines, verbose);
678  }
679 }
680 
682 enum Ignore {
686 };
687 
695 void ScanFile(const char *filename, const char *ext, bool header, bool verbose)
696 {
697  static StringSet defines;
698  static std::stack<Ignore> ignore;
699  /* Copy in the default defines (parameters of depend) */
700  if (!header) {
701  for (StringSet::iterator it = _defines.begin(); it != _defines.end(); it++) {
702  defines.insert(strdup(*it));
703  }
704  }
705 
706  File file(filename);
707  Lexer lexer(&file);
708 
709  /* Start the lexing! */
710  lexer.Lex();
711 
712  while (lexer.GetToken() != TOKEN_END) {
713  switch (lexer.GetToken()) {
714  /* We reached the end of the file... yay, we're done! */
715  case TOKEN_END: break;
716 
717  /* The line started with a # (minus whitespace) */
718  case TOKEN_SHARP:
719  lexer.Lex();
720  switch (lexer.GetToken()) {
721  case TOKEN_INCLUDE:
722  if (verbose) fprintf(stderr, "%s #include ", filename);
723  lexer.Lex();
724  switch (lexer.GetToken()) {
725  case TOKEN_LOCAL:
726  case TOKEN_GLOBAL: {
727  if (verbose) fprintf(stderr, "%s", lexer.GetString());
728  if (!ignore.empty() && ignore.top() != NOT_IGNORE) {
729  if (verbose) fprintf(stderr, " (ignored)");
730  break;
731  }
732  const char *h = GeneratePath(file.GetDirname(), lexer.GetString(), lexer.GetToken() == TOKEN_LOCAL);
733  if (h != NULL) {
734  StringMap::iterator it = _headers.find(h);
735  if (it == _headers.end()) {
736  it = (_headers.insert(StringMapItem(strdup(h), new StringSet()))).first;
737  if (verbose) fprintf(stderr, "\n");
738  ScanFile(h, ext, true, verbose);
739  }
740  StringMap::iterator curfile;
741  if (header) {
742  curfile = _headers.find(filename);
743  } else {
744  /* Replace the extension with the provided extension of '.o'. */
745  char path[PATH_MAX];
746  strecpy(path, filename, lastof(path));
747  *(strrchr(path, '.')) = '\0';
748  strecat(path, ext != NULL ? ext : ".o", lastof(path));
749  curfile = _files.find(path);
750  if (curfile == _files.end()) {
751  curfile = (_files.insert(StringMapItem(strdup(path), new StringSet()))).first;
752  }
753  }
754  if (it != _headers.end()) {
755  for (StringSet::iterator header = it->second->begin(); header != it->second->end(); header++) {
756  if (curfile->second->find(*header) == curfile->second->end()) curfile->second->insert(strdup(*header));
757  }
758  }
759  if (curfile->second->find(h) == curfile->second->end()) curfile->second->insert(strdup(h));
760  free(h);
761  }
762  }
763  /* FALL THROUGH */
764  default: break;
765  }
766  break;
767 
768  case TOKEN_DEFINE:
769  if (verbose) fprintf(stderr, "%s #define ", filename);
770  lexer.Lex();
771  if (lexer.GetToken() == TOKEN_IDENTIFIER) {
772  if (verbose) fprintf(stderr, "%s", lexer.GetString());
773  if (!ignore.empty() && ignore.top() != NOT_IGNORE) {
774  if (verbose) fprintf(stderr, " (ignored)");
775  break;
776  }
777  if (defines.find(lexer.GetString()) == defines.end()) defines.insert(strdup(lexer.GetString()));
778  lexer.Lex();
779  }
780  break;
781 
782  case TOKEN_UNDEF:
783  if (verbose) fprintf(stderr, "%s #undef ", filename);
784  lexer.Lex();
785  if (lexer.GetToken() == TOKEN_IDENTIFIER) {
786  if (verbose) fprintf(stderr, "%s", lexer.GetString());
787  if (!ignore.empty() && ignore.top() != NOT_IGNORE) {
788  if (verbose) fprintf(stderr, " (ignored)");
789  break;
790  }
791  StringSet::iterator it = defines.find(lexer.GetString());
792  if (it != defines.end()) {
793  free(*it);
794  defines.erase(it);
795  }
796  lexer.Lex();
797  }
798  break;
799 
800  case TOKEN_ENDIF:
801  if (verbose) fprintf(stderr, "%s #endif", filename);
802  lexer.Lex();
803  if (!ignore.empty()) ignore.pop();
804  if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not ");
805  break;
806 
807  case TOKEN_ELSE: {
808  if (verbose) fprintf(stderr, "%s #else", filename);
809  lexer.Lex();
810  Ignore last = ignore.empty() ? NOT_IGNORE : ignore.top();
811  if (!ignore.empty()) ignore.pop();
812  if (ignore.empty() || ignore.top() == NOT_IGNORE) {
813  ignore.push(last == IGNORE_UNTIL_ELSE ? NOT_IGNORE : IGNORE_UNTIL_ENDIF);
814  } else {
815  ignore.push(IGNORE_UNTIL_ENDIF);
816  }
817  if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not ");
818  break;
819  }
820 
821  case TOKEN_ELIF: {
822  if (verbose) fprintf(stderr, "%s #elif ", filename);
823  lexer.Lex();
824  Ignore last = ignore.empty() ? NOT_IGNORE : ignore.top();
825  if (!ignore.empty()) ignore.pop();
826  if (ignore.empty() || ignore.top() == NOT_IGNORE) {
827  bool value = ExpressionOr(&lexer, &defines, verbose);
828  ignore.push(last == IGNORE_UNTIL_ELSE ? (value ? NOT_IGNORE : IGNORE_UNTIL_ELSE) : IGNORE_UNTIL_ENDIF);
829  } else {
830  ignore.push(IGNORE_UNTIL_ENDIF);
831  }
832  if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not ");
833  break;
834  }
835 
836  case TOKEN_IF: {
837  if (verbose) fprintf(stderr, "%s #if ", filename);
838  lexer.Lex();
839  if (ignore.empty() || ignore.top() == NOT_IGNORE) {
840  bool value = ExpressionOr(&lexer, &defines, verbose);
841  ignore.push(value ? NOT_IGNORE : IGNORE_UNTIL_ELSE);
842  } else {
843  ignore.push(IGNORE_UNTIL_ENDIF);
844  }
845  if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not ");
846  break;
847  }
848 
849  case TOKEN_IFDEF:
850  if (verbose) fprintf(stderr, "%s #ifdef ", filename);
851  lexer.Lex();
852  if (lexer.GetToken() == TOKEN_IDENTIFIER) {
853  bool value = defines.find(lexer.GetString()) != defines.end();
854  if (verbose) fprintf(stderr, "%s[%d]", lexer.GetString(), value);
855  if (ignore.empty() || ignore.top() == NOT_IGNORE) {
856  ignore.push(value ? NOT_IGNORE : IGNORE_UNTIL_ELSE);
857  } else {
858  ignore.push(IGNORE_UNTIL_ENDIF);
859  }
860  }
861  if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not ");
862  break;
863 
864  case TOKEN_IFNDEF:
865  if (verbose) fprintf(stderr, "%s #ifndef ", filename);
866  lexer.Lex();
867  if (lexer.GetToken() == TOKEN_IDENTIFIER) {
868  bool value = defines.find(lexer.GetString()) != defines.end();
869  if (verbose) fprintf(stderr, "%s[%d]", lexer.GetString(), value);
870  if (ignore.empty() || ignore.top() == NOT_IGNORE) {
871  ignore.push(!value ? NOT_IGNORE : IGNORE_UNTIL_ELSE);
872  } else {
873  ignore.push(IGNORE_UNTIL_ENDIF);
874  }
875  }
876  if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not ");
877  break;
878 
879  default:
880  if (verbose) fprintf(stderr, "%s #<unknown>", filename);
881  lexer.Lex();
882  break;
883  }
884  if (verbose) fprintf(stderr, "\n");
885  /* FALL THROUGH */
886  default:
887  /* Ignore the rest of the garbage on this line */
888  while (lexer.GetToken() != TOKEN_EOL && lexer.GetToken() != TOKEN_END) lexer.Lex();
889  lexer.Lex();
890  break;
891  }
892  }
893 
894  if (!header) {
895  for (StringSet::iterator it = defines.begin(); it != defines.end(); it++) {
896  free(*it);
897  }
898  defines.clear();
899  while (!ignore.empty()) ignore.pop();
900  }
901 }
902 
909 int main(int argc, char *argv[])
910 {
911  bool ignorenext = true;
912  char *filename = NULL;
913  char *ext = NULL;
914  char *delimiter = NULL;
915  bool append = false;
916  bool verbose = false;
917 
918  for (int i = 0; i < argc; i++) {
919  if (ignorenext) {
920  ignorenext = false;
921  continue;
922  }
923  if (argv[i][0] == '-') {
924  /* Append */
925  if (strncmp(argv[i], "-a", 2) == 0) append = true;
926  /* Include dir */
927  if (strncmp(argv[i], "-I", 2) == 0) {
928  if (argv[i][2] == '\0') {
929  i++;
930  _include_dirs.insert(strdup(argv[i]));
931  } else {
932  _include_dirs.insert(strdup(&argv[i][2]));
933  }
934  continue;
935  }
936  /* Define */
937  if (strncmp(argv[i], "-D", 2) == 0) {
938  char *p = strchr(argv[i], '=');
939  if (p != NULL) *p = '\0';
940  _defines.insert(strdup(&argv[i][2]));
941  continue;
942  }
943  /* Output file */
944  if (strncmp(argv[i], "-f", 2) == 0) {
945  if (filename != NULL) continue;
946  filename = strdup(&argv[i][2]);
947  continue;
948  }
949  /* Object file extension */
950  if (strncmp(argv[i], "-o", 2) == 0) {
951  if (ext != NULL) continue;
952  ext = strdup(&argv[i][2]);
953  continue;
954  }
955  /* Starting string delimiter */
956  if (strncmp(argv[i], "-s", 2) == 0) {
957  if (delimiter != NULL) continue;
958  delimiter = strdup(&argv[i][2]);
959  continue;
960  }
961  /* Verbose */
962  if (strncmp(argv[i], "-v", 2) == 0) verbose = true;
963  continue;
964  }
965  ScanFile(argv[i], ext, false, verbose);
966  }
967 
968  /* Default output file is Makefile */
969  if (filename == NULL) filename = strdup("Makefile");
970 
971  /* Default delimiter string */
972  if (delimiter == NULL) delimiter = strdup("# DO NOT DELETE");
973 
974  char backup[PATH_MAX];
975  strecpy(backup, filename, lastof(backup));
976  strecat(backup, ".bak", lastof(backup));
977 
978  char *content = NULL;
979  long size = 0;
980 
981  /* Read in the current file; so we can overwrite everything from the
982  * end of non-depend data marker down till the end. */
983  FILE *src = fopen(filename, "rb");
984  if (src != NULL) {
985  fseek(src, 0, SEEK_END);
986  if ((size = ftell(src)) < 0) {
987  fprintf(stderr, "Could not read %s\n", filename);
988  exit(-2);
989  }
990  rewind(src);
991  content = (char*)malloc(size * sizeof(*content));
992  if (fread(content, 1, size, src) != (size_t)size) {
993  fprintf(stderr, "Could not read %s\n", filename);
994  exit(-2);
995  }
996  fclose(src);
997  }
998 
999  FILE *dst = fopen(filename, "w");
1000  bool found_delimiter = false;
1001 
1002  if (size != 0) {
1003  src = fopen(backup, "wb");
1004  if (fwrite(content, 1, size, src) != (size_t)size) {
1005  fprintf(stderr, "Could not write %s\n", filename);
1006  exit(-2);
1007  }
1008  fclose(src);
1009 
1010  /* Then append it to the real file. */
1011  src = fopen(backup, "rb");
1012  while (fgets(content, size, src) != NULL) {
1013  fputs(content, dst);
1014  if (!strncmp(content, delimiter, strlen(delimiter))) found_delimiter = true;
1015  if (!append && found_delimiter) break;
1016  }
1017  fclose(src);
1018  }
1019  if (!found_delimiter) fprintf(dst, "\n%s\n", delimiter);
1020 
1021  for (StringMap::iterator it = _files.begin(); it != _files.end(); it++) {
1022  for (StringSet::iterator h = it->second->begin(); h != it->second->end(); h++) {
1023  fprintf(dst, "%s: %s\n", it->first, *h);
1024  }
1025  }
1026 
1027  /* Clean up our mess. */
1028  fclose(dst);
1029 
1030  free(delimiter);
1031  free(filename);
1032  free(ext);
1033  free(content);
1034 
1035  for (StringMap::iterator it = _files.begin(); it != _files.end(); it++) {
1036  for (StringSet::iterator h = it->second->begin(); h != it->second->end(); h++) {
1037  free(*h);
1038  }
1039  it->second->clear();
1040  delete it->second;
1041  free(it->first);
1042  }
1043  _files.clear();
1044 
1045  for (StringMap::iterator it = _headers.begin(); it != _headers.end(); it++) {
1046  for (StringSet::iterator h = it->second->begin(); h != it->second->end(); h++) {
1047  free(*h);
1048  }
1049  it->second->clear();
1050  delete it->second;
1051  free(it->first);
1052  }
1053  _headers.clear();
1054 
1055  for (StringSet::iterator it = _defines.begin(); it != _defines.end(); it++) {
1056  free(*it);
1057  }
1058  _defines.clear();
1059 
1060  for (StringSet::iterator it = _include_dirs.begin(); it != _include_dirs.end(); it++) {
1061  free(*it);
1062  }
1063  _include_dirs.clear();
1064 
1065  return 0;
1066 }
void Next()
Read the next character into &#39;current_char&#39;.
Definition: depend.cpp:280
Read a local include.
Definition: depend.cpp:217
bool ExpressionNot(Lexer *lexer, StringSet *defines, bool verbose)
Try to parse a &#39;!expr&#39; expression.
Definition: depend.cpp:577
static char * strecat(char *dst, const char *src, const char *last)
Appends characters from one string to another.
Definition: depend.cpp:99
File(const char *filename)
Create the helper by opening the given file.
Definition: depend.cpp:163
const File * file
The file to read from.
Definition: depend.cpp:489
bool ExpressionDefined(Lexer *lexer, StringSet *defines, bool verbose)
Try to parse a &#39;defined(expr)&#39; expression.
Definition: depend.cpp:620
char * buf
Temporary buffer.
Definition: depend.cpp:493
End of document.
Definition: depend.cpp:214
char * dirname
The directory of the file.
Definition: depend.cpp:208
std::pair< const char *, StringSet * > StringMapItem
Pair of C-style string and a set of C-style strings.
Definition: depend.cpp:142
bool ExpressionAnd(Lexer *lexer, StringSet *defines, bool verbose)
Try to parse a &#39;expr && expr&#39; expression.
Definition: depend.cpp:650
(#)ifdef in code
Definition: depend.cpp:222
void ReadIdentifier()
Read an identifier.
Definition: depend.cpp:442
Lexer of a file.
Definition: depend.cpp:244
size_t buf_len
Length of the temporary buffer.
Definition: depend.cpp:494
No ignoring.
Definition: depend.cpp:683
&#39;0&#39; within #if expression
Definition: depend.cpp:234
const char * GeneratePath(const char *dirname, const char *filename, bool local)
Generate a path from a directory name and a relative filename.
Definition: depend.cpp:508
#define lastof(x)
Get the last element of an fixed size array.
Definition: depend.cpp:50
Read a global include.
Definition: depend.cpp:218
&#39;&&&#39; within #if expression
Definition: depend.cpp:229
static StringMap _headers
Dependencies of headers.
Definition: depend.cpp:149
char current_char
The current character to process.
Definition: depend.cpp:490
const char * GetDirname() const
Get the directory name of the file.
Definition: depend.cpp:201
&#39;(&#39; within #if expression
Definition: depend.cpp:231
Lexer(const File *file)
Create the lexer and fill the keywords table.
Definition: depend.cpp:250
static StringSet _include_dirs
Include directory to search in.
Definition: depend.cpp:145
int main(int argc, char *argv[])
Entry point.
Definition: depend.cpp:909
~Lexer()
Free everything.
Definition: depend.cpp:272
(#)include in code
Definition: depend.cpp:235
Unknown token.
Definition: depend.cpp:213
bool operator()(const char *a, const char *b) const
Compare two strings.
(#)if in code
Definition: depend.cpp:221
char GetChar() const
Get a single character from the file.
Definition: depend.cpp:191
char * string
Currently processed string.
Definition: depend.cpp:491
bool ExpressionOr(Lexer *lexer, StringSet *defines, bool verbose)
Try to parse a &#39;expr || expr&#39; expression.
Definition: depend.cpp:669
Ignore till a #endif is reached.
Definition: depend.cpp:685
End of line.
Definition: depend.cpp:215
(#)ifndef in code
Definition: depend.cpp:223
static StringSet _defines
The current &#39;active&#39; defines.
Definition: depend.cpp:151
(#)define in code
Definition: depend.cpp:220
Token
A token returned by the tokenizer.
Definition: depend.cpp:212
&#39;)&#39; within #if expression
Definition: depend.cpp:232
static StringMap _files
Files that have been parsed/handled with their dependencies.
Definition: depend.cpp:147
Ignore till a #else is reached.
Definition: depend.cpp:684
&#39;||&#39; within #if expression
Definition: depend.cpp:228
void Lex()
Perform the lexing/tokenizing of the file till we can return something that must be parsed...
Definition: depend.cpp:307
(#)else in code
Definition: depend.cpp:225
(#)elif in code
Definition: depend.cpp:224
std::set< const char *, StringCompare > StringSet
Set of C-style strings.
Definition: depend.cpp:138
Token GetToken() const
Get the current token.
Definition: depend.cpp:289
char * strecpy(char *dst, const char *src, const char *last)
Copies characters from one buffer to another.
Definition: depend.cpp:68
#define PATH_MAX
The maximum length of paths, if we don&#39;t know it.
Definition: depend.cpp:121
void ScanFile(const char *filename, const char *ext, bool header, bool verbose)
Scan a file for includes, defines and the lot.
Definition: depend.cpp:695
&#39;!&#39; within #if expression
Definition: depend.cpp:233
~File()
Free everything we have allocated.
Definition: depend.cpp:180
&#39;defined&#39; within #if expression
Definition: depend.cpp:230
const char * GetString() const
Read the currenty processed string.
Definition: depend.cpp:298
Token FindKeyword(const char *name) const
The token based on keyword with a given name.
Definition: depend.cpp:432
Token token
The current token to process.
Definition: depend.cpp:492
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
Definition: depend.cpp:114
std::map< const char *, Token, StringCompare > KeywordList
Mapping from a C-style keyword representation to a Token.
Definition: depend.cpp:239
Ignore
Enumerator to tell how long to ignore &#39;stuff&#39;.
Definition: depend.cpp:682
Identifier within the data.
Definition: depend.cpp:219
KeywordList keywords
All keywords we know of.
Definition: depend.cpp:495
Helper class to read a file.
Definition: depend.cpp:156
std::map< const char *, StringSet *, StringCompare > StringMap
Mapping of C-style string to a set of C-style strings.
Definition: depend.cpp:140
Comparator for strings.
(#)endif in code
Definition: depend.cpp:226
(#)undef in code
Definition: depend.cpp:227
FILE * fp
The currently opened file.
Definition: depend.cpp:207
void ReadString(char end, Token token)
Read a string up to a given character, then set the given token.
Definition: depend.cpp:469
character, usually telling something important comes.
Definition: depend.cpp:216