| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file LICENSE.rst or https://cmake.org/licensing for details. */ | |
| #include "cmDependsJavaParserHelper.h" | |
| #include <cstdio> | |
| #include <cstdlib> | |
| #include <cstring> | |
| #include <iostream> | |
| #include <utility> | |
| #include <cm/memory> | |
| #include <cm/string_view> | |
| #include "cmsys/FStream.hxx" | |
| #include "cmDependsJavaLexer.h" | |
| #include "cmStringAlgorithms.h" | |
| #include "cmSystemTools.h" | |
| int cmDependsJava_yyparse(yyscan_t yyscanner); | |
| cmDependsJavaParserHelper::cmDependsJavaParserHelper() | |
| { | |
| this->CurrentDepth = 0; | |
| this->UnionsAvailable = 0; | |
| this->LastClassId = 0; | |
| CurrentClass tl; | |
| tl.Name = "*"; | |
| this->ClassStack.push_back(std::move(tl)); | |
| } | |
| cmDependsJavaParserHelper::~cmDependsJavaParserHelper() | |
| { | |
| this->CleanupParser(); | |
| } | |
| void cmDependsJavaParserHelper::CurrentClass::AddFileNamesForPrinting( | |
| std::vector<std::string>* files, char const* prefix, char const* sep) const | |
| { | |
| std::string rname; | |
| if (prefix) { | |
| rname = cmStrCat(std::move(rname), prefix, sep); | |
| } | |
| rname += this->Name; | |
| files->push_back(rname); | |
| for (CurrentClass const& nc : this->NestedClasses) { | |
| nc.AddFileNamesForPrinting(files, rname.c_str(), sep); | |
| } | |
| } | |
| void cmDependsJavaParserHelper::DeallocateParserType(char** pt) | |
| { | |
| if (!pt) { | |
| return; | |
| } | |
| if (!*pt) { | |
| return; | |
| } | |
| *pt = nullptr; | |
| this->UnionsAvailable--; | |
| } | |
| void cmDependsJavaParserHelper::AddClassFound(char const* sclass) | |
| { | |
| if (!sclass) { | |
| return; | |
| } | |
| for (std::string const& cf : this->ClassesFound) { | |
| if (cf == sclass) { | |
| return; | |
| } | |
| } | |
| this->ClassesFound.emplace_back(sclass); | |
| } | |
| void cmDependsJavaParserHelper::AddPackagesImport(char const* sclass) | |
| { | |
| for (std::string const& pi : this->PackagesImport) { | |
| if (pi == sclass) { | |
| return; | |
| } | |
| } | |
| this->PackagesImport.emplace_back(sclass); | |
| } | |
| void cmDependsJavaParserHelper::SafePrintMissing(char const* str, int line, | |
| int cnt) | |
| { | |
| if (str) { | |
| std::cout << line << " String " << cnt << " exists: "; | |
| unsigned int cc; | |
| for (cc = 0; cc < strlen(str); cc++) { | |
| unsigned char ch = str[cc]; | |
| if (ch >= 32 && ch <= 126) { | |
| std::cout << static_cast<char>(ch); | |
| } else { | |
| std::cout << "<" << static_cast<int>(ch) << ">"; | |
| break; | |
| } | |
| } | |
| std::cout << "- " << strlen(str) << std::endl; | |
| } | |
| } | |
| void cmDependsJavaParserHelper::Print(char const* place, char const* str) const | |
| { | |
| if (this->Verbose) { | |
| std::cout << "[" << place << "=" << str << "]" << std::endl; | |
| } | |
| } | |
| void cmDependsJavaParserHelper::CombineUnions(char** out, char const* in1, | |
| char** in2, char const* sep) | |
| { | |
| size_t len = 1; | |
| if (in1) { | |
| len += strlen(in1); | |
| } | |
| if (*in2) { | |
| len += strlen(*in2); | |
| } | |
| if (sep) { | |
| len += strlen(sep); | |
| } | |
| *out = new char[len]; | |
| *out[0] = 0; | |
| if (in1) { | |
| strcat(*out, in1); | |
| } | |
| if (sep) { | |
| strcat(*out, sep); | |
| } | |
| if (*in2) { | |
| strcat(*out, *in2); | |
| } | |
| if (*in2) { | |
| this->DeallocateParserType(in2); | |
| } | |
| this->UnionsAvailable++; | |
| } | |
| void cmDependsJavaParserHelper::CheckEmpty( | |
| int line, int cnt, cmDependsJavaParserHelper::ParserType* pt) | |
| { | |
| int cc; | |
| int kk = -cnt + 1; | |
| for (cc = 1; cc <= cnt; cc++) { | |
| cmDependsJavaParserHelper::ParserType* cpt = pt + kk; | |
| this->SafePrintMissing(cpt->str, line, cc); | |
| kk++; | |
| } | |
| } | |
| void cmDependsJavaParserHelper::PrepareElement( | |
| cmDependsJavaParserHelper::ParserType* me) | |
| { | |
| // Initialize self | |
| me->str = nullptr; | |
| } | |
| void cmDependsJavaParserHelper::AllocateParserType( | |
| cmDependsJavaParserHelper::ParserType* pt, char const* str, int len) | |
| { | |
| pt->str = nullptr; | |
| if (len == 0) { | |
| len = static_cast<int>(strlen(str)); | |
| } | |
| if (len == 0) { | |
| return; | |
| } | |
| this->UnionsAvailable++; | |
| auto up = cm::make_unique<char[]>(len + 1); | |
| pt->str = up.get(); | |
| strncpy(pt->str, str, len); | |
| pt->str[len] = 0; | |
| this->Allocates.push_back(std::move(up)); | |
| } | |
| void cmDependsJavaParserHelper::StartClass(char const* cls) | |
| { | |
| CurrentClass cl; | |
| cl.Name = cls; | |
| this->ClassStack.push_back(std::move(cl)); | |
| this->CurrentDepth++; | |
| } | |
| void cmDependsJavaParserHelper::EndClass() | |
| { | |
| if (this->ClassStack.empty()) { | |
| std::cerr << "Error when parsing. Current class is null" << std::endl; | |
| abort(); | |
| } | |
| if (this->ClassStack.size() <= 1) { | |
| std::cerr << "Error when parsing. Parent class is null" << std::endl; | |
| abort(); | |
| } | |
| CurrentClass& current = this->ClassStack.back(); | |
| CurrentClass& parent = this->ClassStack[this->ClassStack.size() - 2]; | |
| this->CurrentDepth--; | |
| parent.NestedClasses.push_back(current); | |
| this->ClassStack.pop_back(); | |
| } | |
| void cmDependsJavaParserHelper::PrintClasses() | |
| { | |
| if (this->ClassStack.empty()) { | |
| std::cerr << "Error when parsing. No classes on class stack" << std::endl; | |
| abort(); | |
| } | |
| for (std::string const& f : this->GetFilesProduced()) { | |
| std::cout << " " << f << ".class" << std::endl; | |
| } | |
| } | |
| std::vector<std::string> cmDependsJavaParserHelper::GetFilesProduced() | |
| { | |
| std::vector<std::string> files; | |
| CurrentClass const& toplevel = this->ClassStack.front(); | |
| for (CurrentClass const& nc : toplevel.NestedClasses) { | |
| nc.AddFileNamesForPrinting(&files, nullptr, "$"); | |
| } | |
| return files; | |
| } | |
| int cmDependsJavaParserHelper::ParseString(char const* str, int verb) | |
| { | |
| if (!str) { | |
| return 0; | |
| } | |
| this->Verbose = verb; | |
| this->InputBuffer = str; | |
| this->InputBufferPos = 0; | |
| this->CurrentLine = 0; | |
| yyscan_t yyscanner; | |
| cmDependsJava_yylex_init(&yyscanner); | |
| cmDependsJava_yyset_extra(this, yyscanner); | |
| int res = cmDependsJava_yyparse(yyscanner); | |
| cmDependsJava_yylex_destroy(yyscanner); | |
| if (res != 0) { | |
| std::cout << "JP_Parse returned: " << res << std::endl; | |
| return 0; | |
| } | |
| if (verb) { | |
| if (!this->CurrentPackage.empty()) { | |
| std::cout << "Current package is: " << this->CurrentPackage << std::endl; | |
| } | |
| std::cout << "Imports packages:"; | |
| if (!this->PackagesImport.empty()) { | |
| std::vector<std::string>::iterator it; | |
| for (it = this->PackagesImport.begin(); it != this->PackagesImport.end(); | |
| ++it) { | |
| std::cout << " " << *it; | |
| } | |
| } | |
| std::cout << std::endl; | |
| std::cout << "Depends on:"; | |
| if (!this->ClassesFound.empty()) { | |
| for (std::string const& cf : this->ClassesFound) { | |
| std::cout << " " << cf; | |
| } | |
| } | |
| std::cout << std::endl; | |
| std::cout << "Generated files:" << std::endl; | |
| this->PrintClasses(); | |
| if (this->UnionsAvailable != 0) { | |
| std::cout << "There are still " << this->UnionsAvailable | |
| << " unions available" << std::endl; | |
| } | |
| } | |
| this->CleanupParser(); | |
| return 1; | |
| } | |
| void cmDependsJavaParserHelper::CleanupParser() | |
| { | |
| this->Allocates.clear(); | |
| } | |
| int cmDependsJavaParserHelper::LexInput(char* buf, int maxlen) | |
| { | |
| if (maxlen < 1) { | |
| return 0; | |
| } | |
| if (this->InputBufferPos < this->InputBuffer.size()) { | |
| buf[0] = this->InputBuffer[this->InputBufferPos++]; | |
| if (buf[0] == '\n') { | |
| this->CurrentLine++; | |
| } | |
| return 1; | |
| } | |
| buf[0] = '\n'; | |
| return 0; | |
| } | |
| void cmDependsJavaParserHelper::Error(char const* str) | |
| { | |
| unsigned long pos = static_cast<unsigned long>(this->InputBufferPos); | |
| fprintf(stderr, "JPError: %s (%lu / Line: %d)\n", str, pos, | |
| this->CurrentLine); | |
| std::cerr << "String: [" | |
| << cm::string_view{ this->InputBuffer }.substr( | |
| this->InputBufferPos, 30) | |
| << "]" << std::endl; | |
| } | |
| void cmDependsJavaParserHelper::UpdateCombine(char const* str1, | |
| char const* str2) | |
| { | |
| if (this->CurrentCombine.empty() && str1) { | |
| // We can reuse allocated memory from `this->CurrentCombine` | |
| this->CurrentCombine = cmStrCat(std::move(this->CurrentCombine), str1); | |
| } | |
| this->CurrentCombine = cmStrCat(std::move(this->CurrentCombine), '.', str2); | |
| } | |
| int cmDependsJavaParserHelper::ParseFile(char const* file) | |
| { | |
| if (!cmSystemTools::FileExists(file)) { | |
| return 0; | |
| } | |
| cmsys::ifstream ifs(file); | |
| if (!ifs) { | |
| return 0; | |
| } | |
| std::string fullfile; | |
| std::string line; | |
| while (cmSystemTools::GetLineFromStream(ifs, line)) { | |
| fullfile = cmStrCat(std::move(fullfile), line, '\n'); | |
| } | |
| return this->ParseString(fullfile.c_str(), 0); | |
| } |