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