Postfix3.3.1
argv.c
[詳解]
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. The old string is destroyed after the update is
92 /* made.
93 /*
94 /* argv_delete() deletes the specified number of elements
95 /* starting at the specified array position. The result is
96 /* null-terminated.
97 /*
98 /* ARGV_FAKE_BEGIN/END are an optimization for the case where
99 /* a single string needs to be passed into an ARGV-based
100 /* interface. ARGV_FAKE_BEGIN() opens a statement block and
101 /* allocates a stack-based ARGV structure named after the first
102 /* argument, that encapsulates the second argument. This
103 /* implementation allocates no heap memory and creates no copy
104 /* of the second argument. ARGV_FAKE_END closes the statement
105 /* block and thereby releases storage.
106 /* SEE ALSO
107 /* msg(3) diagnostics interface
108 /* DIAGNOSTICS
109 /* Fatal errors: memory allocation problem.
110 /* LICENSE
111 /* .ad
112 /* .fi
113 /* The Secure Mailer license must be distributed with this software.
114 /* AUTHOR(S)
115 /* Wietse Venema
116 /* IBM T.J. Watson Research
117 /* P.O. Box 704
118 /* Yorktown Heights, NY 10598, USA
119 /*--*/
120 
121 /* System libraries. */
122 
123 #include <sys_defs.h>
124 #include <stdlib.h> /* 44BSD stdarg.h uses abort() */
125 #include <stdarg.h>
126 #include <string.h>
127 
128 /* Application-specific. */
129 
130 #include "mymalloc.h"
131 #include "msg.h"
132 #include "argv.h"
133 
134 /* argv_free - destroy string array */
135 
137 {
138  char **cpp;
139 
140  for (cpp = argvp->argv; cpp < argvp->argv + argvp->argc; cpp++)
141  myfree(*cpp);
142  myfree((void *) argvp->argv);
143  myfree((void *) argvp);
144  return (0);
145 }
146 
147 /* argv_alloc - initialize string array */
148 
149 ARGV *argv_alloc(ssize_t len)
150 {
151  ARGV *argvp;
152  ssize_t sane_len;
153 
154  /*
155  * Make sure that always argvp->argc < argvp->len.
156  */
157  argvp = (ARGV *) mymalloc(sizeof(*argvp));
158  argvp->len = 0;
159  sane_len = (len < 2 ? 2 : len);
160  argvp->argv = (char **) mymalloc((sane_len + 1) * sizeof(char *));
161  argvp->len = sane_len;
162  argvp->argc = 0;
163  argvp->argv[0] = 0;
164  return (argvp);
165 }
166 
167 static int argv_cmp(const void *e1, const void *e2)
168 {
169  const char *s1 = *(const char **) e1;
170  const char *s2 = *(const char **) e2;
171 
172  return strcmp(s1, s2);
173 }
174 
175 /* argv_sort - sort array in place */
176 
178 {
179  qsort(argvp->argv, argvp->argc, sizeof(argvp->argv[0]), argv_cmp);
180  return (argvp);
181 }
182 
183 /* argv_extend - extend array */
184 
185 static void argv_extend(ARGV *argvp)
186 {
187  ssize_t new_len;
188 
189  new_len = argvp->len * 2;
190  argvp->argv = (char **)
191  myrealloc((void *) argvp->argv, (new_len + 1) * sizeof(char *));
192  argvp->len = new_len;
193 }
194 
195 /* argv_add - add string to vector */
196 
197 void argv_add(ARGV *argvp,...)
198 {
199  char *arg;
200  va_list ap;
201 
202  /*
203  * Make sure that always argvp->argc < argvp->len.
204  */
205 #define ARGV_SPACE_LEFT(a) ((a)->len - (a)->argc - 1)
206 
207  va_start(ap, argvp);
208  while ((arg = va_arg(ap, char *)) != 0) {
209  if (ARGV_SPACE_LEFT(argvp) <= 0)
210  argv_extend(argvp);
211  argvp->argv[argvp->argc++] = mystrdup(arg);
212  }
213  va_end(ap);
214  argvp->argv[argvp->argc] = 0;
215 }
216 
217 /* argv_addn - add string to vector */
218 
219 void argv_addn(ARGV *argvp,...)
220 {
221  char *arg;
222  ssize_t len;
223  va_list ap;
224 
225  /*
226  * Make sure that always argvp->argc < argvp->len.
227  */
228  va_start(ap, argvp);
229  while ((arg = va_arg(ap, char *)) != 0) {
230  if ((len = va_arg(ap, ssize_t)) < 0)
231  msg_panic("argv_addn: bad string length %ld", (long) len);
232  if (ARGV_SPACE_LEFT(argvp) <= 0)
233  argv_extend(argvp);
234  argvp->argv[argvp->argc++] = mystrndup(arg, len);
235  }
236  va_end(ap);
237  argvp->argv[argvp->argc] = 0;
238 }
239 
240 /* argv_terminate - terminate string array */
241 
242 void argv_terminate(ARGV *argvp)
243 {
244 
245  /*
246  * Trust that argvp->argc < argvp->len.
247  */
248  argvp->argv[argvp->argc] = 0;
249 }
250 
251 /* argv_truncate - truncate string array */
252 
253 void argv_truncate(ARGV *argvp, ssize_t len)
254 {
255  char **cpp;
256 
257  /*
258  * Sanity check.
259  */
260  if (len < 0)
261  msg_panic("argv_truncate: bad length %ld", (long) len);
262 
263  if (len < argvp->argc) {
264  for (cpp = argvp->argv + len; cpp < argvp->argv + argvp->argc; cpp++)
265  myfree(*cpp);
266  argvp->argc = len;
267  argvp->argv[argvp->argc] = 0;
268  }
269 }
270 
271 /* argv_insert_one - insert one string into array */
272 
273 void argv_insert_one(ARGV *argvp, ssize_t where, const char *arg)
274 {
275  ssize_t pos;
276 
277  /*
278  * Sanity check.
279  */
280  if (where < 0 || where > argvp->argc)
281  msg_panic("argv_insert_one bad position: %ld", (long) where);
282 
283  if (ARGV_SPACE_LEFT(argvp) <= 0)
284  argv_extend(argvp);
285  for (pos = argvp->argc; pos >= where; pos--)
286  argvp->argv[pos + 1] = argvp->argv[pos];
287  argvp->argv[where] = mystrdup(arg);
288  argvp->argc += 1;
289 }
290 
291 /* argv_replace_one - replace one string in array */
292 
293 void argv_replace_one(ARGV *argvp, ssize_t where, const char *arg)
294 {
295  char *temp;
296 
297  /*
298  * Sanity check.
299  */
300  if (where < 0 || where >= argvp->argc)
301  msg_panic("argv_replace_one bad position: %ld", (long) where);
302 
303  temp = argvp->argv[where];
304  argvp->argv[where] = mystrdup(arg);
305  myfree(temp);
306 }
307 
308 /* argv_delete - remove string(s) from array */
309 
310 void argv_delete(ARGV *argvp, ssize_t first, ssize_t how_many)
311 {
312  ssize_t pos;
313 
314  /*
315  * Sanity check.
316  */
317  if (first < 0 || how_many < 0 || first + how_many > argvp->argc)
318  msg_panic("argv_delete bad range: (start=%ld count=%ld)",
319  (long) first, (long) how_many);
320 
321  for (pos = first; pos < first + how_many; pos++)
322  myfree(argvp->argv[pos]);
323  for (pos = first; pos <= argvp->argc - how_many; pos++)
324  argvp->argv[pos] = argvp->argv[pos + how_many];
325  argvp->argc -= how_many;
326 }
void myfree(void *ptr)
Definition: mymalloc.c:207
char * mystrdup(const char *str)
Definition: mymalloc.c:225
ARGV * argv_free(ARGV *argvp)
Definition: argv.c:136
Definition: argv.h:17
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
void argv_replace_one(ARGV *argvp, ssize_t where, const char *arg)
Definition: argv.c:293
void * myrealloc(void *ptr, ssize_t len)
Definition: mymalloc.c:175
char ** argv
Definition: argv.h:20
void argv_add(ARGV *argvp,...)
Definition: argv.c:197
ARGV * argv_alloc(ssize_t len)
Definition: argv.c:149
#define ARGV_SPACE_LEFT(a)
void argv_addn(ARGV *argvp,...)
Definition: argv.c:219
void argv_truncate(ARGV *argvp, ssize_t len)
Definition: argv.c:253
void argv_delete(ARGV *argvp, ssize_t first, ssize_t how_many)
Definition: argv.c:310
char * mystrndup(const char *str, ssize_t len)
Definition: mymalloc.c:242
ARGV * argv_sort(ARGV *argvp)
Definition: argv.c:177
ssize_t len
Definition: argv.h:18
ssize_t argc
Definition: argv.h:19
void argv_insert_one(ARGV *argvp, ssize_t where, const char *arg)
Definition: argv.c:273
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
void argv_terminate(ARGV *argvp)
Definition: argv.c:242