/***************************************************************************** * @copyright 2024-2024, . POWER SUPPLY CO., LTD. * @file argparse.c * @brief 命令行参数解析实现 * @author Gary * @date 2024/09/20 *****************************************************************************/ #include #include #include #include #include #include #include "kit_log.h" #include "argparse.h" // clang-format off const char* usage_text = "用法:\n" "company_ems [选项]\n" "选项:\n" " -d, --daemon 以守护进程方式运行\n" " -h, --help 显示帮助信息\n" " stop 停止正在运行的 company_ems\n" " --version 打印版本信息\n" "\n"; // clang-format on /***************************************************************************** * @brief 显示命令行帮助信息 *****************************************************************************/ static void usage() { KITPTF(LOG_ARGPARSE_EN, INFO_EN, "%s", usage_text); } /***************************************************************************** * @brief 输出版本号 * @return *****************************************************************************/ static void version() { printf("1.0.0\n"); } /***************************************************************************** * @brief 加载特定命令行参数 * @param[in] argc:命令行参数个数 * @param[in] argv:命令行参数字符数组 * @param[out] args:命令行解析后装入的结构体 * @return 0 表示成功,其他值表示失败 *****************************************************************************/ static int load_spec_arg(int argc, char* argv[], cli_args_t* args) { if (argc > 1 && strcmp(argv[1], "stop") == 0) { args->stop = true; } return 0; // 这里返回0表示成功 } /***************************************************************************** * @brief 解析重启策略字符串 * @param[in] s:重启策略字符串 * @param[out] out:解析后的重启策略值 * @return 0 表示成功,-1 表示失败 *****************************************************************************/ static int parse_restart_policy(const char* s, size_t* out) { if (strcmp(s, "always") == 0) { *out = RESTART_ALWAYS; } else if (strcmp(s, "never") == 0) { *out = RESTART_NEVER; } else if (strcmp(s, "on-failure") == 0) { *out = RESTART_ONFAILURE; } else { errno = 0; char* end = NULL; uintmax_t n = strtoumax(s, &end, 0); // 检查整个字符串是否为有效数字 if (errno != 0 || *s == '\0' || *end != '\0' || n > RESTART_ALWAYS) { return -1; // 返回-1表示解析失败 } *out = n; } return 0; // 返回0表示成功 } /***************************************************************************** * @brief 初始化命令行参数解析 * @param[in] argc:命令行参数个数 * @param[in] argv:命令行参数字符数组 * @param[out] args:命令行解析后装入的结构体 *****************************************************************************/ void cliArgsInit(int argc, char* argv[], cli_args_t* args) { memset(args, 0, sizeof(*args)); // 初始化参数结构体 // 加载特定参数 if (load_spec_arg(argc, argv, args) < 0) { exit(1); } int c = 0; int option_index = 0; char* opts = "dh"; // 短选项字符串 struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"daemon", no_argument, NULL, 'd'}, {"restart", required_argument, NULL, 'r'}, {"version", no_argument, NULL, 'v'}, {"stop", no_argument, NULL, 's'}, {NULL, 0, NULL, 0}, }; // 解析命令行选项 while ((c = getopt_long(argc, argv, opts, long_options, &option_index)) != -1) { switch (c) { case 'h': usage(); exit(0); case 'd': args->daemonized = true; break; case 'r': if (parse_restart_policy(optarg, &args->restart) != 0) { KITPTF(LOG_ARGPARSE_EN, ERROR_EN, "%s: 选项 '--restart' 无效策略: `%s`\n", argv[0], optarg); exit(1); } break; case 'v': version(); exit(0); case '?': default: usage(); exit(1); } } // 检查重启策略的有效性 if (!args->daemonized && args->restart != RESTART_NEVER) { KITPTF(LOG_ARGPARSE_EN, ERROR_EN, "%s: 选项 '--restart' 在没有 '--daemon' 的情况下无效\n", argv[0]); args->restart = RESTART_NEVER; } }