1 /* $NetBSD: argv.c,v 1.1.1.3 2013/09/25 19:06:36 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* argv 3 6 /* SUMMARY 7 /* string array utilities 8 /* SYNOPSIS 9 /* #include <argv.h> 10 /* 11 /* ARGV *argv_alloc(len) 12 /* ssize_t len; 13 /* 14 /* ARGV *argv_free(argvp) 15 /* ARGV *argvp; 16 /* 17 /* void argv_add(argvp, arg, ..., ARGV_END) 18 /* ARGV *argvp; 19 /* char *arg; 20 /* 21 /* void argv_addn(argvp, arg, arg_len, ..., ARGV_END) 22 /* ARGV *argvp; 23 /* char *arg; 24 /* ssize_t arg_len; 25 /* 26 /* void argv_terminate(argvp); 27 /* ARGV *argvp; 28 /* 29 /* void argv_truncate(argvp, len); 30 /* ARGV *argvp; 31 /* ssize_t len; 32 /* 33 /* void argv_insert_one(argvp, pos, arg) 34 /* ARGV *argvp; 35 /* ssize_t pos; 36 /* const char *arg; 37 /* 38 /* void argv_replace_one(argvp, pos, arg) 39 /* ARGV *argvp; 40 /* ssize_t pos; 41 /* const char *arg; 42 /* 43 /* void ARGV_FAKE_BEGIN(argv, arg) 44 /* const char *arg; 45 /* 46 /* void ARGV_FAKE_END 47 /* DESCRIPTION 48 /* The functions in this module manipulate arrays of string 49 /* pointers. An ARGV structure contains the following members: 50 /* .IP len 51 /* The length of the \fIargv\fR array member. 52 /* .IP argc 53 /* The number of \fIargv\fR elements used. 54 /* .IP argv 55 /* An array of pointers to null-terminated strings. 56 /* .PP 57 /* argv_alloc() returns an empty string array of the requested 58 /* length. The result is ready for use by argv_add(). The array 59 /* is null terminated. 60 /* 61 /* argv_add() copies zero or more strings and adds them to the 62 /* specified string array. The array is null terminated. 63 /* Terminate the argument list with a null pointer. The manifest 64 /* constant ARGV_END provides a convenient notation for this. 65 /* 66 /* argv_addn() is like argv_add(), but each string is followed 67 /* by a string length argument. 68 /* 69 /* argv_free() releases storage for a string array, and conveniently 70 /* returns a null pointer. 71 /* 72 /* argv_terminate() null-terminates its string array argument. 73 /* 74 /* argv_truncate() trucates its argument to the specified 75 /* number of entries, but does not reallocate memory. The 76 /* result is null-terminated. 77 /* 78 /* argv_insert_one() inserts one string at the specified array 79 /* position. 80 /* 81 /* argv_replace_one() replaces one string at the specified 82 /* position. 83 /* 84 /* ARGV_FAKE_BEGIN/END are an optimization for the case where 85 /* a single string needs to be passed into an ARGV-based 86 /* interface. ARGV_FAKE_BEGIN() opens a statement block and 87 /* allocates a stack-based ARGV structure named after the first 88 /* argument, that encapsulates the second argument. This 89 /* implementation allocates no heap memory and creates no copy 90 /* of the second argument. ARGV_FAKE_END closes the statement 91 /* block and thereby releases storage. 92 /* SEE ALSO 93 /* msg(3) diagnostics interface 94 /* DIAGNOSTICS 95 /* Fatal errors: memory allocation problem. 96 /* LICENSE 97 /* .ad 98 /* .fi 99 /* The Secure Mailer license must be distributed with this software. 100 /* AUTHOR(S) 101 /* Wietse Venema 102 /* IBM T.J. Watson Research 103 /* P.O. Box 704 104 /* Yorktown Heights, NY 10598, USA 105 /*--*/ 106 107 /* System libraries. */ 108 109 #include <sys_defs.h> 110 #include <stdlib.h> /* 44BSD stdarg.h uses abort() */ 111 #include <stdarg.h> 112 #include <string.h> 113 114 /* Application-specific. */ 115 116 #include "mymalloc.h" 117 #include "msg.h" 118 #include "argv.h" 119 120 /* argv_free - destroy string array */ 121 122 ARGV *argv_free(ARGV *argvp) 123 { 124 char **cpp; 125 126 for (cpp = argvp->argv; cpp < argvp->argv + argvp->argc; cpp++) 127 myfree(*cpp); 128 myfree((char *) argvp->argv); 129 myfree((char *) argvp); 130 return (0); 131 } 132 133 /* argv_alloc - initialize string array */ 134 135 ARGV *argv_alloc(ssize_t len) 136 { 137 ARGV *argvp; 138 ssize_t sane_len; 139 140 /* 141 * Make sure that always argvp->argc < argvp->len. 142 */ 143 argvp = (ARGV *) mymalloc(sizeof(*argvp)); 144 argvp->len = 0; 145 sane_len = (len < 2 ? 2 : len); 146 argvp->argv = (char **) mymalloc((sane_len + 1) * sizeof(char *)); 147 argvp->len = sane_len; 148 argvp->argc = 0; 149 argvp->argv[0] = 0; 150 return (argvp); 151 } 152 153 /* argv_extend - extend array */ 154 155 static void argv_extend(ARGV *argvp) 156 { 157 ssize_t new_len; 158 159 new_len = argvp->len * 2; 160 argvp->argv = (char **) 161 myrealloc((char *) argvp->argv, (new_len + 1) * sizeof(char *)); 162 argvp->len = new_len; 163 } 164 165 /* argv_add - add string to vector */ 166 167 void argv_add(ARGV *argvp,...) 168 { 169 char *arg; 170 va_list ap; 171 172 /* 173 * Make sure that always argvp->argc < argvp->len. 174 */ 175 #define ARGV_SPACE_LEFT(a) ((a)->len - (a)->argc - 1) 176 177 va_start(ap, argvp); 178 while ((arg = va_arg(ap, char *)) != 0) { 179 if (ARGV_SPACE_LEFT(argvp) <= 0) 180 argv_extend(argvp); 181 argvp->argv[argvp->argc++] = mystrdup(arg); 182 } 183 va_end(ap); 184 argvp->argv[argvp->argc] = 0; 185 } 186 187 /* argv_addn - add string to vector */ 188 189 void argv_addn(ARGV *argvp,...) 190 { 191 char *arg; 192 ssize_t len; 193 va_list ap; 194 195 /* 196 * Make sure that always argvp->argc < argvp->len. 197 */ 198 va_start(ap, argvp); 199 while ((arg = va_arg(ap, char *)) != 0) { 200 if ((len = va_arg(ap, ssize_t)) < 0) 201 msg_panic("argv_addn: bad string length %ld", (long) len); 202 if (ARGV_SPACE_LEFT(argvp) <= 0) 203 argv_extend(argvp); 204 argvp->argv[argvp->argc++] = mystrndup(arg, len); 205 } 206 va_end(ap); 207 argvp->argv[argvp->argc] = 0; 208 } 209 210 /* argv_terminate - terminate string array */ 211 212 void argv_terminate(ARGV *argvp) 213 { 214 215 /* 216 * Trust that argvp->argc < argvp->len. 217 */ 218 argvp->argv[argvp->argc] = 0; 219 } 220 221 /* argv_truncate - truncate string array */ 222 223 void argv_truncate(ARGV *argvp, ssize_t len) 224 { 225 char **cpp; 226 227 /* 228 * Sanity check. 229 */ 230 if (len < 0) 231 msg_panic("argv_truncate: bad length %ld", (long) len); 232 233 if (len < argvp->argc) { 234 for (cpp = argvp->argv + len; cpp < argvp->argv + argvp->argc; cpp++) 235 myfree(*cpp); 236 argvp->argc = len; 237 argvp->argv[argvp->argc] = 0; 238 } 239 } 240 241 /* argv_insert_one - insert one string into array */ 242 243 void argv_insert_one(ARGV *argvp, ssize_t where, const char *arg) 244 { 245 ssize_t pos; 246 247 /* 248 * Sanity check. 249 */ 250 if (where < 0 || where > argvp->argc) 251 msg_panic("argv_insert_one bad position: %ld", (long) where); 252 253 if (ARGV_SPACE_LEFT(argvp) <= 0) 254 argv_extend(argvp); 255 for (pos = argvp->argc; pos >= where; pos--) 256 argvp->argv[pos + 1] = argvp->argv[pos]; 257 argvp->argv[where] = mystrdup(arg); 258 argvp->argc += 1; 259 } 260 261 /* argv_replace_one - replace one string in array */ 262 263 void argv_replace_one(ARGV *argvp, ssize_t where, const char *arg) 264 { 265 266 /* 267 * Sanity check. 268 */ 269 if (where < 0 || where >= argvp->argc) 270 msg_panic("argv_replace_one bad position: %ld", (long) where); 271 272 myfree(argvp->argv[where]); 273 argvp->argv[where] = mystrdup(arg); 274 } 275