Refactor neuron command line argument parser into separate module

This commit is contained in:
eeff
2022-04-08 10:23:06 +08:00
parent 1fbd0ccb44
commit 2d7ecfc764
4 changed files with 189 additions and 89 deletions
+1
View File
@@ -94,6 +94,7 @@ set(PERSIST_SOURCES
src/persist/json/persist_json_subs.c)
set(NEURON_SOURCES
src/main.c
src/argparse.c
src/config.c
src/core/message.c
src/core/databuf.c
+133
View File
@@ -0,0 +1,133 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "argparse.h"
#define OPTIONAL_ARGUMENT_IS_PRESENT \
((optarg == NULL && optind < argc && argv[optind][0] != '-') \
? (bool) (optarg = argv[optind++]) \
: (optarg != NULL))
#define STRDUP(var, str) \
do { \
(var) = strdup(str); \
if (NULL == (var)) { \
fprintf( \
stderr, \
"Neuron argument parser fail strdup string: %s, reason: %s\n", \
(str), strerror(errno)); \
goto quit; \
} \
} while (0)
// clang-format off
const char *usage_text =
"USAGE:\n"
" neuron [OPTIONS]\n\n"
"OPTIONS:\n"
" -c, --config <FILE> neuron configuration file\n"
" without this option, default from ./config/neuron.yaml\n"
" -d, --daemon run as daemon process\n"
" -h, --help show this help message\n"
" --log [FILE] log to the given file, or stdout if no FILE argument\n"
" without this option, default log to ./logs/neuron.log\n"
"\n";
// clang-format on
static inline void usage()
{
fprintf(stderr, "%s", usage_text);
}
void neu_cli_args_init(neu_cli_args_t *args, int argc, char *argv[])
{
char * opts = "c:dh";
struct option long_options[] = {
{ "help", no_argument, NULL, 1 },
{ "config", required_argument, NULL, 'c' },
{ "daemon", no_argument, NULL, 'd' },
{ "log", optional_argument, NULL, 'l' },
{ NULL, 0, NULL, 0 },
};
memset(args, 0, sizeof(*args));
int c = 0;
while ((c = getopt_long(argc, argv, opts, long_options, NULL)) != -1) {
switch (c) {
case 'h':
usage();
exit(0);
case 'd':
args->daemonized = true;
break;
case ':':
fprintf(stderr, "%s: option '-%c' requires an argument\n", argv[0],
optopt);
usage();
goto quit;
case 'c':
STRDUP(args->conf_file, optarg);
break;
case 'l':
if (OPTIONAL_ARGUMENT_IS_PRESENT) {
// log to file
STRDUP(args->log_file, optarg);
} else {
// log to stdout
STRDUP(args->log_file, NEU_LOG_STDOUT_FNAME);
}
break;
case '?':
default:
fprintf(stderr, "%s: option '-%c' is invalid: ignored\n", argv[0],
optopt);
usage();
goto quit;
}
}
if (NULL == args->conf_file) {
STRDUP(args->conf_file, "./config/neuron.yaml");
}
if (NULL == args->log_file) {
STRDUP(args->log_file, "./logs/neuron.log");
}
return;
quit:
neu_cli_args_fini(args);
exit(1);
}
void neu_cli_args_fini(neu_cli_args_t *args)
{
free(args->conf_file);
args->conf_file = NULL;
free(args->log_file);
args->log_file = NULL;
}
+46
View File
@@ -0,0 +1,46 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#define NEU_LOG_STDOUT_FNAME "/dev/stdout"
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
/** Neuron command line arguments.
*/
typedef struct {
bool daemonized; // flag indicating whether to run as daemon process
char *conf_file; // configuration file path
char *log_file; // log file path
} neu_cli_args_t;
/** Parse command line arguments.
*/
void neu_cli_args_init(neu_cli_args_t *args, int argc, char *argv[]);
/** Clean up the command line arguments.
*/
void neu_cli_args_fini(neu_cli_args_t *args);
#ifdef __cplusplus
}
#endif
+9 -89
View File
@@ -28,6 +28,7 @@
#include <nng/protocol/pair1/pair.h>
#include <nng/supplemental/util/platform.h>
#include "argparse.h"
#include "config.h"
#include "core/message.h"
#include "core/neu_manager.h"
@@ -36,33 +37,12 @@
#include "neu_panic.h"
#include "restful/rest.h"
#define STDOUT_FILE "/dev/stdout"
#define OPTIONAL_ARGUMENT_IS_PRESENT \
((optarg == NULL && optind < argc && argv[optind][0] != '-') \
? (bool) (optarg = argv[optind++]) \
: (optarg != NULL))
static neu_manager_t *manager = NULL;
static nng_socket main_sock = { 0 };
static nng_mtx *log_mtx;
FILE * g_logfile;
// clang-format off
const char *usage_text =
"USAGE:\n"
" neuron [OPTIONS]\n\n"
"OPTIONS:\n"
" -c, --config <FILE> neuron configuration file\n"
" without this option, default from ./config/neuron.yaml\n"
" -d, --daemon run as daemon process\n"
" -h, --help show this help message\n"
" --log [FILE] log to the given file, or stdout if no FILE argument\n"
" without this option, default log to ./logs/neuron.log\n"
"\n";
// clang-format on
static void log_lock(bool lock, void *udata)
{
nng_mtx *mutex = (nng_mtx *) (udata);
@@ -78,7 +58,7 @@ static void init(const char *log_file)
nng_mtx_alloc(&log_mtx);
log_set_lock(log_lock, log_mtx);
log_set_level(NEU_LOG_DEBUG);
if (0 == strcmp(log_file, STDOUT_FILE)) {
if (0 == strcmp(log_file, NEU_LOG_STDOUT_FNAME)) {
g_logfile = stdout;
} else {
g_logfile = fopen(log_file, "a");
@@ -99,11 +79,6 @@ static void uninit()
nng_mtx_free(log_mtx);
}
static void usage()
{
fprintf(stderr, "%s", usage_text);
}
static int read_neuron_config(const char *config)
{
return neu_config_init(config);
@@ -165,68 +140,14 @@ static void unbind_main_adapter(nng_pipe p, nng_pipe_ev ev, void *arg)
int main(int argc, char *argv[])
{
int rv = 0;
neu_cli_args_t args = { 0 };
int rv = 0;
bool is_daemon = false;
char *config_file = NULL;
char *log_file = NULL;
neu_cli_args_init(&args, argc, argv);
char * opts = "c:dh";
struct option long_options[] = {
{ "help", no_argument, NULL, 1 },
{ "config", required_argument, NULL, 'c' },
{ "daemon", no_argument, NULL, 'd' },
{ "log", optional_argument, NULL, 'l' },
{ NULL, 0, NULL, 0 },
};
init(args.log_file);
int c;
while ((c = getopt_long(argc, argv, opts, long_options, NULL)) != -1) {
switch (c) {
case 'h':
usage();
exit(0);
case 'd':
is_daemon = true;
break;
case ':':
fprintf(stderr, "%s: option '-%c' requires an argument\n", argv[0],
optopt);
usage();
exit(0);
case 'c':
config_file = strdup(optarg);
break;
case 'l':
if (OPTIONAL_ARGUMENT_IS_PRESENT) {
// log to file
log_file = strdup(optarg);
} else {
// log to stdout
log_file = strdup(STDOUT_FILE);
}
break;
case '?':
default:
fprintf(stderr, "%s: option '-%c' is invalid: ignored\n", argv[0],
optopt);
usage();
exit(0);
}
}
if (config_file == NULL) {
config_file = strdup("./config/neuron.yaml");
}
if (log_file == NULL) {
log_file = strdup("./logs/neuron.log");
}
init(log_file);
rv = read_neuron_config(config_file);
rv = read_neuron_config(args.conf_file);
if (rv < 0) {
log_error("Failed to get neuron configuration.");
goto main_end;
@@ -236,7 +157,7 @@ int main(int argc, char *argv[])
signal(SIGTERM, sig_handler);
signal(SIGABRT, sig_handler);
log_info("running neuron main process, daemon: %d", is_daemon);
log_info("running neuron main process, daemon: %d", args.daemonized);
manager = neu_manager_create();
if (manager == NULL) {
log_error("Failed to create neuron manager, exit!");
@@ -271,7 +192,6 @@ int main(int argc, char *argv[])
main_end:
uninit();
free(config_file);
free(log_file);
neu_cli_args_fini(&args);
return rv;
}