xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/argv.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
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