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