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 31namespace panda::proto { 32#if PANDA_TARGET_WINDOWS 33bool 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 64bool 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 95bool 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 105bool 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 133bool 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