1/*	$NetBSD$	*/
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
92ARGV   *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
105ARGV   *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
125static 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
137void    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
159void    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
182void    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
193void    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