163 lines
5.0 KiB
C
163 lines
5.0 KiB
C
|
/*****************************************************************************
|
|||
|
* @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;
|
|||
|
}
|
|||
|
}
|