Skip to content
Extraits de code Groupes Projets
Vérifiée Valider a858b596 rédigé par Kubat's avatar Kubat
Parcourir les fichiers

LKT & CMD: Handle in a more cleaner way the options for cmd.h

Name those options 'env', as they are global options that are common to
all the commands (normally). Not using the POSIX env for now for that,
but they are setted in a same-fashion way:

lkt port=6601 queue 10
    \         \     \_ options passed to the command
     \         \______ the commands
      \_______________ the env, or global options
parent b1d5e3c4
Aucune branche associée trouvée
Aucune étiquette associée trouvée
1 requête de fusion!158Lkt output v2
......@@ -62,6 +62,7 @@ ForEachMacros:
- 'FOR_EVER'
- 'FOR_EVER_IF'
- 'FOR_EVER_UNTIL'
- 'FOR_EACH_FLAT_LIST_ITEM'
IncludeCategories:
- Regex: '.*'
......
......@@ -15,29 +15,69 @@ extern "C" {
{ \
.name = NULL, .call = func \
}
#define CMD_ENV_NULL \
{ \
.name = NULL, .value = NULL, .handler = NULL, \
}
#define CMD_ENV(n, hndl) \
{ \
.name = n, .handler = hndl \
}
#define CMD_ENV_DEFAULT(n, v, hndl) \
{ \
.name = n, .value = v, .handler = hndl \
}
/* The arguments passed to a command */
struct cmd_args {
int argc; /* The number of arguments passed. */
const char **argv; /* An array of argument passed. */
};
/* Callback to call on command, takes the arguments */
typedef void (*cmd_callback)(struct cmd_args *);
/* Callback for the 'apply_env' function. */
typedef void (*cmd_env_callback)(const char *name, const char *value, void *user);
/* The 'option' command struct, this is how a new command is registered for the
* cmd_parse command. The list must end with the CMD_OPT_NULL or
* CMD_OPT_DEFAULT macros (set the NULL at the end of a list with no
* length...). The command names MUST NOT include the = or : characters! They
* also must be distinguishable, i.e. one command name must not be simply
* included in another name:
* - play, playlist => bad, because play is included in playlist
* - status, start => good, no inclusion between the names */
struct cmd_opt {
const char *name;
cmd_callback call;
};
/* Options or env of the command. Don't depend on the POSIX env variables for
* now and do it ourself. */
struct cmd_env {
const char *name;
const char *value;
cmd_env_callback handler;
};
/* Parse the 'env' of the command, i.e. the options before the command, like:
* ./a.out opt1=foo opt2=bar sub-command com1
* The cmd_apply function is here to do the handle stuff for the options to be
* registered in a user specific way (callback + user pointer). */
void cmd_parse_env(struct cmd_env *env, int *argc, const char ***argv);
void cmd_apply_env(struct cmd_env *env, void *user);
/* Parse the command line with the list of options. No parameter may be NULL.
Does not return. */
* Does not return. */
EXIT_FUNCTION cmd_parse(struct cmd_opt *opts, int argc, const char **argv);
/* Must be setted for the lkt_cmd_parse function to display the correct help
in case of errors. */
* in case of errors. */
void cmd_set_executable_name(const char *);
const char *cmd_get_executable_name(void);
/* Prints the help and exit */
/* Prints the help if possible and exit. */
EXIT_FUNCTION print_help(void);
#if defined(__cplusplus)
......
......@@ -58,7 +58,10 @@ extern EXIT_FUNCTION ___not_implemented(const char *func, char *file, int line);
err_flag = errno != 0 || endptr == str; \
})
/* Get a generic function pointer from any function pointer. */
#define FUNCTION_POINTER(func) ((void (*)(void))(func))
/* Forever macros */
#define FOR_EVER for (;;)
#define FOR_EVER_IF(expr) \
FOR_EVER { \
......@@ -67,6 +70,9 @@ extern EXIT_FUNCTION ___not_implemented(const char *func, char *file, int line);
}
#define FOR_EVER_UNTIL(expr) FOR_EVER_IF (!(expr))
/* For each, for flat-list. Need to be null terminated on the normally non-null field. */
#define FOR_EACH_FLAT_LIST_ITEM(it, nnull_field) for (; (it)->nnull_field != NULL; it++)
/* Custom defined assert. */
extern void (*___lkt_assert)(const char *file, int line, const char *func, const char *msg);
#ifdef assert
......
......@@ -59,6 +59,63 @@ print_help(void)
}
}
PRIVATE_FUNCTION size_t
___get_max_options(struct cmd_env *env)
{
struct cmd_env *it = env;
size_t ret = 0;
FOR_EACH_FLAT_LIST_ITEM (it, name) {
ret++;
}
return ret;
}
PRIVATE_FUNCTION bool
___find_and_set_option(struct cmd_env *env, const char *name, size_t name_len, const char *value)
{
struct cmd_env *it = env;
FOR_EACH_FLAT_LIST_ITEM (it, name) {
if (STR_NMATCH(it->name, name, name_len)) {
it->value = value;
return true;
}
}
return false;
}
void
cmd_apply_env(struct cmd_env *env, void *user)
{
struct cmd_env *it = env;
FOR_EACH_FLAT_LIST_ITEM (it, name) {
it->handler(it->name, it->value, user);
}
}
void
cmd_parse_env(struct cmd_env *env, int *argc, const char ***argv)
{
assert((*argv) >= 0);
size_t max_options = ___get_max_options(env);
size_t len = 0;
int got = 0;
for (size_t i = 1; i < (size_t)(*argc) && i < max_options; ++i) {
len = strcspn((*argv)[i], "=:");
got += ___find_and_set_option(env, (*argv)[i], len, (*argv)[i] + len + 1);
}
/* Skip the gotten options from the command line. */
*argv = &(*argv)[got + 1];
*argc = (*argc) - (got + 1);
}
EXIT_FUNCTION
cmd_parse(struct cmd_opt *opts, int argc, const char **argv)
{
......
......@@ -45,7 +45,7 @@ row_printer row_print = NULL;
#define LKT_MAX_OPTIONS 4 /* Number of options that can be passed to lkt before the commands. */
static const char *host;
static const char *port;
static const char *password;
static const char *pwd;
static const char *row_format;
/* Default queue length to query */
......@@ -410,10 +410,10 @@ just_send(queue_flatten__, "__flat\n");
EXIT_FUNCTION
simple_send_with_password__(const char *cmd)
{
FAIL_UNLESS(password, "Password not provided");
FAIL_UNLESS(pwd, "Password not provided");
FILE *sock = lkt_connect();
write_socket(sock, "command_list_begin\n");
write_socket(sock, "password %s\n", password);
write_socket(sock, "password %s\n", pwd);
write_socket(sock, "%s\n", cmd);
write_socket(sock, "command_list_end\n");
exit(EXIT_SUCCESS);
......@@ -436,13 +436,13 @@ kill__(struct cmd_args *args)
EXIT_FUNCTION
rescan_or_update__(struct cmd_args *args, const char *cmd)
{
FAIL_UNLESS(password, "Password not provided");
FAIL_UNLESS(pwd, "Password not provided");
FILE *sock = lkt_connect();
/* All the db */
if (args->argc == 0) {
write_socket(sock, "command_list_begin\n");
write_socket(sock, "password %s\n", password);
write_socket(sock, "password %s\n", pwd);
write_socket(sock, "%s\n", cmd);
write_socket(sock, "command_list_end\n");
}
......@@ -453,7 +453,7 @@ rescan_or_update__(struct cmd_args *args, const char *cmd)
memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char));
FAIL_IF(lkt_get_query_type(args, buff, LKT_MESSAGE_MAX), "Query is not valid");
write_socket(sock, "command_list_begin\n");
write_socket(sock, "password %s\n", password);
write_socket(sock, "password %s\n", pwd);
write_socket(sock, "%s %s\n", cmd, buff);
write_socket(sock, "command_list_end\n");
}
......@@ -1314,32 +1314,37 @@ sigpipe__(int sig)
exit(EXIT_FAILURE);
}
/* Functions declarations. */
/* Handle the options switches */
PRIVATE_FUNCTION void
parse_args(args_t *args, int argc, const char **argv)
{
int i, got = 0;
size_t len;
#define ___DEFINE_SETTER(what) \
PRIVATE_FUNCTION void ___USE_SETTER(what)(const char UNUSED *name, const char *value, void UNUSED *user) \
{ \
what = value; \
}
#define ___USE_SETTER(what) ___set_env_##what
for (i = 1; i < argc && i < LKT_MAX_OPTIONS; ++i) {
len = strcspn(argv[i], "=:");
___DEFINE_SETTER(host);
___DEFINE_SETTER(port);
___DEFINE_SETTER(pwd);
#define ___get_args(name) \
if (STR_NMATCH(#name, argv[i], len)) { \
args->name = (argv[i] + len + 1); \
++got; \
}
___get_args(host);
___get_args(port);
___get_args(pwd);
___get_args(row_format);
#undef ___get_args
PRIVATE_FUNCTION void ___USE_SETTER(row_format)(const char UNUSED *name, const char *value, void UNUSED *user)
{
row_format = value;
setup_row_printer();
}
args->argv = &argv[got + 1];
args->argc = argc - (got + 1);
}
// clang-format off
static struct cmd_env env_[] = {
CMD_ENV_DEFAULT("host", "localhost", ___USE_SETTER(host)),
CMD_ENV_DEFAULT("port", "6600", ___USE_SETTER(port)),
CMD_ENV("pwd", ___USE_SETTER(pwd)),
CMD_ENV("row_format", ___USE_SETTER(row_format)),
CMD_ENV_NULL,
};
// clang-format on
#undef ___USE_SETTER
#undef ___DEFINE_SETTER
int
main(int argc, const char **argv)
......@@ -1352,20 +1357,8 @@ main(int argc, const char **argv)
if (signal(SIGPIPE, sigpipe__))
LOG_ERROR("SYS", "Failed to install handler for SIGPIPE signal (you may be using php...)");
args_t args = {
.host = "localhost",
.port = "6600",
};
parse_args(&args, argc, argv);
host = args.host;
port = args.port;
password = args.pwd;
row_format = args.row_format;
setup_row_printer();
/* Communication with lektor. */
cmd_parse(options_, args.argc, args.argv);
/* Parse */
cmd_parse_env(env_, &argc, &argv);
cmd_apply_env(env_, NULL);
cmd_parse(options_, argc, argv);
}
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Veuillez vous inscrire ou vous pour commenter