Browse Source

Added dep clibs/commander for command line parsing

Thomas Buck 9 years ago
parent
commit
963ed862de

+ 1
- 0
CMakeLists.txt View File

@@ -23,6 +23,7 @@ endif()
23 23
 
24 24
 # Include directories
25 25
 include_directories ("${PROJECT_SOURCE_DIR}/include")
26
+include_directories ("${PROJECT_SOURCE_DIR}/src/deps")
26 27
 include_directories ("${PROJECT_BINARY_DIR}")
27 28
 
28 29
 # Include External Modules

+ 2
- 0
README.md View File

@@ -171,3 +171,5 @@ See the respective files in `cmake` for their licensing.
171 171
 * Copyright 2003-2009 Kitware, Inc.
172 172
 * Eric Wing
173 173
 
174
+The [clibs/commander](https://github.com/clibs/commander) dependency is Copyright (c) 2012 TJ Holowaychuk (tj@vision-media.ca) and licensed under the [MIT License](http://opensource.org/licenses/MIT).
175
+

+ 1
- 0
TODO.md View File

@@ -11,6 +11,7 @@
11 11
     * Rewrite Console and use operator << to write to the console?
12 12
 * Mesh has 2 different approaches of storing the same data (eg. mColors and mColorArray), but half of ‘em isn’t implemented. Unify this, probably even combining Mesh and StaticMesh...
13 13
 * Don’t use float everywhere just because (eg. float colors)
14
+* Add verbose command line flag for debug output also in release builds
14 15
 
15 16
 ## Cmake
16 17
 

+ 4
- 1
src/CMakeLists.txt View File

@@ -202,6 +202,7 @@ set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${OpenRaider_CXX_FLAGS} ${O
202 202
 set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${OpenRaider_CXX_FLAGS} ${OpenRaider_CXX_FLAGS_RELEASE}")
203 203
 
204 204
 # Add subdirectories
205
+add_subdirectory ("deps")
205 206
 add_subdirectory ("math")
206 207
 add_subdirectory ("utils")
207 208
 
@@ -257,6 +258,7 @@ if (UNIX)
257 258
 endif (UNIX)
258 259
 
259 260
 # Add utils Library
261
+set (LIBS ${LIBS} OpenRaider_deps)
260 262
 set (LIBS ${LIBS} OpenRaider_math)
261 263
 set (LIBS ${LIBS} OpenRaider_utils)
262 264
 
@@ -268,4 +270,5 @@ target_link_libraries (OpenRaider ${LIBS})
268 270
 # Add target to run executable
269 271
 if (${CMAKE_GENERATOR} STREQUAL "Unix Makefiles" OR ${CMAKE_GENERATOR} STREQUAL "MinGW Makefiles")
270 272
     add_custom_target(run COMMAND OpenRaider DEPENDS OpenRaider WORKING_DIRECTORY ${CMAKE_PROJECT_DIR})
271
-endif (${CMAKE_GENERATOR} STREQUAL "Unix Makefiles" OR ${CMAKE_GENERATOR} STREQUAL "MinGW Makefiles") 
273
+endif (${CMAKE_GENERATOR} STREQUAL "Unix Makefiles" OR ${CMAKE_GENERATOR} STREQUAL "MinGW Makefiles")
274
+

+ 6
- 0
src/deps/CMakeLists.txt View File

@@ -0,0 +1,6 @@
1
+# Source files
2
+set (DEPS_SRCS ${DEPS_SRCS} "commander/commander.c")
3
+
4
+# Add library
5
+add_library (OpenRaider_deps ${DEPS_SRCS})
6
+

+ 269
- 0
src/deps/commander/commander.c View File

@@ -0,0 +1,269 @@
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
29
+command_version(command_t *self) {
30
+  printf("%s\n", self->version);
31
+  command_free(self);
32
+  exit(0);
33
+}
34
+
35
+/*
36
+ * Output command help.
37
+ */
38
+
39
+void
40
+command_help(command_t *self) {
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
82
+command_free(command_t *self) {
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
+      for (size_t j = 1; j < len; ++j) {
149
+        nargv[size] = malloc(3);
150
+        sprintf(nargv[size], "-%c", arg[j]);
151
+        size++;
152
+      }
153
+      continue;
154
+    }
155
+
156
+    // regular arg
157
+    nargv[size] = malloc(len + 1);
158
+    strcpy(nargv[size], arg);
159
+    size++;
160
+  }
161
+
162
+  nargv[size] = NULL;
163
+  *argc = size;
164
+  return nargv;
165
+}
166
+
167
+/*
168
+ * Define an option.
169
+ */
170
+
171
+void
172
+command_option(command_t *self, const char *small, const char *large, const char *desc, command_callback_t cb) {
173
+  if (self->option_count == COMMANDER_MAX_OPTIONS) {
174
+    command_free(self);
175
+    error("Maximum option definitions exceeded");
176
+  }
177
+  int n = self->option_count++;
178
+  command_option_t *option = &self->options[n];
179
+  option->cb = cb;
180
+  option->small = small;
181
+  option->description = desc;
182
+  option->required_arg = option->optional_arg = 0;
183
+  option->large_with_arg = large;
184
+  option->argname = malloc(strlen(large) + 1);
185
+  assert(option->argname);
186
+  option->large = malloc(strlen(large) + 1);
187
+  assert(option->large);
188
+  parse_argname(large, option->large, option->argname);
189
+  if ('[' == option->argname[0]) option->optional_arg = 1;
190
+  if ('<' == option->argname[0]) option->required_arg = 1;
191
+}
192
+
193
+/*
194
+ * Parse `argv` (internal).
195
+ * Input arguments should be normalized first
196
+ * see `normalize_args`.
197
+ */
198
+
199
+static void
200
+command_parse_args(command_t *self, int argc, char **argv) {
201
+  int literal = 0;
202
+  int i, j;
203
+
204
+  for (i = 1; i < argc; ++i) {
205
+    const char *arg = argv[i];
206
+    for (j = 0; j < self->option_count; ++j) {
207
+      command_option_t *option = &self->options[j];
208
+
209
+      // match flag
210
+      if (!strcmp(arg, option->small) || !strcmp(arg, option->large)) {
211
+        self->arg = NULL;
212
+
213
+        // required
214
+        if (option->required_arg) {
215
+          arg = argv[++i];
216
+          if (!arg || '-' == arg[0]) {
217
+            fprintf(stderr, "%s %s argument required\n", option->large, option->argname);
218
+            command_free(self);
219
+            exit(1);
220
+          }
221
+          self->arg = arg;
222
+        }
223
+
224
+        // optional
225
+        if (option->optional_arg) {
226
+          if (argv[i + 1] && '-' != argv[i + 1][0]) {
227
+            self->arg = argv[++i];
228
+          }
229
+        }
230
+
231
+        // invoke callback
232
+        option->cb(self);
233
+        goto match;
234
+      }
235
+    }
236
+
237
+    // --
238
+    if ('-' == arg[0] && '-' == arg[1] && 0 == arg[2]) {
239
+      literal = 1;
240
+      goto match;
241
+    }
242
+
243
+    // unrecognized
244
+    if ('-' == arg[0] && !literal) {
245
+      fprintf(stderr, "unrecognized flag %s\n", arg);
246
+      command_free(self);
247
+      exit(1);
248
+    }
249
+
250
+    int n = self->argc++;
251
+    if (n == COMMANDER_MAX_ARGS) {
252
+      command_free(self);
253
+      error("Maximum number of arguments exceeded");
254
+    }
255
+    self->argv[n] = (char *) arg;
256
+    match:;
257
+  }
258
+}
259
+
260
+/*
261
+ * Parse `argv` (public).
262
+ */
263
+
264
+void
265
+command_parse(command_t *self, int argc, char **argv) {
266
+  self->nargv = normalize_args(&argc, argv);
267
+  command_parse_args(self, argc, self->nargv);
268
+  self->argv[self->argc] = NULL;
269
+}

+ 96
- 0
src/deps/commander/commander.h View File

@@ -0,0 +1,96 @@
1
+
2
+//
3
+// commander.h
4
+//
5
+// Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>
6
+//
7
+
8
+#ifndef COMMANDER_H
9
+#define COMMANDER_H
10
+
11
+#ifdef __cplusplus
12
+extern "C" {
13
+#endif
14
+
15
+/*
16
+ * Max options that can be defined.
17
+ */
18
+
19
+#ifndef COMMANDER_MAX_OPTIONS
20
+#define COMMANDER_MAX_OPTIONS 32
21
+#endif
22
+
23
+/*
24
+ * Max arguments that can be passed.
25
+ */
26
+
27
+#ifndef COMMANDER_MAX_ARGS
28
+#define COMMANDER_MAX_ARGS 32
29
+#endif
30
+
31
+/*
32
+ * Command struct.
33
+ */
34
+
35
+struct command;
36
+
37
+/*
38
+ * Option callback.
39
+ */
40
+
41
+typedef void (* command_callback_t)(struct command *self);
42
+
43
+/*
44
+ * Command option.
45
+ */
46
+
47
+typedef struct {
48
+  int optional_arg;
49
+  int required_arg;
50
+  char *argname;
51
+  char *large;
52
+  const char *small;
53
+  const char *large_with_arg;
54
+  const char *description;
55
+  command_callback_t cb;
56
+} command_option_t;
57
+
58
+/*
59
+ * Command.
60
+ */
61
+
62
+typedef struct command {
63
+  void *data;
64
+  const char *usage;
65
+  const char *arg;
66
+  const char *name;
67
+  const char *version;
68
+  int option_count;
69
+  command_option_t options[COMMANDER_MAX_OPTIONS];
70
+  int argc;
71
+  char *argv[COMMANDER_MAX_ARGS];
72
+  char **nargv;
73
+} command_t;
74
+
75
+// prototypes
76
+
77
+void
78
+command_init(command_t *self, const char *name, const char *version);
79
+
80
+void
81
+command_free(command_t *self);
82
+
83
+void
84
+command_help(command_t *self);
85
+
86
+void
87
+command_option(command_t *self, const char *small, const char *large, const char *desc, command_callback_t cb);
88
+
89
+void
90
+command_parse(command_t *self, int argc, char **argv);
91
+
92
+#ifdef __cplusplus
93
+}
94
+#endif
95
+
96
+#endif /* COMMANDER_H */

+ 9
- 0
src/deps/commander/package.json View File

@@ -0,0 +1,9 @@
1
+{
2
+  "name": "commander",
3
+  "version": "1.3.2",
4
+  "repo": "clibs/commander",
5
+  "description": "Command-line argument parser",
6
+  "keywords": ["cli", "command", "parser", "argv", "args", "options"],
7
+  "license": "MIT",
8
+  "src": ["src/commander.h", "src/commander.c"]
9
+}

+ 20
- 51
src/main.cpp View File

@@ -19,6 +19,7 @@
19 19
 #include "Render.h"
20 20
 #include "TextureManager.h"
21 21
 #include "World.h"
22
+#include "commander/commander.h"
22 23
 #include "utils/strings.h"
23 24
 #include "utils/time.h"
24 25
 
@@ -34,8 +35,6 @@
34 35
 #error No Windowing Library selected!
35 36
 #endif
36 37
 
37
-void cleanupHandler(void);
38
-
39 38
 Camera &getCamera() {
40 39
     static Camera gCamera;
41 40
     return gCamera;
@@ -97,7 +96,7 @@ World &getWorld() {
97 96
     return gWorld;
98 97
 }
99 98
 
100
-void cleanupHandler(void) {
99
+static void cleanupHandler(void) {
101 100
 #ifdef DEBUG
102 101
     std::cout << std::endl;
103 102
     std::cout << "Thanks for testing " << VERSION << std::endl;
@@ -108,38 +107,23 @@ void cleanupHandler(void) {
108 107
 #endif
109 108
 }
110 109
 
110
+static bool configFileWasSpecified = false;
111
+static void configFileCallback(command_t *self) {
112
+    getOpenRaider().loadConfig(self->arg);
113
+    configFileWasSpecified = true;
114
+}
115
+
111 116
 int main(int argc, char *argv[]) {
112
-    bool configArg = false;
113
-
114
-    // Handle arguments
115
-    if (argc == 2) {
116
-        // Check for command line switches
117
-        if ((strcmp("-h", argv[1]) == 0)
118
-                || (strcmp("--help", argv[1]) == 0)) {
119
-            // Display help text
120
-            std::cout << argv[0] << " [OPTIONS | /path/to/config]" << std::endl;
121
-            std::cout << "Options:" << std::endl;
122
-            std::cout << "\t--help" << std::endl;
123
-            std::cout << "\t-h\tDisplay this help text" << std::endl;
124
-            std::cout << "\t--version" << std::endl;
125
-            std::cout << "\t-v\tDisplay version information" << std::endl;
126
-            std::cout << "If no options are given, the default config will be loaded from:" << std::endl;
127
-            std::cout << "\t" << DEFAULT_CONFIG_FILE << std::endl;
128
-            std::cout << "or" << std::endl;
129
-            std::cout << "\t" << DEFAULT_CONFIG_PATH << "/" << DEFAULT_CONFIG_FILE << std::endl;
130
-            return 0;
131
-        } else if ((strcmp("-v", argv[1]) == 0)
132
-                || (strcmp("--version", argv[1]) == 0)) {
133
-            // Display version
134
-            std::cout << VERSION << std::endl;
135
-            return 0;
136
-        } else {
137
-            configArg = true;
117
+    command_t cmd;
118
+    command_init(&cmd, argv[0], VERSION);
119
+    //command_option(&cmd, "-v", "--verbose", "enable verbose output", functionPointer);
120
+    command_option(&cmd, "-c", "--config <file>", "select config file to use", configFileCallback);
121
+    command_parse(&cmd, argc, argv);
122
+
123
+    if (!configFileWasSpecified) {
124
+        if (getOpenRaider().loadConfig(DEFAULT_CONFIG_FILE) != 0) {
125
+            getOpenRaider().loadConfig(DEFAULT_CONFIG_PATH "/" DEFAULT_CONFIG_FILE);
138 126
         }
139
-    } else if (argc > 2) {
140
-        std::cout << "Usage:" << std::endl;
141
-        std::cout << argv[0] << " -h" << std::endl;
142
-        return 1;
143 127
     }
144 128
 
145 129
 #ifdef DEBUG
@@ -148,29 +132,14 @@ int main(int argc, char *argv[]) {
148 132
 
149 133
     atexit(cleanupHandler);
150 134
 
151
-    // Try to load a configuration
152
-    if (configArg) {
153
-        if (getOpenRaider().loadConfig(argv[1]) != 0) {
154
-            std::cout << "Could not find the specified config file. Aborting..." << std::endl;
155
-            return 2;
156
-        }
157
-    } else {
158
-        if (getOpenRaider().loadConfig(DEFAULT_CONFIG_FILE) != 0) {
159
-            if (getOpenRaider().loadConfig(DEFAULT_CONFIG_PATH "/" DEFAULT_CONFIG_FILE) != 0) {
160
-                std::cout << "Could not find a config file. Aborting..." << std::endl;
161
-                return 3;
162
-            }
163
-        }
164
-    }
165
-
166
-    // Initialize everything
167 135
     int error = getOpenRaider().initialize();
168 136
     if (error != 0) {
169 137
         std::cout << "Could not initialize OpenRaider (" << error << ")!" << std::endl;
170
-        return 4;
138
+        return 2;
171 139
     }
172 140
 
173
-    // Enter Main loop
141
+    command_free(&cmd);
142
+
174 143
     getConsole().print("Starting %s", VERSION);
175 144
     getOpenRaider().run();
176 145
 

+ 1
- 3
src/math/CMakeLists.txt View File

@@ -4,8 +4,6 @@ set (MATH_SRCS ${MATH_SRCS} "Matrix.cpp")
4 4
 set (MATH_SRCS ${MATH_SRCS} "Quaternion.cpp")
5 5
 set (MATH_SRCS ${MATH_SRCS} "Vector3d.cpp")
6 6
 
7
-# Include directory
8
-include_directories ("${PROJECT_SOURCE_DIR}/include")
9
-
10 7
 # Add library
11 8
 add_library (OpenRaider_math ${MATH_SRCS})
9
+

+ 1
- 3
src/utils/CMakeLists.txt View File

@@ -10,8 +10,6 @@ if (USING_PNG)
10 10
     set (UTIL_SRCS ${UTIL_SRCS} "png.cpp")
11 11
 endif (USING_PNG)
12 12
 
13
-# Include directory
14
-include_directories ("${PROJECT_SOURCE_DIR}/include")
15
-
16 13
 # Add library
17 14
 add_library (OpenRaider_utils ${UTIL_SRCS})
15
+

Loading…
Cancel
Save