4 * Copyright (c) 2008 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>
26 int cmd_getopt(int, char **, const char *, const char *);
27 int cmd_parse_flags(int, const char *, uint64_t *);
28 size_t cmd_print_flags(char *, size_t, size_t, uint64_t);
29 int cmd_fill_argument(int, char **, char **, int, char **);
32 cmd_prarg(char *buf
, size_t len
, const char *prefix
, char *arg
)
34 if (strchr(arg
, ' ') != NULL
)
35 return (xsnprintf(buf
, len
, "%s\"%s\"", prefix
, arg
));
36 return (xsnprintf(buf
, len
, "%s%s", prefix
, arg
));
39 /* Append two flag strings together and call getopt. */
41 cmd_getopt(int argc
, char **argv
, const char *flagstr
, const char *chflagstr
)
45 if (strlcpy(tmp
, flagstr
, sizeof tmp
) >= sizeof tmp
)
46 fatalx("strlcpy overflow");
47 if (strlcat(tmp
, chflagstr
, sizeof tmp
) >= sizeof tmp
)
48 fatalx("strlcat overflow");
49 return (getopt(argc
, argv
, tmp
));
52 /* Return if flag character is set. */
54 cmd_check_flag(uint64_t chflags
, int flag
)
56 if (flag
>= 'A' && flag
<= 'Z')
57 flag
= 26 + flag
- 'A';
58 else if (flag
>= 'a' && flag
<= 'z')
62 return ((chflags
& (1ULL << flag
)) != 0);
65 /* Set flag character. */
67 cmd_set_flag(uint64_t *chflags
, int flag
)
69 if (flag
>= 'A' && flag
<= 'Z')
70 flag
= 26 + flag
- 'A';
71 else if (flag
>= 'a' && flag
<= 'z')
75 (*chflags
) |= (1ULL << flag
);
78 /* If this option is expected, set it in chflags, otherwise return -1. */
80 cmd_parse_flags(int opt
, const char *chflagstr
, uint64_t *chflags
)
82 if (strchr(chflagstr
, opt
) == NULL
)
84 cmd_set_flag(chflags
, opt
);
88 /* Print the flags present in chflags. */
90 cmd_print_flags(char *buf
, size_t len
, size_t off
, uint64_t chflags
)
97 off
+= xsnprintf(buf
+ off
, len
- off
, " -");
99 for (ch
= 0; ch
< 26; ch
++) {
100 if (cmd_check_flag(chflags
, 'a' + ch
))
101 off
+= xsnprintf(buf
+ off
, len
- off
, "%c", 'a' + ch
);
102 if (cmd_check_flag(chflags
, 'A' + ch
))
103 off
+= xsnprintf(buf
+ off
, len
- off
, "%c", 'A' + ch
);
109 cmd_fill_argument(int flags
, char **arg
, char **arg2
, int argc
, char **argv
)
114 if (flags
& CMD_ARG1
) {
117 *arg
= xstrdup(argv
[0]);
121 if (flags
& CMD_ARG01
) {
122 if (argc
!= 0 && argc
!= 1)
125 *arg
= xstrdup(argv
[0]);
129 if (flags
& CMD_ARG2
) {
132 *arg
= xstrdup(argv
[0]);
133 *arg2
= xstrdup(argv
[1]);
137 if (flags
& CMD_ARG12
) {
138 if (argc
!= 1 && argc
!= 2)
140 *arg
= xstrdup(argv
[0]);
142 *arg2
= xstrdup(argv
[1]);
153 cmd_target_init(struct cmd
*self
, unused
int key
)
155 struct cmd_target_data
*data
;
157 self
->data
= data
= xmalloc(sizeof *data
);
165 cmd_target_parse(struct cmd
*self
, int argc
, char **argv
, char **cause
)
167 struct cmd_target_data
*data
;
168 const struct cmd_entry
*entry
= self
->entry
;
171 /* Don't use the entry version since it may be dependent on key. */
172 cmd_target_init(self
, 0);
175 while ((opt
= cmd_getopt(argc
, argv
, "t:", entry
->chflags
)) != -1) {
176 if (cmd_parse_flags(opt
, entry
->chflags
, &data
->chflags
) == 0)
180 if (data
->target
== NULL
)
181 data
->target
= xstrdup(optarg
);
190 if (cmd_fill_argument(
191 self
->entry
->flags
, &data
->arg
, &data
->arg2
, argc
, argv
) != 0)
196 xasprintf(cause
, "usage: %s %s", self
->entry
->name
, self
->entry
->usage
);
198 self
->entry
->free(self
);
203 cmd_target_free(struct cmd
*self
)
205 struct cmd_target_data
*data
= self
->data
;
207 if (data
->target
!= NULL
)
209 if (data
->arg
!= NULL
)
211 if (data
->arg2
!= NULL
)
217 cmd_target_print(struct cmd
*self
, char *buf
, size_t len
)
219 struct cmd_target_data
*data
= self
->data
;
222 off
+= xsnprintf(buf
, len
, "%s", self
->entry
->name
);
225 off
+= cmd_print_flags(buf
, len
, off
, data
->chflags
);
226 if (off
< len
&& data
->target
!= NULL
)
227 off
+= cmd_prarg(buf
+ off
, len
- off
, " -t ", data
->target
);
228 if (off
< len
&& data
->arg
!= NULL
)
229 off
+= cmd_prarg(buf
+ off
, len
- off
, " ", data
->arg
);
230 if (off
< len
&& data
->arg2
!= NULL
)
231 off
+= cmd_prarg(buf
+ off
, len
- off
, " ", data
->arg2
);
237 cmd_srcdst_init(struct cmd
*self
, unused
int key
)
239 struct cmd_srcdst_data
*data
;
241 self
->data
= data
= xmalloc(sizeof *data
);
250 cmd_srcdst_parse(struct cmd
*self
, int argc
, char **argv
, char **cause
)
252 struct cmd_srcdst_data
*data
;
253 const struct cmd_entry
*entry
= self
->entry
;
256 cmd_srcdst_init(self
, 0);
259 while ((opt
= cmd_getopt(argc
, argv
, "s:t:", entry
->chflags
)) != -1) {
260 if (cmd_parse_flags(opt
, entry
->chflags
, &data
->chflags
) == 0)
264 if (data
->src
== NULL
)
265 data
->src
= xstrdup(optarg
);
268 if (data
->dst
== NULL
)
269 data
->dst
= xstrdup(optarg
);
278 if (cmd_fill_argument(
279 self
->entry
->flags
, &data
->arg
, &data
->arg2
, argc
, argv
) != 0)
284 xasprintf(cause
, "usage: %s %s", self
->entry
->name
, self
->entry
->usage
);
286 self
->entry
->free(self
);
291 cmd_srcdst_free(struct cmd
*self
)
293 struct cmd_srcdst_data
*data
= self
->data
;
295 if (data
->src
!= NULL
)
297 if (data
->dst
!= NULL
)
299 if (data
->arg
!= NULL
)
301 if (data
->arg2
!= NULL
)
307 cmd_srcdst_print(struct cmd
*self
, char *buf
, size_t len
)
309 struct cmd_srcdst_data
*data
= self
->data
;
312 off
+= xsnprintf(buf
, len
, "%s", self
->entry
->name
);
315 off
+= cmd_print_flags(buf
, len
, off
, data
->chflags
);
316 if (off
< len
&& data
->src
!= NULL
)
317 off
+= xsnprintf(buf
+ off
, len
- off
, " -s %s", data
->src
);
318 if (off
< len
&& data
->dst
!= NULL
)
319 off
+= xsnprintf(buf
+ off
, len
- off
, " -t %s", data
->dst
);
320 if (off
< len
&& data
->arg
!= NULL
)
321 off
+= cmd_prarg(buf
+ off
, len
- off
, " ", data
->arg
);
322 if (off
< len
&& data
->arg2
!= NULL
)
323 off
+= cmd_prarg(buf
+ off
, len
- off
, " ", data
->arg2
);
329 cmd_buffer_init(struct cmd
*self
, unused
int key
)
331 struct cmd_buffer_data
*data
;
333 self
->data
= data
= xmalloc(sizeof *data
);
342 cmd_buffer_parse(struct cmd
*self
, int argc
, char **argv
, char **cause
)
344 struct cmd_buffer_data
*data
;
345 const struct cmd_entry
*entry
= self
->entry
;
349 cmd_buffer_init(self
, 0);
352 while ((opt
= cmd_getopt(argc
, argv
, "b:t:", entry
->chflags
)) != -1) {
353 if (cmd_parse_flags(opt
, entry
->chflags
, &data
->chflags
) == 0)
357 if (data
->buffer
== -1) {
358 n
= strtonum(optarg
, 0, INT_MAX
, &errstr
);
359 if (errstr
!= NULL
) {
360 xasprintf(cause
, "buffer %s", errstr
);
367 if (data
->target
== NULL
)
368 data
->target
= xstrdup(optarg
);
377 if (cmd_fill_argument(
378 self
->entry
->flags
, &data
->arg
, &data
->arg2
, argc
, argv
) != 0)
383 xasprintf(cause
, "usage: %s %s", self
->entry
->name
, self
->entry
->usage
);
386 self
->entry
->free(self
);
391 cmd_buffer_free(struct cmd
*self
)
393 struct cmd_buffer_data
*data
= self
->data
;
395 if (data
->target
!= NULL
)
397 if (data
->arg
!= NULL
)
399 if (data
->arg2
!= NULL
)
405 cmd_buffer_print(struct cmd
*self
, char *buf
, size_t len
)
407 struct cmd_buffer_data
*data
= self
->data
;
410 off
+= xsnprintf(buf
, len
, "%s", self
->entry
->name
);
413 off
+= cmd_print_flags(buf
, len
, off
, data
->chflags
);
414 if (off
< len
&& data
->buffer
!= -1)
415 off
+= xsnprintf(buf
+ off
, len
- off
, " -b %d", data
->buffer
);
416 if (off
< len
&& data
->target
!= NULL
)
417 off
+= cmd_prarg(buf
+ off
, len
- off
, " -t ", data
->target
);
418 if (off
< len
&& data
->arg
!= NULL
)
419 off
+= cmd_prarg(buf
+ off
, len
- off
, " ", data
->arg
);
420 if (off
< len
&& data
->arg2
!= NULL
)
421 off
+= cmd_prarg(buf
+ off
, len
- off
, " ", data
->arg2
);