1 /**
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "assembler/assembly-function.h"
17 #include "libpandafile/literal_data_accessor.h"
18 #include "os/file.h"
19 #include "options.h"
20
21 #include "mergeProgram.h"
22
23 #if defined(PANDA_TARGET_WINDOWS)
24 #include <io.h>
25 #else
26 #include <dirent.h>
27 #endif
28
29 #include <fstream>
30
31 namespace panda::proto {
GetProtoFiles(const std::string & protoBinPath,const std::string & protoBinSuffix,std::vector<std::string> & directoryFiles)32 bool MergeProgram::GetProtoFiles(const std::string &protoBinPath, const std::string &protoBinSuffix,
33 std::vector<std::string> &directoryFiles)
34 {
35 #if PANDA_TARGET_WINDOWS
36 int handle = 0;
37 struct _finddata_t fileInfo;
38 std::string path;
39 if ((handle = _findfirst(path.assign(protoBinPath).append("\\*").c_str(), &fileInfo)) == -1) {
40 return false;
41 }
42 do {
43 if (fileInfo.attrib & _A_SUBDIR) {
44 if((!strncmp(fileInfo.name, ".", 1)) || (!strncmp(fileInfo.name, "..", 2))) {
45 continue;
46 }
47 if (!GetProtoFiles(path.assign(protoBinPath).append("\\").append(fileInfo.name), protoBinSuffix,
48 directoryFiles)) {
49 _findclose(handle);
50 return false;
51 }
52 } else {
53 std::string fileName(fileInfo.name);
54 if (fileName.substr(fileName.find_last_of(".") + 1).compare(protoBinSuffix) == 0) {
55 directoryFiles.emplace_back(path.assign(protoBinPath).append("\\").append(fileName));
56 }
57 }
58 } while (_findnext(handle, &fileInfo) == 0);
59 _findclose(handle);
60 #elif PANDA_TARGET_UNIX
61 DIR *protoBin = opendir(protoBinPath.c_str());
62 if (protoBin == nullptr) {
63 return false;
64 }
65 dirent *dir = nullptr;
66 std::string pathPrefix = protoBinPath + "/";
67 while ((dir = readdir(protoBin)) != nullptr) {
68 if((!strncmp(dir->d_name, ".", 1)) || (!strncmp(dir->d_name, "..", 2))) {
69 continue;
70 }
71 if (dir->d_type == DT_DIR) {
72 std::string subDirName = pathPrefix + dir->d_name;
73 if (!GetProtoFiles(subDirName, protoBinSuffix, directoryFiles)) {
74 closedir(protoBin);
75 return false;
76 }
77 } else {
78 std::string fileName = pathPrefix + dir->d_name;
79 if (fileName.substr(fileName.find_last_of(".") + 1).compare(protoBinSuffix) == 0) {
80 directoryFiles.emplace_back(fileName);
81 }
82 }
83 }
84 closedir(protoBin);
85 #endif
86 return true;
87 }
88
AppendProtoFiles(const std::string & filePath,const std::string & protoBinSuffix,std::vector<std::string> & protoFiles)89 bool MergeProgram::AppendProtoFiles(const std::string &filePath, const std::string &protoBinSuffix,
90 std::vector<std::string> &protoFiles)
91 {
92 auto inputAbs = panda::os::file::File::GetAbsolutePath(filePath);
93 if (!inputAbs) {
94 std::cerr << "Failed to open: " << filePath << std::endl;
95 return false;
96 }
97
98 auto fPath = inputAbs.Value();
99 if (panda::os::file::File::IsRegularFile(fPath)) {
100 if (filePath.substr(filePath.find_last_of(".") + 1).compare(protoBinSuffix) == 0) {
101 protoFiles.emplace_back(fPath);
102 }
103 } else if (panda::os::file::File::IsDirectory(fPath)) {
104 std::vector<std::string> directoryFiles;
105 if (!GetProtoFiles(fPath, protoBinSuffix, directoryFiles)) {
106 return false;
107 }
108 protoFiles.insert(protoFiles.end(), directoryFiles.begin(), directoryFiles.end());
109 } else {
110 std::cerr << "The input path: " << fPath << " must be either a regular file or directory." << std::endl;
111 return false;
112 }
113
114 return true;
115 }
116
CollectProtoFiles(std::string & input,const std::string & protoBinSuffix,std::vector<std::string> & protoFiles)117 bool MergeProgram::CollectProtoFiles(std::string &input, const std::string &protoBinSuffix,
118 std::vector<std::string> &protoFiles)
119 {
120 constexpr const char DOGGY = '@';
121 std::vector<std::string> inputs;
122 bool isList = false;
123
124 if (input[0] == DOGGY) {
125 input.erase(input.begin() + 0);
126 isList = true;
127 }
128
129 auto inputAbs = panda::os::file::File::GetAbsolutePath(input);
130 if (!inputAbs) {
131 std::cerr << "Failed to open: " << input << std::endl;
132 return false;
133 }
134 if (isList) {
135 std::ifstream in(panda::os::file::File::GetExtendedFilePath(inputAbs.Value()));
136 std::string line;
137 constexpr const char CARRIAGE = '\r';
138 while (getline(in, line)) {
139 // erase front spaces
140 line.erase(line.begin(),
141 std::find_if(line.begin(), line.end(), [](unsigned char ch) { return std::isspace(ch) == 0; }));
142 // erase carrige return symbol (Windows workaround)
143 line.erase(std::find_if(line.rbegin(), line.rend(), [](unsigned char ch) { return ch != CARRIAGE; }).base(),
144 line.end());
145 if (!line.empty()) {
146 inputs.push_back(line);
147 }
148 }
149 in.close();
150 } else {
151 inputs.push_back(inputAbs.Value());
152 }
153
154 protoFiles.reserve(inputs.size());
155 for (auto &filePath : inputs) {
156 if (!AppendProtoFiles(filePath, protoBinSuffix, protoFiles)) {
157 return false;
158 }
159 }
160
161 return true;
162 }
163 } // namespace panda::proto
164