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>
28 * Manipulate command arguments.
31 struct args_entry
*args_find(struct args
*, u_char
);
33 RB_GENERATE(args_tree
, args_entry
, entry
, args_cmp
);
35 /* Arguments tree comparison function. */
37 args_cmp(struct args_entry
*a1
, struct args_entry
*a2
)
39 return (a1
->flag
- a2
->flag
);
42 /* Create an arguments set with no flags. */
44 args_create(int argc
, ...)
50 args
= xcalloc(1, sizeof *args
);
56 args
->argv
= xcalloc(argc
, sizeof *args
->argv
);
59 for (i
= 0; i
< argc
; i
++)
60 args
->argv
[i
] = xstrdup(va_arg(ap
, char *));
66 /* Find a flag in the arguments tree. */
68 args_find(struct args
*args
, u_char ch
)
70 struct args_entry entry
;
73 return (RB_FIND(args_tree
, &args
->tree
, &entry
));
76 /* Parse an argv and argc into a new argument set. */
78 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
== '?' || 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
) {
209 entry
= xcalloc(1, sizeof *entry
);
211 RB_INSERT(args_tree
, &args
->tree
, entry
);
215 entry
->value
= xstrdup(value
);
218 /* Get argument value. Will be NULL if it isn't present. */
220 args_get(struct args
*args
, u_char ch
)
222 struct args_entry
*entry
;
224 if ((entry
= args_find(args
, ch
)) == NULL
)
226 return (entry
->value
);
229 /* Convert an argument value to a number. */
231 args_strtonum(struct args
*args
, u_char ch
, long long minval
, long long maxval
,
236 struct args_entry
*entry
;
238 if ((entry
= args_find(args
, ch
)) == NULL
) {
239 *cause
= xstrdup("missing");
243 ll
= strtonum(entry
->value
, minval
, maxval
, &errstr
);
244 if (errstr
!= NULL
) {
245 *cause
= xstrdup(errstr
);