forked from gary/ems
2
0
Fork 0
sun_ems/ems_c/argparse.c

163 lines
5.0 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*****************************************************************************
* @copyright 2024-2024, . POWER SUPPLY CO., LTD.
* @file argparse.c
* @brief 命令行参数解析实现
* @author Gary
* @date 2024/09/20
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <errno.h>
#include <string.h>
#include <inttypes.h>
#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;
}
}