2024-05-28 15:46:58 +08:00
|
|
|
#include "src/pub.h"
|
2024-05-28 10:09:34 +08:00
|
|
|
#include <CLI11.hpp>
|
2024-05-28 15:46:58 +08:00
|
|
|
#include <filesystem>
|
2024-06-29 10:18:42 +08:00
|
|
|
#include <fmt/format.h>
|
2024-05-28 15:46:58 +08:00
|
|
|
#include <fstream>
|
2024-05-28 10:09:34 +08:00
|
|
|
#include <iostream>
|
2024-05-28 15:46:58 +08:00
|
|
|
#include <list>
|
2024-05-28 10:09:34 +08:00
|
|
|
#include <string>
|
|
|
|
|
|
|
|
#define CODECREATE_VERSION "1.0.0"
|
|
|
|
|
2024-05-28 15:46:58 +08:00
|
|
|
enum ProjectType { TYPE_CONSOLE = 0, TYPE_QT_CONSOLE, TYPE_QT_WIDGET };
|
|
|
|
|
2024-05-28 10:09:34 +08:00
|
|
|
struct MParam {
|
2024-05-28 15:46:58 +08:00
|
|
|
std::string point_code{};
|
|
|
|
std::string qt_path{};
|
|
|
|
std::string exe_dir{};
|
2024-05-28 10:09:34 +08:00
|
|
|
std::string des_path{};
|
2024-05-28 15:46:58 +08:00
|
|
|
std::string des_dir{};
|
|
|
|
std::string name{};
|
|
|
|
std::string shortkey{};
|
|
|
|
ProjectType type{TYPE_CONSOLE};
|
2024-05-28 10:09:34 +08:00
|
|
|
};
|
|
|
|
|
2024-05-28 15:46:58 +08:00
|
|
|
MParam gParam;
|
2024-05-28 10:09:34 +08:00
|
|
|
|
2024-05-28 15:46:58 +08:00
|
|
|
namespace fs = std::filesystem;
|
2024-05-28 10:09:34 +08:00
|
|
|
bool parse_cmd(int argc, char** argv, MParam& param)
|
|
|
|
{
|
|
|
|
std::string intro("");
|
|
|
|
intro.append(CODECREATE_VERSION);
|
|
|
|
CLI::App app(intro);
|
|
|
|
|
2024-05-28 15:46:58 +08:00
|
|
|
std::string type;
|
|
|
|
|
|
|
|
app.add_option("-p,--path", param.des_path, "project position");
|
|
|
|
app.add_option("-n,--name", param.name, "project name");
|
|
|
|
app.add_option("-t,--type", type, "0-console,1-qtconsole,2-qtdialog");
|
|
|
|
app.add_option("-q,--qt", param.qt_path, "qt path, bin dir's parent dir.");
|
|
|
|
app.add_option("-k,--key", param.shortkey, "if not empty, set f5 and alt+g.");
|
2024-05-28 10:09:34 +08:00
|
|
|
|
|
|
|
try {
|
|
|
|
CLI11_PARSE(app, argc, argv);
|
2024-05-28 15:46:58 +08:00
|
|
|
param.type = static_cast<ProjectType>(std::stoi(type));
|
|
|
|
param.qt_path = CUtil::replace(param.qt_path, "\\", "/");
|
2024-05-28 10:09:34 +08:00
|
|
|
return true;
|
|
|
|
} catch (const CLI::ParseError& e) {
|
|
|
|
std::cerr << "Error parsing command line: " << e.what() << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-28 15:46:58 +08:00
|
|
|
bool copy_dir(const std::string& source_dir, const std::string& des_dir, bool add_dir = true)
|
|
|
|
{
|
|
|
|
if (!fs::exists(source_dir) || !fs::exists(des_dir)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto replaceAll = [](const std::string& str, const std::string& from, const std::string& to) {
|
|
|
|
std::string tp(str);
|
|
|
|
if (from.empty()) {
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
std::size_t start_pos = 0;
|
|
|
|
while ((start_pos = tp.find(from, start_pos)) != std::string::npos) {
|
|
|
|
tp.replace(start_pos, from.length(), to);
|
|
|
|
start_pos += to.length();
|
|
|
|
}
|
|
|
|
return tp;
|
|
|
|
};
|
|
|
|
|
|
|
|
fs::path des_parent_dir;
|
|
|
|
if (add_dir) {
|
|
|
|
des_parent_dir = fs::path(des_dir).append(fs::path(source_dir).filename().string());
|
|
|
|
if (!fs::exists(des_parent_dir)) {
|
|
|
|
fs::create_directories(des_parent_dir);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
des_parent_dir = fs::path(des_dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::list<fs::path> paths{};
|
|
|
|
for (const auto& entry : fs::directory_iterator(source_dir)) {
|
|
|
|
paths.push_back(entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!paths.empty()) {
|
|
|
|
fs::path path = paths.front();
|
|
|
|
paths.pop_front();
|
|
|
|
|
|
|
|
fs::path destination(replaceAll(path.string(), source_dir, des_parent_dir.string()));
|
|
|
|
if (fs::is_directory(path)) {
|
|
|
|
if (!fs::exists(destination)) {
|
|
|
|
fs::create_directories(destination);
|
|
|
|
}
|
|
|
|
for (const auto& entry : fs::directory_iterator(path)) {
|
|
|
|
paths.push_back(entry);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
fs::copy_file(path, destination, fs::copy_options::overwrite_existing);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool create_base()
|
|
|
|
{
|
|
|
|
if (gParam.name.empty()) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("project name is empty.") << std::endl;
|
2024-05-28 15:46:58 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!fs::exists(gParam.des_path)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("{} is not exit.", gParam.des_path) << std::endl;
|
2024-05-28 15:46:58 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fs::path des_dir(gParam.des_path);
|
|
|
|
gParam.des_dir = des_dir.append(gParam.name).string();
|
|
|
|
|
|
|
|
if (fs::exists(des_dir)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("{} is already exist.", des_dir.string()) << "\n";
|
2024-05-28 15:46:58 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!fs::create_directory(des_dir)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("{} create failed.", des_dir.string()) << std::endl;
|
2024-05-28 15:46:58 +08:00
|
|
|
return false;
|
|
|
|
} else {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("{} create success.", des_dir.string()) << std::endl;
|
2024-05-28 15:46:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fs::path point_code_dir(des_dir);
|
|
|
|
gParam.point_code = point_code_dir.append(".vscode").string();
|
|
|
|
|
|
|
|
if (!fs::exists(point_code_dir)) {
|
|
|
|
if (fs::create_directory(point_code_dir)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("{} create success.", point_code_dir.string()) << std::endl;
|
2024-05-28 15:46:58 +08:00
|
|
|
} else {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("{} create failed.", point_code_dir.string()) << std::endl;
|
2024-05-28 15:46:58 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fs::path settings_file(point_code_dir);
|
|
|
|
fs::path clang_file(des_dir);
|
|
|
|
settings_file.append("settings.json");
|
|
|
|
clang_file.append(".clang-format");
|
|
|
|
|
|
|
|
fs::path source_settings(gParam.exe_dir);
|
|
|
|
fs::path clang_format(gParam.exe_dir);
|
|
|
|
source_settings.append(".vscode").append("settings.json");
|
|
|
|
clang_format.append("template").append(".clang-format");
|
|
|
|
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("source settings is: {}", source_settings.string()) << std::endl;
|
|
|
|
std::cout << fmt::format("clang_format is: {}", clang_format.string()) << std::endl;
|
2024-05-28 15:46:58 +08:00
|
|
|
|
|
|
|
if (fs::copy_file(source_settings, settings_file)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("copy to {} success.", settings_file.string()) << std::endl;
|
2024-05-28 15:46:58 +08:00
|
|
|
} else {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("copy to {} success.", settings_file.string()) << std::endl;
|
2024-05-28 15:46:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fs::copy_file(clang_format, clang_file)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("copy to {} success.", clang_format.string()) << std::endl;
|
2024-05-28 15:46:58 +08:00
|
|
|
} else {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("copy to {} success.", clang_format.string()) << std::endl;
|
2024-05-28 15:46:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool copy_console()
|
|
|
|
{
|
|
|
|
fs::path console_path(gParam.exe_dir);
|
|
|
|
console_path.append("template").append("console");
|
|
|
|
copy_dir(console_path.string(), gParam.des_dir, false);
|
|
|
|
|
|
|
|
fs::path cmakelist(gParam.des_dir);
|
|
|
|
cmakelist.append("CMakeLists.txt");
|
|
|
|
|
|
|
|
std::string str_content;
|
|
|
|
if (!CUtil::read_txt(cmakelist.string(), str_content)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("can't open file {}", cmakelist.string());
|
2024-05-28 15:46:58 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string rep("replace");
|
|
|
|
std::string ncontent = CUtil::replace(str_content, rep, gParam.name);
|
|
|
|
|
|
|
|
if (!CUtil::save_txt(cmakelist.string(), ncontent)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("can't write file {}", cmakelist.string());
|
2024-05-28 15:46:58 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool copy_qt_widget()
|
|
|
|
{
|
|
|
|
fs::path widget_path(gParam.exe_dir);
|
|
|
|
widget_path.append("template").append("qt-widget");
|
|
|
|
copy_dir(widget_path.string(), gParam.des_dir, false);
|
|
|
|
|
|
|
|
fs::path cmakelist(gParam.des_dir);
|
|
|
|
cmakelist.append("CMakeLists.txt");
|
|
|
|
|
|
|
|
std::string str_content;
|
|
|
|
if (!CUtil::read_txt(cmakelist.string(), str_content)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("can't open file {}", cmakelist.string());
|
2024-05-28 15:46:58 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string rep("QT_PATH");
|
|
|
|
std::string rep2("untitled3");
|
|
|
|
std::string ncontent = CUtil::replace(str_content, rep, gParam.qt_path);
|
|
|
|
ncontent = CUtil::replace(ncontent, rep2, gParam.name);
|
|
|
|
|
|
|
|
if (!CUtil::save_txt(cmakelist.string(), ncontent)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("can't write file {}", cmakelist.string());
|
2024-05-28 15:46:58 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fs::path settings(gParam.point_code);
|
|
|
|
settings.append("settings.json");
|
|
|
|
|
|
|
|
std::string settings_content;
|
|
|
|
if (!CUtil::read_txt(settings.string(), settings_content)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("can't open file {}", settings.string());
|
2024-05-28 15:46:58 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string from("replace");
|
|
|
|
std::string to(gParam.qt_path + "/bin");
|
|
|
|
settings_content = CUtil::replace(settings_content, from, to);
|
|
|
|
|
|
|
|
if (!CUtil::save_txt(settings.string(), settings_content)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("can't write file {}", settings.string());
|
2024-05-28 15:46:58 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool copy_qt_console()
|
|
|
|
{
|
|
|
|
fs::path qt_console_path(gParam.exe_dir);
|
|
|
|
qt_console_path.append("template").append("qt-console");
|
|
|
|
|
|
|
|
fs::path cmakelist(qt_console_path);
|
|
|
|
fs::path main_file(qt_console_path);
|
|
|
|
cmakelist.append("CMakeLists.txt");
|
|
|
|
main_file.append("main.cpp");
|
|
|
|
|
|
|
|
fs::path save_main(gParam.des_dir);
|
|
|
|
save_main.append("main.cpp");
|
|
|
|
|
|
|
|
if (!fs::copy_file(main_file, save_main)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("can't copy main file {}", main_file.string());
|
2024-05-28 15:46:58 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string str_content;
|
|
|
|
if (!CUtil::read_txt(cmakelist.string(), str_content)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("can't open file {}", cmakelist.string());
|
2024-05-28 15:46:58 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string rep("QT_PATH");
|
|
|
|
std::string rep2("PROJECT_NAME");
|
|
|
|
std::string ncontent = CUtil::replace(str_content, rep, gParam.qt_path);
|
|
|
|
ncontent = CUtil::replace(ncontent, rep2, gParam.name);
|
|
|
|
|
|
|
|
fs::path save_cmake(gParam.des_dir);
|
|
|
|
save_cmake.append("CMakeLists.txt");
|
|
|
|
|
|
|
|
if (!CUtil::save_txt(save_cmake.string(), ncontent)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("can't write file {}", save_cmake.string());
|
2024-05-28 15:46:58 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fs::path settings(gParam.point_code);
|
|
|
|
settings.append("settings.json");
|
|
|
|
|
|
|
|
std::string settings_content;
|
|
|
|
if (!CUtil::read_txt(settings.string(), settings_content)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("can't open file {}", settings.string());
|
2024-05-28 15:46:58 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string from("replace");
|
|
|
|
std::string to(gParam.qt_path + "/bin");
|
|
|
|
settings_content = CUtil::replace(settings_content, from, to);
|
|
|
|
|
|
|
|
if (!CUtil::save_txt(settings.string(), settings_content)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("can't write file {}", settings.string());
|
2024-05-28 15:46:58 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool set_key()
|
|
|
|
{
|
|
|
|
std::string shortkey_file = CUtil::get_keybindings_file();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool handle_gdb_qtprinter()
|
|
|
|
{
|
|
|
|
#if _MSC_VER
|
|
|
|
fs::path template_dir(gParam.exe_dir);
|
|
|
|
template_dir.append("template");
|
|
|
|
|
|
|
|
fs::path qt5_file(template_dir);
|
|
|
|
fs::path qt6_file(template_dir);
|
|
|
|
qt5_file.append("qt5.natvis");
|
|
|
|
qt6_file.append("qt6.natvis");
|
|
|
|
|
|
|
|
fs::path des_qt5_file(gParam.point_code);
|
|
|
|
fs::path des_qt6_file(gParam.point_code);
|
|
|
|
des_qt5_file.append("qt5.natvis");
|
|
|
|
des_qt6_file.append("qt6.natvis");
|
|
|
|
|
|
|
|
if (fs::copy_file(qt5_file, des_qt5_file)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("copy to {} success.", des_qt5_file.string()) << std::endl;
|
2024-05-28 15:46:58 +08:00
|
|
|
} else {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("copy to {} success.", des_qt5_file.string()) << std::endl;
|
2024-05-28 15:46:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fs::copy_file(qt6_file, des_qt6_file)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("copy to {} success.", des_qt6_file.string()) << std::endl;
|
2024-05-28 15:46:58 +08:00
|
|
|
} else {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("copy to {} success.", des_qt6_file.string()) << std::endl;
|
2024-05-28 15:46:58 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
std::string home = CUtil::get_home();
|
|
|
|
if (home.empty()) {
|
|
|
|
std::cout << "can't get home dir.\n";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fs::path gdb_des(home);
|
|
|
|
gdb_des.append(".gdbinit");
|
|
|
|
|
|
|
|
fs::path gdb_source(gParam.exe_dir);
|
|
|
|
gdb_source.append("template").append("qt-printer").append(".gdbinit");
|
|
|
|
|
|
|
|
if (!fs::exists(gdb_des)) {
|
|
|
|
if (fs::copy_file(gdb_source, gdb_des)) {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("copy to {} success.", gdb_des.string()) << std::endl;
|
2024-05-28 15:46:58 +08:00
|
|
|
} else {
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("copy to {} success.", gdb_des.string()) << std::endl;
|
2024-05-28 15:46:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fs::path gdb_path(home);
|
|
|
|
fs::path gdb_source_path(gParam.exe_dir);
|
|
|
|
gdb_path.append(".gdb");
|
|
|
|
gdb_source_path.append("template").append("qt-printer").append("QtPrinters");
|
|
|
|
|
|
|
|
if (fs::exists(gdb_path)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
fs::create_directory(gdb_path);
|
|
|
|
|
|
|
|
copy_dir(gdb_source_path.string(), gdb_path.string(), true);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-05-28 10:09:34 +08:00
|
|
|
int main(int argc, char** argv)
|
|
|
|
{
|
2024-05-28 15:46:58 +08:00
|
|
|
std::cout << "\n";
|
2024-05-28 10:09:34 +08:00
|
|
|
|
2024-05-28 15:46:58 +08:00
|
|
|
if (!parse_cmd(argc, argv, gParam)) {
|
2024-05-28 10:09:34 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2024-05-28 15:46:58 +08:00
|
|
|
#if _DEBUG
|
|
|
|
std::cout << "Debug Mode." << std::endl;
|
2024-05-28 16:05:05 +08:00
|
|
|
fs::path exe_path(CUtil::get_exe_path());
|
|
|
|
gParam.exe_dir = exe_path.parent_path().parent_path().string();
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("current_path is: {}", gParam.exe_dir) << "\n";
|
2024-05-28 15:46:58 +08:00
|
|
|
#else
|
|
|
|
std::cout << "Release Mode." << std::endl;
|
2024-05-28 16:05:05 +08:00
|
|
|
fs::path exe_path(CUtil::get_exe_path());
|
|
|
|
gParam.exe_dir = exe_path.parent_path().string();
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("current_path is: {}", gParam.exe_dir) << "\n";
|
2024-05-28 15:46:58 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
// if (!gParam.shortkey.empty()) {
|
|
|
|
// set_key();
|
|
|
|
// return 0;
|
|
|
|
// }
|
|
|
|
|
|
|
|
switch (gParam.type) {
|
|
|
|
case TYPE_CONSOLE: {
|
|
|
|
if (!create_base()) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
copy_console();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TYPE_QT_CONSOLE: {
|
|
|
|
if (gParam.qt_path.empty()) {
|
|
|
|
std::cout << "qt path is empty.\n";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!create_base()) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
copy_qt_console();
|
|
|
|
handle_gdb_qtprinter();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TYPE_QT_WIDGET: {
|
|
|
|
if (gParam.qt_path.empty()) {
|
|
|
|
std::cout << "qt path is empty.\n";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!create_base()) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
copy_qt_widget();
|
|
|
|
handle_gdb_qtprinter();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
2024-06-29 10:18:42 +08:00
|
|
|
std::cout << fmt::format("{} is not support.", static_cast<int>(gParam.type)) << "\n";
|
2024-05-28 15:46:58 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-05-28 10:09:34 +08:00
|
|
|
return 0;
|
|
|
|
}
|