Imported Upstream version 3.24.0
[platform/upstream/cmake.git] / Tests / CMakeLib / run_compile_commands.cxx
1 #include "cmConfigure.h" // IWYU pragma: keep
2
3 #include <cstdlib>
4 #include <iostream>
5 #include <map>
6 #include <string>
7 #include <utility>
8 #include <vector>
9
10 #include "cmsys/FStream.hxx"
11
12 #include "cmSystemTools.h"
13
14 class CompileCommandParser
15 {
16 public:
17   class CommandType : public std::map<std::string, std::string>
18   {
19   public:
20     std::string const& at(std::string const& k) const
21     {
22       auto i = this->find(k);
23       if (i != this->end()) {
24         return i->second;
25       }
26       static std::string emptyString;
27       return emptyString;
28     }
29   };
30   using TranslationUnitsType = std::vector<CommandType>;
31
32   CompileCommandParser(std::istream& input)
33     : Input(input)
34   {
35   }
36
37   void Parse()
38   {
39     this->NextNonWhitespace();
40     this->ParseTranslationUnits();
41   }
42
43   const TranslationUnitsType& GetTranslationUnits()
44   {
45     return this->TranslationUnits;
46   }
47
48 private:
49   void ParseTranslationUnits()
50   {
51     this->TranslationUnits = TranslationUnitsType();
52     this->ExpectOrDie('[', "at start of compile command file\n");
53     do {
54       this->ParseTranslationUnit();
55       this->TranslationUnits.push_back(this->Command);
56     } while (this->Expect(','));
57     this->ExpectOrDie(']', "at end of array");
58   }
59
60   void ParseTranslationUnit()
61   {
62     this->Command = CommandType();
63     if (!this->Expect('{')) {
64       return;
65     }
66     if (this->Expect('}')) {
67       return;
68     }
69     do {
70       this->ParseString();
71       std::string name = this->String;
72       this->ExpectOrDie(':', "between name and value");
73       this->ParseString();
74       std::string value = this->String;
75       this->Command[name] = value;
76     } while (this->Expect(','));
77     this->ExpectOrDie('}', "at end of object");
78   }
79
80   void ParseString()
81   {
82     this->String = "";
83     if (!this->Expect('"')) {
84       return;
85     }
86     while (!this->Expect('"')) {
87       this->Expect('\\');
88       this->String.append(1, this->C);
89       this->Next();
90     }
91   }
92
93   bool Expect(char c)
94   {
95     if (this->C == c) {
96       this->NextNonWhitespace();
97       return true;
98     }
99     return false;
100   }
101
102   void ExpectOrDie(char c, const std::string& message)
103   {
104     if (!this->Expect(c)) {
105       this->ErrorExit(std::string("'") + c + "' expected " + message + ".");
106     }
107   }
108
109   void NextNonWhitespace()
110   {
111     do {
112       this->Next();
113     } while (this->IsWhitespace());
114   }
115
116   void Next()
117   {
118     this->C = static_cast<char>(this->Input.get());
119     if (this->Input.bad()) {
120       this->ErrorExit("Unexpected end of file.");
121     }
122   }
123
124   void ErrorExit(const std::string& message)
125   {
126     std::cout << "ERROR: " << message;
127     exit(1);
128   }
129
130   bool IsWhitespace() const
131   {
132     return (this->C == ' ' || this->C == '\t' || this->C == '\n' ||
133             this->C == '\r');
134   }
135
136   char C;
137   TranslationUnitsType TranslationUnits;
138   CommandType Command;
139   std::string String;
140   std::istream& Input;
141 };
142
143 int main()
144 {
145   cmsys::ifstream file("compile_commands.json");
146   CompileCommandParser parser(file);
147   parser.Parse();
148   for (auto const& tu : parser.GetTranslationUnits()) {
149     std::vector<std::string> command;
150     cmSystemTools::ParseUnixCommandLine(tu.at("command").c_str(), command);
151     if (!cmSystemTools::RunSingleCommand(command, nullptr, nullptr, nullptr,
152                                          tu.at("directory").c_str())) {
153       std::cout << "ERROR: Failed to run command \"" << command[0] << "\""
154                 << std::endl;
155       exit(1);
156     }
157   }
158   return 0;
159 }