version 1.4, 2012/07/10 11:53:01 |
version 1.5, 2013/05/31 12:19:34 |
|
|
|
|
#include <sys/types.h> |
#include <sys/types.h> |
|
|
#include <bitstring.h> |
|
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
|
|
#include "tmux.h" |
#include "tmux.h" |
|
|
|
/* |
|
* Manipulate command arguments. |
|
*/ |
|
|
|
struct args_entry *args_find(struct args *, u_char); |
|
|
|
RB_GENERATE(args_tree, args_entry, entry, args_cmp); |
|
|
|
/* Arguments tree comparison function. */ |
|
int |
|
args_cmp(struct args_entry *a1, struct args_entry *a2) |
|
{ |
|
return (a1->flag - a2->flag); |
|
} |
|
|
/* Create an arguments set with no flags. */ |
/* Create an arguments set with no flags. */ |
struct args * |
struct args * |
args_create(int argc, ...) |
args_create(int argc, ...) |
|
|
int i; |
int i; |
|
|
args = xcalloc(1, sizeof *args); |
args = xcalloc(1, sizeof *args); |
if ((args->flags = bit_alloc(SCHAR_MAX)) == NULL) |
|
fatal("bit_alloc failed"); |
|
|
|
args->argc = argc; |
args->argc = argc; |
if (argc == 0) |
if (argc == 0) |
|
|
return (args); |
return (args); |
} |
} |
|
|
|
/* Find a flag in the arguments tree. */ |
|
struct args_entry * |
|
args_find(struct args *args, u_char ch) |
|
{ |
|
struct args_entry entry; |
|
|
|
entry.flag = ch; |
|
return (RB_FIND(args_tree, &args->tree, &entry)); |
|
} |
|
|
/* Parse an argv and argc into a new argument set. */ |
/* Parse an argv and argc into a new argument set. */ |
struct args * |
struct args * |
args_parse(const char *template, int argc, char **argv) |
args_parse(const char *template, int argc, char **argv) |
|
|
int opt; |
int opt; |
|
|
args = xcalloc(1, sizeof *args); |
args = xcalloc(1, sizeof *args); |
if ((args->flags = bit_alloc(SCHAR_MAX)) == NULL) |
|
fatal("bit_alloc failed"); |
|
|
|
optreset = 1; |
optreset = 1; |
optind = 1; |
optind = 1; |
|
|
while ((opt = getopt(argc, argv, template)) != -1) { |
while ((opt = getopt(argc, argv, template)) != -1) { |
if (opt < 0 || opt >= SCHAR_MAX) |
if (opt < 0) |
continue; |
continue; |
if (opt == '?' || (ptr = strchr(template, opt)) == NULL) { |
if (opt == '?' || (ptr = strchr(template, opt)) == NULL) { |
free(args->flags); |
args_free(args); |
free(args); |
|
return (NULL); |
return (NULL); |
} |
} |
|
args_set(args, opt, optarg); |
bit_set(args->flags, opt); |
|
if (ptr[1] == ':') { |
|
free(args->values[opt]); |
|
args->values[opt] = xstrdup(optarg); |
|
} |
|
} |
} |
argc -= optind; |
argc -= optind; |
argv += optind; |
argv += optind; |
|
|
void |
void |
args_free(struct args *args) |
args_free(struct args *args) |
{ |
{ |
u_int i; |
struct args_entry *entry; |
|
struct args_entry *entry1; |
|
|
cmd_free_argv(args->argc, args->argv); |
cmd_free_argv(args->argc, args->argv); |
|
|
for (i = 0; i < SCHAR_MAX; i++) |
RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) { |
free(args->values[i]); |
RB_REMOVE(args_tree, &args->tree, entry); |
|
free(entry->value); |
|
free(entry); |
|
} |
|
|
free(args->flags); |
|
free(args); |
free(args); |
} |
} |
|
|
|
|
size_t |
size_t |
args_print(struct args *args, char *buf, size_t len) |
args_print(struct args *args, char *buf, size_t len) |
{ |
{ |
size_t off; |
size_t off; |
int i; |
int i; |
const char *quotes; |
const char *quotes; |
|
struct args_entry *entry; |
|
|
/* There must be at least one byte at the start. */ |
/* There must be at least one byte at the start. */ |
if (len == 0) |
if (len == 0) |
|
|
|
|
/* Process the flags first. */ |
/* Process the flags first. */ |
buf[off++] = '-'; |
buf[off++] = '-'; |
for (i = 0; i < SCHAR_MAX; i++) { |
RB_FOREACH(entry, args_tree, &args->tree) { |
if (!bit_test(args->flags, i) || args->values[i] != NULL) |
if (entry->value != NULL) |
continue; |
continue; |
|
|
if (off == len - 1) { |
if (off == len - 1) { |
buf[off] = '\0'; |
buf[off] = '\0'; |
return (len); |
return (len); |
} |
} |
buf[off++] = i; |
buf[off++] = entry->flag; |
buf[off] = '\0'; |
buf[off] = '\0'; |
} |
} |
if (off == 1) |
if (off == 1) |
buf[--off] = '\0'; |
buf[--off] = '\0'; |
|
|
/* Then the flags with arguments. */ |
/* Then the flags with arguments. */ |
for (i = 0; i < SCHAR_MAX; i++) { |
RB_FOREACH(entry, args_tree, &args->tree) { |
if (!bit_test(args->flags, i) || args->values[i] == NULL) |
if (entry->value == NULL) |
continue; |
continue; |
|
|
if (off >= len) { |
if (off >= len) { |
|
|
return (len); |
return (len); |
} |
} |
|
|
if (strchr(args->values[i], ' ') != NULL) |
if (strchr(entry->value, ' ') != NULL) |
quotes = "\""; |
quotes = "\""; |
else |
else |
quotes = ""; |
quotes = ""; |
off += xsnprintf(buf + off, len - off, "%s-%c %s%s%s", |
off += xsnprintf(buf + off, len - off, "%s-%c %s%s%s", |
off != 0 ? " " : "", i, quotes, args->values[i], quotes); |
off != 0 ? " " : "", entry->flag, quotes, entry->value, |
|
quotes); |
} |
} |
|
|
/* And finally the argument vector. */ |
/* And finally the argument vector. */ |
|
|
int |
int |
args_has(struct args *args, u_char ch) |
args_has(struct args *args, u_char ch) |
{ |
{ |
return (bit_test(args->flags, ch)); |
return (args_find(args, ch) == NULL ? 0 : 1); |
} |
} |
|
|
/* Set argument value. */ |
/* 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 *value) |
{ |
{ |
free(args->values[ch]); |
struct args_entry *entry; |
|
|
|
/* Replace existing argument. */ |
|
if ((entry = args_find(args, ch)) != NULL) { |
|
free(entry->value); |
|
if (value != NULL) |
|
entry->value = xstrdup(value); |
|
else |
|
entry->value = NULL; |
|
return; |
|
} |
|
|
|
entry = xcalloc(1, sizeof *entry); |
|
entry->flag = ch; |
if (value != NULL) |
if (value != NULL) |
args->values[ch] = xstrdup(value); |
entry->value = xstrdup(value); |
else |
|
args->values[ch] = NULL; |
RB_INSERT(args_tree, &args->tree, entry); |
bit_set(args->flags, ch); |
|
} |
} |
|
|
/* Get argument value. Will be NULL if it isn't present. */ |
/* Get argument value. Will be NULL if it isn't present. */ |
const char * |
const char * |
args_get(struct args *args, u_char ch) |
args_get(struct args *args, u_char ch) |
{ |
{ |
return (args->values[ch]); |
struct args_entry *entry; |
|
|
|
if ((entry = args_find(args, ch)) == NULL) |
|
return (NULL); |
|
return (entry->value); |
} |
} |
|
|
/* Convert an argument value to a number. */ |
/* Convert an argument value to a number. */ |
long long |
long long |
args_strtonum(struct args *args, |
args_strtonum(struct args *args, u_char ch, long long minval, long long maxval, |
u_char ch, long long minval, long long maxval, char **cause) |
char **cause) |
{ |
{ |
const char *errstr; |
const char *errstr; |
long long ll; |
long long ll; |
|
struct args_entry *entry; |
|
|
if (!args_has(args, ch)) { |
if ((entry = args_find(args, ch)) == NULL) { |
*cause = xstrdup("missing"); |
*cause = xstrdup("missing"); |
return (0); |
return (0); |
} |
} |
|
|
ll = strtonum(args->values[ch], minval, maxval, &errstr); |
ll = strtonum(entry->value, minval, maxval, &errstr); |
if (errstr != NULL) { |
if (errstr != NULL) { |
*cause = xstrdup(errstr); |
*cause = xstrdup(errstr); |
return (0); |
return (0); |