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 {
32 #if PANDA_TARGET_WINDOWS
EnumerateFilesWindows(const std::string & protoBinPath,const std::string & protoBinSuffix,std::vector<std::string> & directoryFiles)33 bool MergeProgram::EnumerateFilesWindows(const std::string &protoBinPath, const std::string &protoBinSuffix,
34 std::vector<std::string> &directoryFiles)
35 {
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 return true;
61 }
62
63 #elif PANDA_TARGET_UNIX
64 bool MergeProgram::EnumerateFilesUnix(const std::string &protoBinPath, const std::string &protoBinSuffix,
65 std::vector<std::string> &directoryFiles)
66 {
67 DIR *protoBin = opendir(protoBinPath.c_str());
68 if (protoBin == nullptr) {
69 return false;
70 }
71 dirent *dir = nullptr;
72 std::string pathPrefix = protoBinPath + "/";
73 while ((dir = readdir(protoBin)) != nullptr) {
74 if ((!strncmp(dir->d_name, ".", 1)) || (!strncmp(dir->d_name, "..", 2))) {
75 continue;
76 }
77 if (dir->d_type == DT_DIR) {
78 std::string subDirName = pathPrefix + dir->d_name;
79 if (!GetProtoFiles(subDirName, protoBinSuffix, directoryFiles)) {
80 closedir(protoBin);
81 return false;
82 }
83 } else {
84 std::string fileName = pathPrefix + dir->d_name;
85 if (fileName.substr(fileName.find_last_of(".") + 1).compare(protoBinSuffix) == 0) {
86 directoryFiles.emplace_back(fileName);
87 }
88 }
89 }
90 closedir(protoBin);
91 return true;
92 }
93 #endif
94
GetProtoFiles(const std::string & protoBinPath,const std::string & protoBinSuffix,std::vector<std::string> & directoryFiles)95 bool MergeProgram::GetProtoFiles(const std::string &protoBinPath, const std::string &protoBinSuffix,
96 std::vector<std::string> &directoryFiles)
97 {
98 #if PANDA_TARGET_WINDOWS
99 return EnumerateFilesWindows(protoBinPath, protoBinSuffix, directoryFiles);
100 #elif PANDA_TARGET_UNIX
101 return EnumerateFilesUnix(protoBinPath, protoBinSuffix, directoryFiles);
102 #endif
103 }
104
AppendProtoFiles(const std::string & filePath,const std::string & protoBinSuffix,std::vector<std::string> & protoFiles)105 bool MergeProgram::AppendProtoFiles(const std::string &filePath, const std::string &protoBinSuffix,
106 std::vector<std::string> &protoFiles)
107 {
108 auto inputAbs = panda::os::file::File::GetAbsolutePath(filePath);
109 if (!inputAbs) {
110 std::cerr << "Failed to open: " << filePath << std::endl;
111 return false;
112 }
113
114 auto fPath = inputAbs.Value();
115 if (panda::os::file::File::IsRegularFile(fPath)) {
116 if (filePath.substr(filePath.find_last_of(".") + 1).compare(protoBinSuffix) == 0) {
117 protoFiles.emplace_back(fPath);
118 }
119 } else if (panda::os::file::File::IsDirectory(fPath)) {
120 std::vector<std::string> directoryFiles;
121 if (!GetProtoFiles(fPath, protoBinSuffix, directoryFiles)) {
122 return false;
123 }
124 protoFiles.insert(protoFiles.end(), directoryFiles.begin(), directoryFiles.end());
125 } else {
126 std::cerr << "The input path: " << fPath << " must be either a regular file or directory." << std::endl;
127 return false;
128 }
129
130 return true;
131 }
132
CollectProtoFiles(std::string & input,const std::string & protoBinSuffix,std::vector<std::string> & protoFiles)133 bool MergeProgram::CollectProtoFiles(std::string &input, const std::string &protoBinSuffix,
134 std::vector<std::string> &protoFiles)
135 {
136 constexpr const char DOGGY = '@';
137 std::vector<std::string> inputs;
138 bool isList = false;
139
140 if (input[0] == DOGGY) {
141 input.erase(input.begin() + 0);
142 isList = true;
143 }
144
145 auto inputAbs = panda::os::file::File::GetAbsolutePath(input);
146 if (!inputAbs) {
147 std::cerr << "Failed to open: " << input << std::endl;
148 return false;
149 }
150 if (isList) {
151 std::ifstream in(panda::os::file::File::GetExtendedFilePath(inputAbs.Value()));
152 std::string line;
153 constexpr const char CARRIAGE = '\r';
154 while (getline(in, line)) {
155 // erase front spaces
156 line.erase(line.begin(),
157 std::find_if(line.begin(), line.end(), [](unsigned char ch) { return std::isspace(ch) == 0; }));
158 // erase carrige return symbol (Windows workaround)
159 line.erase(std::find_if(line.rbegin(), line.rend(), [](unsigned char ch) { return ch != CARRIAGE; }).base(),
160 line.end());
161 if (!line.empty()) {
162 inputs.push_back(line);
163 }
164 }
165 in.close();
166 } else {
167 inputs.push_back(inputAbs.Value());
168 }
169
170 protoFiles.reserve(inputs.size());
171 for (auto &filePath : inputs) {
172 if (!AppendProtoFiles(filePath, protoBinSuffix, protoFiles)) {
173 return false;
174 }
175 }
176
177 return true;
178 }
179 } // namespace panda::proto
180