4 * Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
27 * Manipulate command arguments.
30 struct args_entry
*args_find(struct args
*, u_char
);
32 RB_GENERATE(args_tree
, args_entry
, entry
, args_cmp
);
34 /* Arguments tree comparison function. */
36 args_cmp(struct args_entry
*a1
, struct args_entry
*a2
)
38 return (a1
->flag
- a2
->flag
);
41 /* Create an arguments set with no flags. */
43 args_create(int argc
, ...)
49 args
= xcalloc(1, sizeof *args
);
55 args
->argv
= xcalloc(argc
, sizeof *args
->argv
);
58 for (i
= 0; i
< argc
; i
++)
59 args
->argv
[i
] = xstrdup(va_arg(ap
, char *));
65 /* Find a flag in the arguments tree. */
67 args_find(struct args
*args
, u_char ch
)
69 struct args_entry entry
;
72 return (RB_FIND(args_tree
, &args
->tree
, &entry
));
75 /* Parse an argv and argc into a new argument set. */
77 args_parse(const char *template, int argc
, char **argv
)
83 args
= xcalloc(1, sizeof *args
);
88 while ((opt
= getopt(argc
, argv
, template)) != -1) {
91 if (opt
== '?' || (ptr
= strchr(template, opt
)) == NULL
) {
95 args_set(args
, opt
, optarg
);
101 args
->argv
= cmd_copy_argv(argc
, argv
);
106 /* Free an arguments set. */
108 args_free(struct args
*args
)
110 struct args_entry
*entry
;
111 struct args_entry
*entry1
;
113 cmd_free_argv(args
->argc
, args
->argv
);
115 RB_FOREACH_SAFE(entry
, args_tree
, &args
->tree
, entry1
) {
116 RB_REMOVE(args_tree
, &args
->tree
, entry
);
124 /* Print a set of arguments. */
126 args_print(struct args
*args
, char *buf
, size_t len
)
131 struct args_entry
*entry
;
133 /* There must be at least one byte at the start. */
138 /* Process the flags first. */
140 RB_FOREACH(entry
, args_tree
, &args
->tree
) {
141 if (entry
->value
!= NULL
)
144 if (off
== len
- 1) {
148 buf
[off
++] = entry
->flag
;
154 /* Then the flags with arguments. */
155 RB_FOREACH(entry
, args_tree
, &args
->tree
) {
156 if (entry
->value
== NULL
)
160 /* snprintf will have zero terminated. */
164 if (strchr(entry
->value
, ' ') != NULL
)
168 off
+= xsnprintf(buf
+ off
, len
- off
, "%s-%c %s%s%s",
169 off
!= 0 ? " " : "", entry
->flag
, quotes
, entry
->value
,
173 /* And finally the argument vector. */
174 for (i
= 0; i
< args
->argc
; i
++) {
176 /* snprintf will have zero terminated. */
180 if (strchr(args
->argv
[i
], ' ') != NULL
)
184 off
+= xsnprintf(buf
+ off
, len
- off
, "%s%s%s%s",
185 off
!= 0 ? " " : "", quotes
, args
->argv
[i
], quotes
);
191 /* Return if an argument is present. */
193 args_has(struct args
*args
, u_char ch
)
195 return (args_find(args
, ch
) == NULL
? 0 : 1);
198 /* Set argument value in the arguments tree. */
200 args_set(struct args
*args
, u_char ch
, const char *value
)
202 struct args_entry
*entry
;
204 /* Replace existing argument. */
205 if ((entry
= args_find(args
, ch
)) != NULL
) {
208 entry
->value
= xstrdup(value
);
214 entry
= xcalloc(1, sizeof *entry
);
217 entry
->value
= xstrdup(value
);
219 RB_INSERT(args_tree
, &args
->tree
, entry
);
222 /* Get argument value. Will be NULL if it isn't present. */
224 args_get(struct args
*args
, u_char ch
)
226 struct args_entry
*entry
;
228 if ((entry
= args_find(args
, ch
)) == NULL
)
230 return (entry
->value
);
233 /* Convert an argument value to a number. */
235 args_strtonum(struct args
*args
, u_char ch
, long long minval
, long long maxval
,
240 struct args_entry
*entry
;
242 if ((entry
= args_find(args
, ch
)) == NULL
) {
243 *cause
= xstrdup("missing");
247 ll
= strtonum(entry
->value
, minval
, maxval
, &errstr
);
248 if (errstr
!= NULL
) {
249 *cause
= xstrdup(errstr
);