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