1 /* $NetBSD: argv.c,v 1.1.1.1 2009/06/23 10:08:58 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 /* DESCRIPTION 33 /* The functions in this module manipulate arrays of string 34 /* pointers. An ARGV structure contains the following members: 35 /* .IP len 36 /* The length of the \fIargv\fR array member. 37 /* .IP argc 38 /* The number of \fIargv\fR elements used. 39 /* .IP argv 40 /* An array of pointers to null-terminated strings. 41 /* .PP 42 /* argv_alloc() returns an empty string array of the requested 43 /* length. The result is ready for use by argv_add(). The array 44 /* is null terminated. 45 /* 46 /* argv_add() copies zero or more strings and adds them to the 47 /* specified string array. The array is null terminated. 48 /* Terminate the argument list with a null pointer. The manifest 49 /* constant ARGV_END provides a convenient notation for this. 50 /* 51 /* argv_addn() is like argv_add(), but each string is followed 52 /* by a string length argument. 53 /* 54 /* argv_free() releases storage for a string array, and conveniently 55 /* returns a null pointer. 56 /* 57 /* argv_terminate() null-terminates its string array argument. 58 /* 59 /* argv_truncate() trucates its argument to the specified 60 /* number of entries, but does not reallocate memory. The 61 /* result is null-terminated. 62 /* SEE ALSO 63 /* msg(3) diagnostics interface 64 /* DIAGNOSTICS 65 /* Fatal errors: memory allocation problem. 66 /* LICENSE 67 /* .ad 68 /* .fi 69 /* The Secure Mailer license must be distributed with this software. 70 /* AUTHOR(S) 71 /* Wietse Venema 72 /* IBM T.J. Watson Research 73 /* P.O. Box 704 74 /* Yorktown Heights, NY 10598, USA 75 /*--*/ 76 77 /* System libraries. */ 78 79 #include <sys_defs.h> 80 #include <stdlib.h> /* 44BSD stdarg.h uses abort() */ 81 #include <stdarg.h> 82 #include <string.h> 83 84 /* Application-specific. */ 85 86 #include "mymalloc.h" 87 #include "msg.h" 88 #include "argv.h" 89 90 /* argv_free - destroy string array */ 91 92 ARGV *argv_free(ARGV *argvp) 93 { 94 char **cpp; 95 96 for (cpp = argvp->argv; cpp < argvp->argv + argvp->argc; cpp++) 97 myfree(*cpp); 98 myfree((char *) argvp->argv); 99 myfree((char *) argvp); 100 return (0); 101 } 102 103 /* argv_alloc - initialize string array */ 104 105 ARGV *argv_alloc(ssize_t len) 106 { 107 ARGV *argvp; 108 ssize_t sane_len; 109 110 /* 111 * Make sure that always argvp->argc < argvp->len. 112 */ 113 argvp = (ARGV *) mymalloc(sizeof(*argvp)); 114 argvp->len = 0; 115 sane_len = (len < 2 ? 2 : len); 116 argvp->argv = (char **) mymalloc((sane_len + 1) * sizeof(char *)); 117 argvp->len = sane_len; 118 argvp->argc = 0; 119 argvp->argv[0] = 0; 120 return (argvp); 121 } 122 123 /* argv_extend - extend array */ 124 125 static void argv_extend(ARGV *argvp) 126 { 127 ssize_t new_len; 128 129 new_len = argvp->len * 2; 130 argvp->argv = (char **) 131 myrealloc((char *) argvp->argv, (new_len + 1) * sizeof(char *)); 132 argvp->len = new_len; 133 } 134 135 /* argv_add - add string to vector */ 136 137 void argv_add(ARGV *argvp,...) 138 { 139 char *arg; 140 va_list ap; 141 142 /* 143 * Make sure that always argvp->argc < argvp->len. 144 */ 145 #define ARGV_SPACE_LEFT(a) ((a)->len - (a)->argc - 1) 146 147 va_start(ap, argvp); 148 while ((arg = va_arg(ap, char *)) != 0) { 149 if (ARGV_SPACE_LEFT(argvp) <= 0) 150 argv_extend(argvp); 151 argvp->argv[argvp->argc++] = mystrdup(arg); 152 } 153 va_end(ap); 154 argvp->argv[argvp->argc] = 0; 155 } 156 157 /* argv_addn - add string to vector */ 158 159 void argv_addn(ARGV *argvp,...) 160 { 161 char *arg; 162 ssize_t len; 163 va_list ap; 164 165 /* 166 * Make sure that always argvp->argc < argvp->len. 167 */ 168 va_start(ap, argvp); 169 while ((arg = va_arg(ap, char *)) != 0) { 170 if ((len = va_arg(ap, ssize_t)) < 0) 171 msg_panic("argv_addn: bad string length %ld", (long) len); 172 if (ARGV_SPACE_LEFT(argvp) <= 0) 173 argv_extend(argvp); 174 argvp->argv[argvp->argc++] = mystrndup(arg, len); 175 } 176 va_end(ap); 177 argvp->argv[argvp->argc] = 0; 178 } 179 180 /* argv_terminate - terminate string array */ 181 182 void argv_terminate(ARGV *argvp) 183 { 184 185 /* 186 * Trust that argvp->argc < argvp->len. 187 */ 188 argvp->argv[argvp->argc] = 0; 189 } 190 191 /* argv_truncate - truncate string array */ 192 193 void argv_truncate(ARGV *argvp, ssize_t len) 194 { 195 char **cpp; 196 197 /* 198 * Sanity check. 199 */ 200 if (len < 0) 201 msg_panic("argv_truncate: bad length %ld", (long) len); 202 203 if (len < argvp->argc) { 204 for (cpp = argvp->argv + len; cpp < argvp->argv + argvp->argc; cpp++) 205 myfree(*cpp); 206 argvp->argc = len; 207 argvp->argv[argvp->argc] = 0; 208 } 209 } 210