aboutsummaryrefslogtreecommitdiffstats
path: root/src/command.h
blob: 77092926ec0bbe21a289514d2db91ead89d5e148 (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
#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_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 */