OpenRaider  0.1.4-dev
Open Source Tomb Raider Game Engine implementation
commander.c
Go to the documentation of this file.
1 
2 //
3 // commander.c
4 //
5 // Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>
6 //
7 
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <assert.h>
12 #include "commander.h"
13 
14 /*
15  * Output error and exit.
16  */
17 
18 static void
19 error(char *msg) {
20  fprintf(stderr, "%s\n", msg);
21  exit(1);
22 }
23 
24 /*
25  * Output command version.
26  */
27 
28 static void
30  printf("%s\n", self->version);
31  command_free(self);
32  exit(0);
33 }
34 
35 /*
36  * Output command help.
37  */
38 
39 void
41  printf("\n");
42  printf(" Usage: %s %s\n", self->name, self->usage);
43  printf("\n");
44  printf(" Options:\n");
45  printf("\n");
46 
47  int i;
48  for (i = 0; i < self->option_count; ++i) {
49  command_option_t *option = &self->options[i];
50  printf(" %s, %-25s %s\n"
51  , option->small
52  , option->large_with_arg
53  , option->description);
54  }
55 
56  printf("\n");
57  command_free(self);
58  exit(0);
59 }
60 
61 /*
62  * Initialize with program `name` and `version`.
63  */
64 
65 void
66 command_init(command_t *self, const char *name, const char *version) {
67  self->arg = NULL;
68  self->name = name;
69  self->version = version;
70  self->option_count = self->argc = 0;
71  self->usage = "[options]";
72  self->nargv = NULL;
73  command_option(self, "-V", "--version", "output program version", command_version);
74  command_option(self, "-h", "--help", "output help information", command_help);
75 }
76 
77 /*
78  * Free up commander after use.
79  */
80 
81 void
83  int i;
84 
85  for (i = 0; i < self->option_count; ++i) {
86  command_option_t *option = &self->options[i];
87  free(option->argname);
88  free(option->large);
89  }
90 
91  if (self->nargv) {
92  for (i = 0; self->nargv[i]; ++i) {
93  free(self->nargv[i]);
94  }
95  free(self->nargv);
96  }
97 }
98 
99 /*
100  * Parse argname from `str`. For example
101  * Take "--required <arg>" and populate `flag`
102  * with "--required" and `arg` with "<arg>".
103  */
104 
105 static void
106 parse_argname(const char *str, char *flag, char *arg) {
107  int buffer = 0;
108  size_t flagpos = 0;
109  size_t argpos = 0;
110  size_t len = strlen(str);
111  size_t i;
112 
113  for (i = 0; i < len; ++i) {
114  if (buffer || '[' == str[i] || '<' == str[i]) {
115  buffer = 1;
116  arg[argpos++] = str[i];
117  } else {
118  if (' ' == str[i]) continue;
119  flag[flagpos++] = str[i];
120  }
121  }
122 
123  arg[argpos] = '\0';
124  flag[flagpos] = '\0';
125 }
126 
127 /*
128  * Normalize the argument vector by exploding
129  * multiple options (if any). For example
130  * "foo -abc --scm git" -> "foo -a -b -c --scm git"
131  */
132 
133 static char **
134 normalize_args(int *argc, char **argv) {
135  int size = 0;
136  int alloc = *argc + 1;
137  char **nargv = malloc(alloc * sizeof(char *));
138  int i;
139 
140  for (i = 0; argv[i]; ++i) {
141  const char *arg = argv[i];
142  size_t len = strlen(arg);
143 
144  // short flag
145  if (len > 2 && '-' == arg[0] && !strchr(arg + 1, '-')) {
146  alloc += len - 2;
147  nargv = realloc(nargv, alloc * sizeof(char *));
148  size_t j;
149  for (j = 1; j < len; ++j) {
150  nargv[size] = malloc(3);
151  sprintf(nargv[size], "-%c", arg[j]);
152  size++;
153  }
154  continue;
155  }
156 
157  // regular arg
158  nargv[size] = malloc(len + 1);
159  strcpy(nargv[size], arg);
160  size++;
161  }
162 
163  nargv[size] = NULL;
164  *argc = size;
165  return nargv;
166 }
167 
168 /*
169  * Define an option.
170  */
171 
172 void
173 command_option(command_t *self, const char *small, const char *large, const char *desc, command_callback_t cb) {
174  if (self->option_count == COMMANDER_MAX_OPTIONS) {
175  command_free(self);
176  error("Maximum option definitions exceeded");
177  }
178  int n = self->option_count++;
179  command_option_t *option = &self->options[n];
180  option->cb = cb;
181  option->small = small;
182  option->description = desc;
183  option->required_arg = option->optional_arg = 0;
184  option->large_with_arg = large;
185  option->argname = malloc(strlen(large) + 1);
186  assert(option->argname);
187  option->large = malloc(strlen(large) + 1);
188  assert(option->large);
189  parse_argname(large, option->large, option->argname);
190  if ('[' == option->argname[0]) option->optional_arg = 1;
191  if ('<' == option->argname[0]) option->required_arg = 1;
192 }
193 
194 /*
195  * Parse `argv` (internal).
196  * Input arguments should be normalized first
197  * see `normalize_args`.
198  */
199 
200 static void
201 command_parse_args(command_t *self, int argc, char **argv) {
202  int literal = 0;
203  int i, j;
204 
205  for (i = 1; i < argc; ++i) {
206  const char *arg = argv[i];
207  for (j = 0; j < self->option_count; ++j) {
208  command_option_t *option = &self->options[j];
209 
210  // match flag
211  if (!strcmp(arg, option->small) || !strcmp(arg, option->large)) {
212  self->arg = NULL;
213 
214  // required
215  if (option->required_arg) {
216  arg = argv[++i];
217  if (!arg || '-' == arg[0]) {
218  fprintf(stderr, "%s %s argument required\n", option->large, option->argname);
219  command_free(self);
220  exit(1);
221  }
222  self->arg = arg;
223  }
224 
225  // optional
226  if (option->optional_arg) {
227  if (argv[i + 1] && '-' != argv[i + 1][0]) {
228  self->arg = argv[++i];
229  }
230  }
231 
232  // invoke callback
233  option->cb(self);
234  goto match;
235  }
236  }
237 
238  // --
239  if ('-' == arg[0] && '-' == arg[1] && 0 == arg[2]) {
240  literal = 1;
241  goto match;
242  }
243 
244  // unrecognized
245  if ('-' == arg[0] && !literal) {
246  fprintf(stderr, "unrecognized flag %s\n", arg);
247  command_free(self);
248  exit(1);
249  }
250 
251  int n = self->argc++;
252  if (n == COMMANDER_MAX_ARGS) {
253  command_free(self);
254  error("Maximum number of arguments exceeded");
255  }
256  self->argv[n] = (char *) arg;
257  match:;
258  }
259 }
260 
261 /*
262  * Parse `argv` (public).
263  */
264 
265 void
266 command_parse(command_t *self, int argc, char **argv) {
267  self->nargv = normalize_args(&argc, argv);
268  command_parse_args(self, argc, self->nargv);
269  self->argv[self->argc] = NULL;
270 }
const char * description
Definition: commander.h:54
char * argname
Definition: commander.h:50
static char ** normalize_args(int *argc, char **argv)
Definition: commander.c:134
void command_help(command_t *self)
Definition: commander.c:40
static void command_version(command_t *self)
Definition: commander.c:29
void command_free(command_t *self)
Definition: commander.c:82
#define assert(x)
Definition: global.h:124
static void error(char *msg)
Definition: commander.c:19
void(* command_callback_t)(struct command *self)
Definition: commander.h:41
const char * small
Definition: commander.h:52
static void parse_argname(const char *str, char *flag, char *arg)
Definition: commander.c:106
#define COMMANDER_MAX_ARGS
Definition: commander.h:28
void command_init(command_t *self, const char *name, const char *version)
Definition: commander.c:66
void command_option(command_t *self, const char *small, const char *large, const char *desc, command_callback_t cb)
Definition: commander.c:173
const char * large_with_arg
Definition: commander.h:53
void command_parse(command_t *self, int argc, char **argv)
Definition: commander.c:266
#define COMMANDER_MAX_OPTIONS
Definition: commander.h:20
static void command_parse_args(command_t *self, int argc, char **argv)
Definition: commander.c:201
command_callback_t cb
Definition: commander.h:55