1 /* $OpenBSD: arguments.c,v 1.4 2012/07/10 11:53:01 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 <bitstring.h> 22 #include <stdlib.h> 23 #include <string.h> 24 25 #include "tmux.h" 26 27 /* Create an arguments set with no flags. */ 28 struct args * 29 args_create(int argc, ...) 30 { 31 struct args *args; 32 va_list ap; 33 int i; 34 35 args = xcalloc(1, sizeof *args); 36 if ((args->flags = bit_alloc(SCHAR_MAX)) == NULL) 37 fatal("bit_alloc failed"); 38 39 args->argc = argc; 40 if (argc == 0) 41 args->argv = NULL; 42 else 43 args->argv = xcalloc(argc, sizeof *args->argv); 44 45 va_start(ap, argc); 46 for (i = 0; i < argc; i++) 47 args->argv[i] = xstrdup(va_arg(ap, char *)); 48 va_end(ap); 49 50 return (args); 51 } 52 53 /* Parse an argv and argc into a new argument set. */ 54 struct args * 55 args_parse(const char *template, int argc, char **argv) 56 { 57 struct args *args; 58 char *ptr; 59 int opt; 60 61 args = xcalloc(1, sizeof *args); 62 if ((args->flags = bit_alloc(SCHAR_MAX)) == NULL) 63 fatal("bit_alloc failed"); 64 65 optreset = 1; 66 optind = 1; 67 68 while ((opt = getopt(argc, argv, template)) != -1) { 69 if (opt < 0 || opt >= SCHAR_MAX) 70 continue; 71 if (opt == '?' || (ptr = strchr(template, opt)) == NULL) { 72 free(args->flags); 73 free(args); 74 return (NULL); 75 } 76 77 bit_set(args->flags, opt); 78 if (ptr[1] == ':') { 79 free(args->values[opt]); 80 args->values[opt] = xstrdup(optarg); 81 } 82 } 83 argc -= optind; 84 argv += optind; 85 86 args->argc = argc; 87 args->argv = cmd_copy_argv(argc, argv); 88 89 return (args); 90 } 91 92 /* Free an arguments set. */ 93 void 94 args_free(struct args *args) 95 { 96 u_int i; 97 98 cmd_free_argv(args->argc, args->argv); 99 100 for (i = 0; i < SCHAR_MAX; i++) 101 free(args->values[i]); 102 103 free(args->flags); 104 free(args); 105 } 106 107 /* Print a set of arguments. */ 108 size_t 109 args_print(struct args *args, char *buf, size_t len) 110 { 111 size_t off; 112 int i; 113 const char *quotes; 114 115 /* There must be at least one byte at the start. */ 116 if (len == 0) 117 return (0); 118 off = 0; 119 120 /* Process the flags first. */ 121 buf[off++] = '-'; 122 for (i = 0; i < SCHAR_MAX; i++) { 123 if (!bit_test(args->flags, i) || args->values[i] != NULL) 124 continue; 125 126 if (off == len - 1) { 127 buf[off] = '\0'; 128 return (len); 129 } 130 buf[off++] = i; 131 buf[off] = '\0'; 132 } 133 if (off == 1) 134 buf[--off] = '\0'; 135 136 /* Then the flags with arguments. */ 137 for (i = 0; i < SCHAR_MAX; i++) { 138 if (!bit_test(args->flags, i) || args->values[i] == NULL) 139 continue; 140 141 if (off >= len) { 142 /* snprintf will have zero terminated. */ 143 return (len); 144 } 145 146 if (strchr(args->values[i], ' ') != NULL) 147 quotes = "\""; 148 else 149 quotes = ""; 150 off += xsnprintf(buf + off, len - off, "%s-%c %s%s%s", 151 off != 0 ? " " : "", i, quotes, args->values[i], quotes); 152 } 153 154 /* And finally the argument vector. */ 155 for (i = 0; i < args->argc; i++) { 156 if (off >= len) { 157 /* snprintf will have zero terminated. */ 158 return (len); 159 } 160 161 if (strchr(args->argv[i], ' ') != NULL) 162 quotes = "\""; 163 else 164 quotes = ""; 165 off += xsnprintf(buf + off, len - off, "%s%s%s%s", 166 off != 0 ? " " : "", quotes, args->argv[i], quotes); 167 } 168 169 return (off); 170 } 171 172 /* Return if an argument is present. */ 173 int 174 args_has(struct args *args, u_char ch) 175 { 176 return (bit_test(args->flags, ch)); 177 } 178 179 /* Set argument value. */ 180 void 181 args_set(struct args *args, u_char ch, const char *value) 182 { 183 free(args->values[ch]); 184 if (value != NULL) 185 args->values[ch] = xstrdup(value); 186 else 187 args->values[ch] = NULL; 188 bit_set(args->flags, ch); 189 } 190 191 /* Get argument value. Will be NULL if it isn't present. */ 192 const char * 193 args_get(struct args *args, u_char ch) 194 { 195 return (args->values[ch]); 196 } 197 198 /* Convert an argument value to a number. */ 199 long long 200 args_strtonum(struct args *args, 201 u_char ch, long long minval, long long maxval, char **cause) 202 { 203 const char *errstr; 204 long long ll; 205 206 if (!args_has(args, ch)) { 207 *cause = xstrdup("missing"); 208 return (0); 209 } 210 211 ll = strtonum(args->values[ch], minval, maxval, &errstr); 212 if (errstr != NULL) { 213 *cause = xstrdup(errstr); 214 return (0); 215 } 216 217 *cause = NULL; 218 return (ll); 219 } 220