1 /* $OpenBSD$ */ 2 3 /* 4 * Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com> 5 * 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. 9 * 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. 17 */ 18 19 #include <sys/types.h> 20 21 #include <stdlib.h> 22 #include <string.h> 23 #include <unistd.h> 24 25 #include "tmux.h" 26 27 /* 28 * Manipulate command arguments. 29 */ 30 31 struct args_entry { 32 u_char flag; 33 char *value; 34 RB_ENTRY(args_entry) entry; 35 }; 36 37 struct args_entry *args_find(struct args *, u_char); 38 39 RB_GENERATE(args_tree, args_entry, entry, args_cmp); 40 41 /* Arguments tree comparison function. */ 42 int 43 args_cmp(struct args_entry *a1, struct args_entry *a2) 44 { 45 return (a1->flag - a2->flag); 46 } 47 48 /* Create an arguments set with no flags. */ 49 struct args * 50 args_create(int argc, ...) 51 { 52 struct args *args; 53 va_list ap; 54 int i; 55 56 args = xcalloc(1, sizeof *args); 57 58 args->argc = argc; 59 if (argc == 0) 60 args->argv = NULL; 61 else 62 args->argv = xcalloc(argc, sizeof *args->argv); 63 64 va_start(ap, argc); 65 for (i = 0; i < argc; i++) 66 args->argv[i] = xstrdup(va_arg(ap, char *)); 67 va_end(ap); 68 69 return (args); 70 } 71 72 /* Find a flag in the arguments tree. */ 73 struct args_entry * 74 args_find(struct args *args, u_char ch) 75 { 76 struct args_entry entry; 77 78 entry.flag = ch; 79 return (RB_FIND(args_tree, &args->tree, &entry)); 80 } 81 82 /* Parse an argv and argc into a new argument set. */ 83 struct args * 84 args_parse(const char *template, int argc, char **argv) 85 { 86 struct args *args; 87 int opt; 88 89 args = xcalloc(1, sizeof *args); 90 91 optreset = 1; 92 optind = 1; 93 94 while ((opt = getopt(argc, argv, template)) != -1) { 95 if (opt < 0) 96 continue; 97 if (opt == '?' || strchr(template, opt) == NULL) { 98 args_free(args); 99 return (NULL); 100 } 101 args_set(args, opt, optarg); 102 } 103 argc -= optind; 104 argv += optind; 105 106 args->argc = argc; 107 args->argv = cmd_copy_argv(argc, argv); 108 109 return (args); 110 } 111 112 /* Free an arguments set. */ 113 void 114 args_free(struct args *args) 115 { 116 struct args_entry *entry; 117 struct args_entry *entry1; 118 119 cmd_free_argv(args->argc, args->argv); 120 121 RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) { 122 RB_REMOVE(args_tree, &args->tree, entry); 123 free(entry->value); 124 free(entry); 125 } 126 127 free(args); 128 } 129 130 /* Add to string. */ 131 static void printflike(3, 4) 132 args_print_add(char **buf, size_t *len, const char *fmt, ...) 133 { 134 va_list ap; 135 char *s; 136 size_t slen; 137 138 va_start(ap, fmt); 139 slen = xvasprintf(&s, fmt, ap); 140 va_end(ap); 141 142 *len += slen; 143 *buf = xrealloc(*buf, *len); 144 145 strlcat(*buf, s, *len); 146 free(s); 147 } 148 149 /* Print a set of arguments. */ 150 char * 151 args_print(struct args *args) 152 { 153 size_t len; 154 char *buf; 155 int i; 156 struct args_entry *entry; 157 158 len = 1; 159 buf = xcalloc(1, len); 160 161 /* Process the flags first. */ 162 RB_FOREACH(entry, args_tree, &args->tree) { 163 if (entry->value != NULL) 164 continue; 165 166 if (*buf == '\0') 167 args_print_add(&buf, &len, "-"); 168 args_print_add(&buf, &len, "%c", entry->flag); 169 } 170 171 /* Then the flags with arguments. */ 172 RB_FOREACH(entry, args_tree, &args->tree) { 173 if (entry->value == NULL) 174 continue; 175 176 if (*buf != '\0') 177 args_print_add(&buf, &len, " -%c ", entry->flag); 178 else 179 args_print_add(&buf, &len, "-%c ", entry->flag); 180 if (strchr(entry->value, ' ') != NULL) 181 args_print_add(&buf, &len, "\"%s\"", entry->value); 182 else 183 args_print_add(&buf, &len, "%s", entry->value); 184 } 185 186 /* And finally the argument vector. */ 187 for (i = 0; i < args->argc; i++) { 188 if (*buf != '\0') 189 args_print_add(&buf, &len, " "); 190 if (strchr(args->argv[i], ' ') != NULL) 191 args_print_add(&buf, &len, "\"%s\"", args->argv[i]); 192 else 193 args_print_add(&buf, &len, "%s", args->argv[i]); 194 } 195 196 return (buf); 197 } 198 199 /* Return if an argument is present. */ 200 int 201 args_has(struct args *args, u_char ch) 202 { 203 return (args_find(args, ch) == NULL ? 0 : 1); 204 } 205 206 /* Set argument value in the arguments tree. */ 207 void 208 args_set(struct args *args, u_char ch, const char *value) 209 { 210 struct args_entry *entry; 211 212 /* Replace existing argument. */ 213 if ((entry = args_find(args, ch)) != NULL) { 214 free(entry->value); 215 entry->value = NULL; 216 } else { 217 entry = xcalloc(1, sizeof *entry); 218 entry->flag = ch; 219 RB_INSERT(args_tree, &args->tree, entry); 220 } 221 222 if (value != NULL) 223 entry->value = xstrdup(value); 224 } 225 226 /* Get argument value. Will be NULL if it isn't present. */ 227 const char * 228 args_get(struct args *args, u_char ch) 229 { 230 struct args_entry *entry; 231 232 if ((entry = args_find(args, ch)) == NULL) 233 return (NULL); 234 return (entry->value); 235 } 236 237 /* Convert an argument value to a number. */ 238 long long 239 args_strtonum(struct args *args, u_char ch, long long minval, long long maxval, 240 char **cause) 241 { 242 const char *errstr; 243 long long ll; 244 struct args_entry *entry; 245 246 if ((entry = args_find(args, ch)) == NULL) { 247 *cause = xstrdup("missing"); 248 return (0); 249 } 250 251 ll = strtonum(entry->value, minval, maxval, &errstr); 252 if (errstr != NULL) { 253 *cause = xstrdup(errstr); 254 return (0); 255 } 256 257 *cause = NULL; 258 return (ll); 259 } 260