Use offsetof() instead of a hard-coded constant for readability.
[dragonfly.git] / lib / libiberty / argv.c
blob708851c8bcbbfda6219a8e86a4076c9558f712af
1 /*
2 * Copyright (c) 2004 Joerg Sonnenberger <joerg@bec.de>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
25 * $DragonFly: src/lib/libiberty/argv.c,v 1.1 2004/10/23 12:15:21 joerg Exp $
28 #include <assert.h>
29 #include <libiberty.h>
30 #include <stdlib.h>
31 #include <string.h>
33 #define IS_SEP(x) ((x) == ' ' || (x) == '\t')
36 * Return the first character of the next word.
37 * len is the word len after quoting and escaping has been removed.
39 static const char *
40 find_next_word(const char *arg, size_t *len)
42 enum {NOQUOTE, SQUOTE, DQUOTE} in_quote = NOQUOTE;
44 *len = 0;
46 while (*arg != '\0') {
47 if (IS_SEP(*arg) && in_quote == NOQUOTE) {
48 break;
49 } else if (*arg == '\\') {
50 arg++;
51 if (*arg == '\0')
52 break;
53 (*len)++;
54 } else if (*arg == '"') {
55 if (in_quote == NOQUOTE)
56 in_quote = DQUOTE;
57 else if (in_quote == DQUOTE)
58 in_quote = NOQUOTE;
59 else
60 (*len)++;
61 } else if (*arg == '\'') {
62 if (in_quote == NOQUOTE)
63 in_quote = SQUOTE;
64 else if (in_quote == SQUOTE)
65 in_quote = NOQUOTE;
66 else
67 (*len)++;
68 } else {
69 (*len)++;
71 arg++;
73 return(arg);
76 static char *
77 copy_word(const char *arg, const char *end, size_t len)
79 char *buf, *buf_begin;
80 enum {NOQUOTE, SQUOTE, DQUOTE} in_quote = NOQUOTE;
82 assert(arg < end);
84 buf_begin = buf = malloc(len + 1);
86 for (; arg < end; arg++) {
87 if (*arg == '\\') {
88 arg++;
89 if (arg >= end)
90 break;
91 *buf++ = *arg;
92 } else if (*arg == '"') {
93 if (in_quote == NOQUOTE)
94 in_quote = DQUOTE;
95 else if (in_quote == DQUOTE)
96 in_quote = NOQUOTE;
97 else
98 *buf++ = *arg;
99 } else if (*arg == '\'') {
100 if (in_quote == NOQUOTE)
101 in_quote = SQUOTE;
102 else if (in_quote == SQUOTE)
103 in_quote = NOQUOTE;
104 else
105 *buf++ = *arg;
106 } else {
107 *buf++ = *arg;
110 *buf = '\0';
111 return(buf_begin);
114 char **
115 buildargv(const char *arg)
117 void *tmp;
118 const char *begin_arg;
119 char **argv;
120 int args;
121 size_t len;
123 if (arg == NULL)
124 return(NULL);
126 args = 0;
127 argv = malloc(sizeof(char *));
128 if (argv == NULL)
129 return(NULL);
130 argv[0] = NULL;
132 while (*arg != '\0') {
133 /* Skip leading white space. */
134 while (IS_SEP(*arg))
135 arg++;
136 if (*arg == '\0')
137 break;
139 begin_arg = arg;
140 arg = find_next_word(arg, &len);
142 tmp = realloc(argv, (args + 2) * sizeof(char *));
143 if (tmp == NULL)
144 goto error;
145 argv = tmp;
147 argv[args] = copy_word(begin_arg, arg, len);
148 if (argv[args] == NULL)
149 goto error;
150 args++;
151 argv[args] = NULL;
155 * The argument might be only white space, in that case,
156 * an empty argument list should be returned.
158 if (args == 0) {
159 tmp = realloc(argv, 2 * sizeof(char *));
160 if (tmp == NULL)
161 goto error;
162 argv = tmp;
164 argv[0] = strdup("");
165 if (argv[0] == NULL)
166 goto error;
167 argv[1] = NULL;
169 return(argv);
170 error:
171 freeargv(argv);
172 return(NULL);
175 void
176 freeargv(char **argv)
178 char **orig_argv;
180 if (argv == NULL)
181 return;
183 for (orig_argv = argv; *argv != NULL; argv++)
184 free(*argv);
186 free(orig_argv);
189 char **
190 dupargv(char * const *argv)
192 char * const *orig_argv;
193 char **new_argv, **new_argv2;
194 size_t len;
196 orig_argv = argv;
197 for (len = 0; *argv != NULL; argv++)
198 len++;
200 new_argv = malloc((len+1) * sizeof(char *));
202 new_argv2 = new_argv;
203 for (; orig_argv != NULL; orig_argv++, new_argv++) {
204 *new_argv = strdup(*orig_argv);
205 if (*new_argv == NULL) {
206 freeargv(new_argv2);
207 return(NULL);
210 *new_argv = NULL;
212 return(new_argv2);