resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmDependsJavaParserHelper.cxx
1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #include "cmDependsJavaParserHelper.h"
4
5 #include <cstdio>
6 #include <cstdlib>
7 #include <cstring>
8 #include <iostream>
9 #include <utility>
10
11 #include <cm/memory>
12 #include <cm/string_view>
13
14 #include "cmsys/FStream.hxx"
15
16 #include "cmDependsJavaLexer.h"
17 #include "cmSystemTools.h"
18
19 int cmDependsJava_yyparse(yyscan_t yyscanner);
20
21 cmDependsJavaParserHelper::cmDependsJavaParserHelper()
22 {
23   this->CurrentDepth = 0;
24
25   this->UnionsAvailable = 0;
26   this->LastClassId = 0;
27
28   CurrentClass tl;
29   tl.Name = "*";
30   this->ClassStack.push_back(std::move(tl));
31 }
32
33 cmDependsJavaParserHelper::~cmDependsJavaParserHelper()
34 {
35   this->CleanupParser();
36 }
37
38 void cmDependsJavaParserHelper::CurrentClass::AddFileNamesForPrinting(
39   std::vector<std::string>* files, const char* prefix, const char* sep) const
40 {
41   std::string rname;
42   if (prefix) {
43     rname += prefix;
44     rname += sep;
45   }
46   rname += this->Name;
47   files->push_back(rname);
48   for (CurrentClass const& nc : this->NestedClasses) {
49     nc.AddFileNamesForPrinting(files, rname.c_str(), sep);
50   }
51 }
52
53 void cmDependsJavaParserHelper::DeallocateParserType(char** pt)
54 {
55   if (!pt) {
56     return;
57   }
58   if (!*pt) {
59     return;
60   }
61   *pt = nullptr;
62   this->UnionsAvailable--;
63 }
64
65 void cmDependsJavaParserHelper::AddClassFound(const char* sclass)
66 {
67   if (!sclass) {
68     return;
69   }
70   for (std::string const& cf : this->ClassesFound) {
71     if (cf == sclass) {
72       return;
73     }
74   }
75   this->ClassesFound.emplace_back(sclass);
76 }
77
78 void cmDependsJavaParserHelper::AddPackagesImport(const char* sclass)
79 {
80   for (std::string const& pi : this->PackagesImport) {
81     if (pi == sclass) {
82       return;
83     }
84   }
85   this->PackagesImport.emplace_back(sclass);
86 }
87
88 void cmDependsJavaParserHelper::SafePrintMissing(const char* str, int line,
89                                                  int cnt)
90 {
91   if (str) {
92     std::cout << line << " String " << cnt << " exists: ";
93     unsigned int cc;
94     for (cc = 0; cc < strlen(str); cc++) {
95       unsigned char ch = str[cc];
96       if (ch >= 32 && ch <= 126) {
97         std::cout << static_cast<char>(ch);
98       } else {
99         std::cout << "<" << static_cast<int>(ch) << ">";
100         break;
101       }
102     }
103     std::cout << "- " << strlen(str) << std::endl;
104   }
105 }
106 void cmDependsJavaParserHelper::Print(const char* place, const char* str) const
107 {
108   if (this->Verbose) {
109     std::cout << "[" << place << "=" << str << "]" << std::endl;
110   }
111 }
112
113 void cmDependsJavaParserHelper::CombineUnions(char** out, const char* in1,
114                                               char** in2, const char* sep)
115 {
116   size_t len = 1;
117   if (in1) {
118     len += strlen(in1);
119   }
120   if (*in2) {
121     len += strlen(*in2);
122   }
123   if (sep) {
124     len += strlen(sep);
125   }
126   *out = new char[len];
127   *out[0] = 0;
128   if (in1) {
129     strcat(*out, in1);
130   }
131   if (sep) {
132     strcat(*out, sep);
133   }
134   if (*in2) {
135     strcat(*out, *in2);
136   }
137   if (*in2) {
138     this->DeallocateParserType(in2);
139   }
140   this->UnionsAvailable++;
141 }
142
143 void cmDependsJavaParserHelper::CheckEmpty(
144   int line, int cnt, cmDependsJavaParserHelper::ParserType* pt)
145 {
146   int cc;
147   int kk = -cnt + 1;
148   for (cc = 1; cc <= cnt; cc++) {
149     cmDependsJavaParserHelper::ParserType* cpt = pt + kk;
150     this->SafePrintMissing(cpt->str, line, cc);
151     kk++;
152   }
153 }
154
155 void cmDependsJavaParserHelper::PrepareElement(
156   cmDependsJavaParserHelper::ParserType* me)
157 {
158   // Inititalize self
159   me->str = nullptr;
160 }
161
162 void cmDependsJavaParserHelper::AllocateParserType(
163   cmDependsJavaParserHelper::ParserType* pt, const char* str, int len)
164 {
165   pt->str = nullptr;
166   if (len == 0) {
167     len = static_cast<int>(strlen(str));
168   }
169   if (len == 0) {
170     return;
171   }
172   this->UnionsAvailable++;
173   auto up = cm::make_unique<char[]>(len + 1);
174   pt->str = up.get();
175   strncpy(pt->str, str, len);
176   pt->str[len] = 0;
177   this->Allocates.push_back(std::move(up));
178 }
179
180 void cmDependsJavaParserHelper::StartClass(const char* cls)
181 {
182   CurrentClass cl;
183   cl.Name = cls;
184   this->ClassStack.push_back(std::move(cl));
185
186   this->CurrentDepth++;
187 }
188
189 void cmDependsJavaParserHelper::EndClass()
190 {
191   if (this->ClassStack.empty()) {
192     std::cerr << "Error when parsing. Current class is null" << std::endl;
193     abort();
194   }
195   if (this->ClassStack.size() <= 1) {
196     std::cerr << "Error when parsing. Parent class is null" << std::endl;
197     abort();
198   }
199   CurrentClass& current = this->ClassStack.back();
200   CurrentClass& parent = this->ClassStack[this->ClassStack.size() - 2];
201   this->CurrentDepth--;
202   parent.NestedClasses.push_back(current);
203   this->ClassStack.pop_back();
204 }
205
206 void cmDependsJavaParserHelper::PrintClasses()
207 {
208   if (this->ClassStack.empty()) {
209     std::cerr << "Error when parsing. No classes on class stack" << std::endl;
210     abort();
211   }
212   for (std::string const& f : this->GetFilesProduced()) {
213     std::cout << "  " << f << ".class" << std::endl;
214   }
215 }
216
217 std::vector<std::string> cmDependsJavaParserHelper::GetFilesProduced()
218 {
219   std::vector<std::string> files;
220   CurrentClass const& toplevel = this->ClassStack.front();
221   for (CurrentClass const& nc : toplevel.NestedClasses) {
222     nc.AddFileNamesForPrinting(&files, nullptr, "$");
223   }
224   return files;
225 }
226
227 int cmDependsJavaParserHelper::ParseString(const char* str, int verb)
228 {
229   if (!str) {
230     return 0;
231   }
232   this->Verbose = verb;
233   this->InputBuffer = str;
234   this->InputBufferPos = 0;
235   this->CurrentLine = 0;
236
237   yyscan_t yyscanner;
238   cmDependsJava_yylex_init(&yyscanner);
239   cmDependsJava_yyset_extra(this, yyscanner);
240   int res = cmDependsJava_yyparse(yyscanner);
241   cmDependsJava_yylex_destroy(yyscanner);
242   if (res != 0) {
243     std::cout << "JP_Parse returned: " << res << std::endl;
244     return 0;
245   }
246
247   if (verb) {
248     if (!this->CurrentPackage.empty()) {
249       std::cout << "Current package is: " << this->CurrentPackage << std::endl;
250     }
251     std::cout << "Imports packages:";
252     if (!this->PackagesImport.empty()) {
253       std::vector<std::string>::iterator it;
254       for (it = this->PackagesImport.begin(); it != this->PackagesImport.end();
255            ++it) {
256         std::cout << " " << *it;
257       }
258     }
259     std::cout << std::endl;
260     std::cout << "Depends on:";
261     if (!this->ClassesFound.empty()) {
262       for (std::string const& cf : this->ClassesFound) {
263         std::cout << " " << cf;
264       }
265     }
266     std::cout << std::endl;
267     std::cout << "Generated files:" << std::endl;
268     this->PrintClasses();
269     if (this->UnionsAvailable != 0) {
270       std::cout << "There are still " << this->UnionsAvailable
271                 << " unions available" << std::endl;
272     }
273   }
274   this->CleanupParser();
275   return 1;
276 }
277
278 void cmDependsJavaParserHelper::CleanupParser()
279 {
280   this->Allocates.clear();
281 }
282
283 int cmDependsJavaParserHelper::LexInput(char* buf, int maxlen)
284 {
285   if (maxlen < 1) {
286     return 0;
287   }
288   if (this->InputBufferPos < this->InputBuffer.size()) {
289     buf[0] = this->InputBuffer[this->InputBufferPos++];
290     if (buf[0] == '\n') {
291       this->CurrentLine++;
292     }
293     return 1;
294   }
295   buf[0] = '\n';
296   return 0;
297 }
298 void cmDependsJavaParserHelper::Error(const char* str)
299 {
300   unsigned long pos = static_cast<unsigned long>(this->InputBufferPos);
301   fprintf(stderr, "JPError: %s (%lu / Line: %d)\n", str, pos,
302           this->CurrentLine);
303   std::cerr << "String: ["
304             << cm::string_view{ this->InputBuffer }.substr(
305                  this->InputBufferPos, 30)
306             << "]" << std::endl;
307 }
308
309 void cmDependsJavaParserHelper::UpdateCombine(const char* str1,
310                                               const char* str2)
311 {
312   if (this->CurrentCombine.empty() && str1 != nullptr) {
313     this->CurrentCombine = str1;
314   }
315   this->CurrentCombine += ".";
316   this->CurrentCombine += str2;
317 }
318
319 int cmDependsJavaParserHelper::ParseFile(const char* file)
320 {
321   if (!cmSystemTools::FileExists(file)) {
322     return 0;
323   }
324   cmsys::ifstream ifs(file);
325   if (!ifs) {
326     return 0;
327   }
328
329   std::string fullfile;
330   std::string line;
331   while (cmSystemTools::GetLineFromStream(ifs, line)) {
332     fullfile += line + "\n";
333   }
334   return this->ParseString(fullfile.c_str(), 0);
335 }