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