aboutsummaryrefslogtreecommitdiffstats
path: root/src/command.h
blob: abd7d556e89de3a7e40e7a8cbb97f54edc6b274b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#ifndef L2SU_COMMAND_H_INCLUDED
#define L2SU_COMMAND_H_INCLUDED

#include <stddef.h>

/* for CMD_ macros */
#include <stdlib.h>
#include <string.h>
#include <errno.h>

enum {
  CMD_NODE_TYPE_NULL,
  CMD_NODE_TYPE_LITERAL,
  CMD_NODE_TYPE_ARGUMENT,
  CMD_NODE_FLAG_EXEC = 0x100
};

enum {
  CMD_INIT_SUCCESS,
  CMD_INIT_ERROR
};

enum {
  CMD_RESULT_SUCCESS,
  CMD_RESULT_FAIL
};

enum {
  CMD_VALIDATE_PASS,      /* yep this argument is correct */
  CMD_VALIDATE_FAIL_SKIP, /* this argument is NOT correct */
  CMD_VALIDATE_FAIL_ERROR /* this argument IS the correct argument, but it is invalid (stop searching siblings) */
};

enum {
  CMD_PARSE_SUCCESS, /* parse successful */
  CMD_PARSE_ESYNTAX, /* invalid command syntax */
  CMD_PARSE_EUSAGE   /* function was called with NULL arguments */
};

#define CMD_FATAL_(_op) do {         \
  _op;                               \
  exit(EXIT_FAILURE);                \
} while (0)

#define CMD_MSG(_l, _s, ...) fprintf(stderr, _l ": " _s "\n", __VA_ARGS__)
#define CMD_MSG0(_l, _s)     fputs(_l ": " _s "\n", stderr);

#define CMD_FATAL(_s, ...) CMD_FATAL_(CMD_MSG("fatal", _s, __VA_ARGS__))
#define CMD_FATAL0(_s)     CMD_FATAL_(CMD_MSG0("fatal", _s))

#define CMD_ERROR(_s, ...) CMD_MSG("error", _s, __VA_ARGS__)
#define CMD_ERROR0(_s)     CMD_MSG0("error", _s)

#define CMD_WARN(_s, ...) CMD_MSG("warn", _s, __VA_ARGS__)
#define CMD_WARN0(_s)     CMD_MSG0("warn", _s)

#define CMD_INFO(_s, ...) CMD_MSG("info", _s, __VA_ARGS__)
#define CMD_INFO0(_s)     CMD_MSG0("info", _s)

#ifdef NDEBUG
#define CMD_DEBUG(_s, ...)
#define CMD_DEBUG0(_s)
#else
#define CMD_DEBUG(_s, ...) CMD_MSG("debug", _s, __VA_ARGS__)
#define CMD_DEBUG0(_s)     CMD_MSG0("debug", _s)
#endif

#define CMD_MSG_UNKNOWN_ARGUMENT    "Unknown argument '%s'."
#define CMD_MSG_REQ_ARG_UNSPECIFIED "Required argument '%s' not specified."
#define CMD_MSG_INVALID_UUID        "Invalid UUID '%s'."

#define CMD_MSG_ALLOCATION_FAILED "Allocation failed."

struct l2_command_node;

struct l2_context_node {
  struct l2_context_node *next;
  struct l2_command_node *node;

  char *value; /* for argument command nodes */
};

typedef unsigned (l2_cmd_proc_t)(struct l2_context_node * /* ctx */, char ** /* args */);
typedef unsigned (l2_cmd_validate_proc_t)(const char * /* arg */);

struct l2_command_node {
  unsigned type;
  const char *name;

  union {
    /* for literal nodes */
    const char **aliases;

    /* for argument nodes */
    l2_cmd_validate_proc_t *validate_proc; /* a validate_proc of NULL is assumed to always return CMD_VALIDATE_PASS */
  } extra;

  l2_cmd_proc_t *cmd_proc;

  struct l2_command_node *children;
};

extern struct l2_command_node l2_cmd_root;

/* unsigned l2_cmd_init(void); */

struct l2_parseinfo {
  char **argv;
  l2_cmd_proc_t *proc;
  struct l2_context_node *ctx;
};

unsigned l2_cmd_parse_command(char **argv, struct l2_parseinfo *parseinfo);
void l2_cmd_free_ctx(struct l2_context_node *ctx);

/* DESCRIPTION:
 * This function is for unpacking a bunch of arguments from a parsed command into
 * string variables.
 *
 * HOW TO USE:
 * Pass your command context followed by your arguments (const char *name, char **pvalue).
 * Prefix the name with "#" if it is optional.
 *
 * This function will exit if a required value was not present.
 *
 * Example: l2_cmd_collect_args(ctx, 2, "name", &name, "#location", &path);
 */
void l2_cmd_collect_args(struct l2_context_node *ctx, unsigned argc, ...);

#endif /* include guard */