1 /* =========================================================================
2 zargs - Platform independent command line argument parsing helpers
3
4 Copyright (c) the Contributors as noted in the AUTHORS file.
5 This file is part of CZMQ, the high-level C binding for 0MQ:
6 http://czmq.zeromq.org.
7
8 This Source Code Form is subject to the terms of the Mozilla Public
9 License, v. 2.0. If a copy of the MPL was not distributed with this
10 file, You can obtain one at http://mozilla.org/MPL/2.0/.
11 =========================================================================
12 */
13
14 /*
15 @header
16 zargs - Platform independent command line argument parsing helpers
17
18 Platform independent command line argument parsing helpers
19
20 There are two kind of elements provided by this class
21 foo --named-parameter --parameter with_value positional arguments -a gain-parameter
22 zargs keeps poision only for arguments, parameters are to be accessed like hash.
23
24 It DOES:
25 * provide easy to use CLASS compatible API for accessing argv
26 * is platform independent
27 * provide getopt_long style -- argument, which delimits parameters from arguments
28 * makes parameters positon independent
29
30 It does NOT
31 * change argv
32 * provide a "declarative" way to define command line interface
33
34 In future it SHALL
35 * hide several formats of command line to one (-Idir, --include=dir,
36 --include dir are the same from API pov)
37 @discuss
38 @end
39 */
40
41 #include "czmq_classes.h"
42
43 // Structure of our class
44 static char *ZARG_PARAM_EMPTY = "";
45
46 struct _zargs_t {
47 char *progname; // program name aka argv [0]
48 zlist_t *arguments; // positional arguments
49 zhash_t *parameters; // --named parameters
50 };
51
52
53 // --------------------------------------------------------------------------
54 // Create a new zargs
55
56 zargs_t *
zargs_new(int argc,char ** argv)57 zargs_new (int argc, char **argv)
58 {
59 assert (argc > 0);
60 assert (argv);
61 zargs_t *self = (zargs_t *) zmalloc (sizeof (zargs_t));
62 assert (self);
63 // Initialize class properties here
64 self->progname = argv [0];
65 assert (self->progname);
66 self->arguments = zlist_new ();
67 assert (self->arguments);
68 self->parameters = zhash_new ();
69 assert (self->parameters);
70
71 if (argc == 1)
72 return self;
73
74 int idx = 1;
75 bool params_only = false;
76 while (argv [idx]) {
77 if (params_only || argv [idx][0] != '-')
78 zlist_append (self->arguments, argv [idx]);
79 else {
80 if (streq (argv [idx], "--")) {
81 params_only = true;
82 idx ++;
83 continue;
84 }
85 else
86 if (argv [idx+1] && argv [idx+1][0] != '-') {
87 zhash_insert (self->parameters, argv [idx], argv [idx+1]);
88 idx ++;
89 }
90 else {
91 zhash_insert (self->parameters, argv [idx], ZARG_PARAM_EMPTY);
92 }
93 }
94 idx ++;
95 }
96
97 return self;
98 }
99
100 // --------------------------------------------------------------------------
101 // Destroy the zargs
102
103 void
zargs_destroy(zargs_t ** self_p)104 zargs_destroy (zargs_t **self_p)
105 {
106 assert (self_p);
107 if (*self_p) {
108 zargs_t *self = *self_p;
109 // Free class properties here
110 // Free object itself
111 zlist_destroy (&self->arguments);
112 zhash_destroy (&self->parameters);
113 free (self);
114 *self_p = NULL;
115 }
116 }
117
118 // --------------------------------------------------------------------------
119 // Return the program name (argv[0])
120
121 const char *
zargs_progname(zargs_t * self)122 zargs_progname (zargs_t *self) {
123 assert (self);
124 return self->progname;
125 }
126
127 // --------------------------------------------------------------------------
128 // Return the number of command line arguments
129
130 size_t
zargs_arguments(zargs_t * self)131 zargs_arguments (zargs_t *self) {
132 assert (self);
133 return zlist_size (self->arguments);
134 }
135
136 // --------------------------------------------------------------------------
137 // Return first command line argument
138
139 const char *
zargs_first(zargs_t * self)140 zargs_first (zargs_t *self) {
141 assert (self);
142 return (const char*) zlist_first (self->arguments);
143 }
144
145 // --------------------------------------------------------------------------
146 // Return next command line argument
147
148 const char *
zargs_next(zargs_t * self)149 zargs_next (zargs_t *self) {
150 assert (self);
151 return (const char*) zlist_next (self->arguments);
152 }
153
154 // --------------------------------------------------------------------------
155 // Return first command line parameter value
156
157 const char *
zargs_param_first(zargs_t * self)158 zargs_param_first (zargs_t *self) {
159 assert (self);
160 return (const char*) zhash_first (self->parameters);
161 }
162
163 // --------------------------------------------------------------------------
164 // Return next command line parameter value
165
166 const char *
zargs_param_next(zargs_t * self)167 zargs_param_next (zargs_t *self) {
168 assert (self);
169 return (const char*) zhash_next (self->parameters);
170 }
171
172 // --------------------------------------------------------------------------
173 // Return current command line parameter name
174
175 const char *
zargs_param_name(zargs_t * self)176 zargs_param_name (zargs_t *self) {
177 assert (self);
178 return (const char*) zhash_cursor (self->parameters);
179 }
180
181 // --------------------------------------------------------------------------
182 // Return value of named parameter, NULL if no given parameter has
183 // been specified, or special value for wich zargs_param_empty ()
184 // returns true.
185
186 const char *
zargs_param_lookup(zargs_t * self,const char * name)187 zargs_param_lookup (zargs_t *self, const char *name) {
188 assert (self);
189 assert (name);
190 const char *ret = NULL;
191 ret = (const char*) zhash_lookup (self->parameters, name);
192 return ret;
193 }
194
195 // --------------------------------------------------------------------------
196 // Return value of named parameter(s), NULL if no given parameter has
197 // been specified, or special value for wich zargs_param_empty ()
198 // returns true.
199
200 const char *
zargs_param_lookupx(zargs_t * self,const char * name,...)201 zargs_param_lookupx (zargs_t *self, const char *name, ...) {
202 assert (self);
203 const char *ret = NULL;
204 va_list args;
205 va_start (args, name);
206 while (name) {
207 ret = zargs_param_lookup (self, name);
208 if (ret)
209 break;
210 name = va_arg (args, const char *);
211 }
212 va_end (args);
213 return ret;
214 }
215
216 // --------------------------------------------------------------------------
217
218 bool
zargs_has_help(zargs_t * self)219 zargs_has_help (zargs_t *self) {
220 return zargs_param_lookupx (self, "--help", "-h", NULL) != NULL;
221 }
222
223 // --------------------------------------------------------------------------
224 // check if argument had a value or not
225
226 bool
zargs_param_empty(const char * arg)227 zargs_param_empty (const char* arg) {
228 return arg && arg == ZARG_PARAM_EMPTY;
229 }
230
231 // --------------------------------------------------------------------------
232 // Print the zargs instance
233
234 void
zargs_print(zargs_t * self)235 zargs_print (zargs_t *self) {
236 assert (self);
237 fprintf (stderr, "%s ", self->progname);
238 for (const char *pvalue = zargs_param_first (self);
239 pvalue != NULL;
240 pvalue = zargs_param_next (self)) {
241 const char *pname = zargs_param_name (self);
242 if (pvalue == ZARG_PARAM_EMPTY)
243 fprintf (stderr, "%s : None ", pname);
244 else
245 fprintf (stderr, "%s : %s ", pname, pvalue);
246 fprintf (stderr, ", ");
247 }
248 for (const char *arg = zargs_first (self);
249 arg != NULL;
250 arg = zargs_next (self)) {
251 fprintf (stderr, "%s ", arg);
252 }
253 fputs ("", stderr);
254 }
255 // --------------------------------------------------------------------------
256 // Self test of this class
257
258 void
zargs_test(bool verbose)259 zargs_test (bool verbose)
260 {
261 zsys_init ();
262 printf (" * zargs: ");
263
264 // @selftest
265 // Simple create/destroy test
266
267 char *argv1[] = {"progname", "--named1", "-n1", "val1", "positional1", "--with", "value", "--with2=value2", "-W3value3", "--", "--thisis", "considered", "positional", NULL};
268
269 zargs_t *self = zargs_new (13, argv1);
270 assert (self);
271
272 assert (streq (zargs_progname (self), "progname"));
273 assert (streq (zargs_first (self), "positional1"));
274 assert (streq (zargs_next (self), "--thisis"));
275 assert (streq (zargs_next (self), "considered"));
276 assert (streq (zargs_next (self), "positional"));
277 assert (!zargs_next (self));
278
279 assert (zargs_param_empty (zargs_param_lookup (self, "--named1")));
280 assert (!zargs_param_empty (zargs_param_lookup (self, "-n1")));
281 assert (streq (zargs_param_lookupx (self, "--not at all", "-n1", NULL), "val1"));
282 // TODO: this does not look like an easy hack w/o allocating extra memory
283 // ???
284 //assert (streq (zargs_param_lookup (self, "--with", NULL), "value2"));
285
286 zargs_destroy (&self);
287 // @end
288 printf ("OK\n");
289 }
290