version 1.20, 2017/08/23 09:14:21 |
version 1.21, 2019/04/28 20:05:50 |
|
|
* Manipulate command arguments. |
* Manipulate command arguments. |
*/ |
*/ |
|
|
|
struct args_value { |
|
char *value; |
|
TAILQ_ENTRY(args_value) entry; |
|
}; |
|
TAILQ_HEAD(args_values, args_value); |
|
|
struct args_entry { |
struct args_entry { |
u_char flag; |
u_char flag; |
char *value; |
struct args_values values; |
RB_ENTRY(args_entry) entry; |
RB_ENTRY(args_entry) entry; |
}; |
}; |
|
|
|
|
{ |
{ |
struct args_entry *entry; |
struct args_entry *entry; |
struct args_entry *entry1; |
struct args_entry *entry1; |
|
struct args_value *value; |
|
struct args_value *value1; |
|
|
cmd_free_argv(args->argc, args->argv); |
cmd_free_argv(args->argc, args->argv); |
|
|
RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) { |
RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) { |
RB_REMOVE(args_tree, &args->tree, entry); |
RB_REMOVE(args_tree, &args->tree, entry); |
free(entry->value); |
TAILQ_FOREACH_SAFE(value, &entry->values, entry, value1) { |
|
TAILQ_REMOVE(&entry->values, value, entry); |
|
free(value->value); |
|
free(value); |
|
} |
free(entry); |
free(entry); |
} |
} |
|
|
|
|
free(s); |
free(s); |
} |
} |
|
|
|
/* Add value to string. */ |
|
static void |
|
args_print_add_value(char **buf, size_t *len, struct args_entry *entry, |
|
struct args_value *value) |
|
{ |
|
static const char quoted[] = " #\"';$"; |
|
char *escaped; |
|
int flags; |
|
|
|
if (**buf != '\0') |
|
args_print_add(buf, len, " -%c ", entry->flag); |
|
else |
|
args_print_add(buf, len, "-%c ", entry->flag); |
|
|
|
flags = VIS_OCTAL|VIS_TAB|VIS_NL; |
|
if (value->value[strcspn(value->value, quoted)] != '\0') |
|
flags |= VIS_DQ; |
|
utf8_stravis(&escaped, value->value, flags); |
|
if (flags & VIS_DQ) |
|
args_print_add(buf, len, "\"%s\"", escaped); |
|
else |
|
args_print_add(buf, len, "%s", escaped); |
|
free(escaped); |
|
} |
|
|
|
/* Add argument to string. */ |
|
static void |
|
args_print_add_argument(char **buf, size_t *len, const char *argument) |
|
{ |
|
static const char quoted[] = " #\"';$"; |
|
char *escaped; |
|
int flags; |
|
|
|
if (**buf != '\0') |
|
args_print_add(buf, len, " "); |
|
|
|
flags = VIS_OCTAL|VIS_TAB|VIS_NL; |
|
if (argument[strcspn(argument, quoted)] != '\0') |
|
flags |= VIS_DQ; |
|
utf8_stravis(&escaped, argument, flags); |
|
if (flags & VIS_DQ) |
|
args_print_add(buf, len, "\"%s\"", escaped); |
|
else |
|
args_print_add(buf, len, "%s", escaped); |
|
free(escaped); |
|
} |
|
|
/* Print a set of arguments. */ |
/* Print a set of arguments. */ |
char * |
char * |
args_print(struct args *args) |
args_print(struct args *args) |
{ |
{ |
size_t len; |
size_t len; |
char *buf, *escaped; |
char *buf; |
int i, flags; |
int i; |
struct args_entry *entry; |
struct args_entry *entry; |
static const char quoted[] = " #\"';$"; |
struct args_value *value; |
|
|
len = 1; |
len = 1; |
buf = xcalloc(1, len); |
buf = xcalloc(1, len); |
|
|
/* Process the flags first. */ |
/* Process the flags first. */ |
RB_FOREACH(entry, args_tree, &args->tree) { |
RB_FOREACH(entry, args_tree, &args->tree) { |
if (entry->value != NULL) |
if (!TAILQ_EMPTY(&entry->values)) |
continue; |
continue; |
|
|
if (*buf == '\0') |
if (*buf == '\0') |
|
|
|
|
/* Then the flags with arguments. */ |
/* Then the flags with arguments. */ |
RB_FOREACH(entry, args_tree, &args->tree) { |
RB_FOREACH(entry, args_tree, &args->tree) { |
if (entry->value == NULL) |
TAILQ_FOREACH(value, &entry->values, entry) |
continue; |
args_print_add_value(&buf, &len, entry, value); |
|
|
if (*buf != '\0') |
|
args_print_add(&buf, &len, " -%c ", entry->flag); |
|
else |
|
args_print_add(&buf, &len, "-%c ", entry->flag); |
|
|
|
flags = VIS_OCTAL|VIS_TAB|VIS_NL; |
|
if (entry->value[strcspn(entry->value, quoted)] != '\0') |
|
flags |= VIS_DQ; |
|
utf8_stravis(&escaped, entry->value, flags); |
|
if (flags & VIS_DQ) |
|
args_print_add(&buf, &len, "\"%s\"", escaped); |
|
else |
|
args_print_add(&buf, &len, "%s", escaped); |
|
free(escaped); |
|
} |
} |
|
|
/* And finally the argument vector. */ |
/* And finally the argument vector. */ |
for (i = 0; i < args->argc; i++) { |
for (i = 0; i < args->argc; i++) |
if (*buf != '\0') |
args_print_add_argument(&buf, &len, args->argv[i]); |
args_print_add(&buf, &len, " "); |
|
|
|
flags = VIS_OCTAL|VIS_TAB|VIS_NL; |
|
if (args->argv[i][strcspn(args->argv[i], quoted)] != '\0') |
|
flags |= VIS_DQ; |
|
utf8_stravis(&escaped, args->argv[i], flags); |
|
if (flags & VIS_DQ) |
|
args_print_add(&buf, &len, "\"%s\"", escaped); |
|
else |
|
args_print_add(&buf, &len, "%s", escaped); |
|
free(escaped); |
|
} |
|
|
|
return (buf); |
return (buf); |
} |
} |
|
|
|
|
|
|
/* Set argument value in the arguments tree. */ |
/* Set argument value in the arguments tree. */ |
void |
void |
args_set(struct args *args, u_char ch, const char *value) |
args_set(struct args *args, u_char ch, const char *s) |
{ |
{ |
struct args_entry *entry; |
struct args_entry *entry; |
|
struct args_value *value; |
|
|
/* Replace existing argument. */ |
entry = args_find(args, ch); |
if ((entry = args_find(args, ch)) != NULL) { |
if (entry == NULL) { |
free(entry->value); |
|
entry->value = NULL; |
|
} else { |
|
entry = xcalloc(1, sizeof *entry); |
entry = xcalloc(1, sizeof *entry); |
entry->flag = ch; |
entry->flag = ch; |
|
TAILQ_INIT(&entry->values); |
RB_INSERT(args_tree, &args->tree, entry); |
RB_INSERT(args_tree, &args->tree, entry); |
} |
} |
|
|
if (value != NULL) |
if (s != NULL) { |
entry->value = xstrdup(value); |
value = xcalloc(1, sizeof *value); |
|
value->value = xstrdup(s); |
|
TAILQ_INSERT_TAIL(&entry->values, value, entry); |
|
} |
} |
} |
|
|
/* Get argument value. Will be NULL if it isn't present. */ |
/* Get argument value. Will be NULL if it isn't present. */ |
|
|
|
|
if ((entry = args_find(args, ch)) == NULL) |
if ((entry = args_find(args, ch)) == NULL) |
return (NULL); |
return (NULL); |
return (entry->value); |
return (TAILQ_LAST(&entry->values, args_values)->value); |
} |
} |
|
|
|
/* Get first value in argument. */ |
|
const char * |
|
args_first_value(struct args *args, u_char ch, struct args_value **value) |
|
{ |
|
struct args_entry *entry; |
|
|
|
if ((entry = args_find(args, ch)) == NULL) |
|
return (NULL); |
|
|
|
*value = TAILQ_FIRST(&entry->values); |
|
if (*value == NULL) |
|
return (NULL); |
|
return ((*value)->value); |
|
} |
|
|
|
/* Get next value in argument. */ |
|
const char * |
|
args_next_value(struct args_value **value) |
|
{ |
|
if (*value == NULL) |
|
return (NULL); |
|
*value = TAILQ_NEXT(*value, entry); |
|
if (*value == NULL) |
|
return (NULL); |
|
return ((*value)->value); |
|
} |
|
|
/* Convert an argument value to a number. */ |
/* Convert an argument value to a number. */ |
long long |
long long |
args_strtonum(struct args *args, u_char ch, long long minval, long long maxval, |
args_strtonum(struct args *args, u_char ch, long long minval, long long maxval, |
|
|
const char *errstr; |
const char *errstr; |
long long ll; |
long long ll; |
struct args_entry *entry; |
struct args_entry *entry; |
|
struct args_value *value; |
|
|
if ((entry = args_find(args, ch)) == NULL) { |
if ((entry = args_find(args, ch)) == NULL) { |
*cause = xstrdup("missing"); |
*cause = xstrdup("missing"); |
return (0); |
return (0); |
} |
} |
|
value = TAILQ_LAST(&entry->values, args_values); |
|
|
ll = strtonum(entry->value, minval, maxval, &errstr); |
ll = strtonum(value->value, minval, maxval, &errstr); |
if (errstr != NULL) { |
if (errstr != NULL) { |
*cause = xstrdup(errstr); |
*cause = xstrdup(errstr); |
return (0); |
return (0); |