Add some more functions for -liberty and make the library WARNS=6 clean.
[dragonfly.git] / lib / libiberty / argv.c
1 /*
2  * Copyright (c) 2004 Joerg Sonnenberger <joerg@bec.de>
3  *
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.
12  *
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.
24  *
25  * $DragonFly: src/lib/libiberty/argv.c,v 1.1 2004/10/23 12:15:21 joerg Exp $
26  */
27
28 #include <assert.h>
29 #include <libiberty.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #define IS_SEP(x) ((x) == ' ' || (x) == '\t')
34
35 /*
36  * Return the first character of the next word.
37  * len is the word len after quoting and escaping has been removed.
38  */
39 static const char *
40 find_next_word(const char *arg, size_t *len)
41 {
42         enum {NOQUOTE, SQUOTE, DQUOTE} in_quote = NOQUOTE;
43
44         *len = 0;
45
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)++;
70                 }
71                 arg++;
72         }
73         return(arg);
74 }
75
76 static char *
77 copy_word(const char *arg, const char *end, size_t len)
78 {
79         char *buf, *buf_begin;
80         enum {NOQUOTE, SQUOTE, DQUOTE} in_quote = NOQUOTE;
81
82         assert(arg < end);
83
84         buf_begin = buf = malloc(len + 1);
85
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;
108                 }
109         }
110         *buf = '\0';
111         return(buf_begin);
112 }
113
114 char **
115 buildargv(const char *arg)
116 {
117         void *tmp;
118         const char *begin_arg;
119         char **argv;
120         int args;
121         size_t len;
122
123         if (arg == NULL)
124                 return(NULL);
125
126         args = 0;
127         argv = malloc(sizeof(char *));
128         if (argv == NULL)
129                 return(NULL);
130         argv[0] = NULL;
131
132         while (*arg != '\0') {
133                 /* Skip leading white space. */
134                 while (IS_SEP(*arg))
135                         arg++;
136                 if (*arg == '\0')
137                         break;
138
139                 begin_arg = arg;
140                 arg = find_next_word(arg, &len);
141
142                 tmp = realloc(argv, (args + 2) * sizeof(char *));
143                 if (tmp == NULL)
144                         goto error;
145                 argv = tmp;
146
147                 argv[args] = copy_word(begin_arg, arg, len);
148                 if (argv[args] == NULL)
149                         goto error;
150                 args++;
151                 argv[args] = NULL;
152         }
153
154         /*
155          * The argument might be only white space, in that case,
156          * an empty argument list should be returned.
157          */
158         if (args == 0) {
159                 tmp = realloc(argv, 2 * sizeof(char *));
160                 if (tmp == NULL)
161                         goto error;
162                 argv = tmp;
163
164                 argv[0] = strdup("");
165                 if (argv[0] == NULL)
166                         goto error;
167                 argv[1] = NULL;
168         }
169         return(argv);
170 error:
171         freeargv(argv);
172         return(NULL);
173 }
174
175 void
176 freeargv(char **argv)
177 {
178         char **orig_argv;
179
180         if (argv == NULL)
181                 return;
182
183         for (orig_argv = argv; *argv != NULL; argv++)
184                 free(*argv);
185
186         free(orig_argv);        
187 }
188
189 char **
190 dupargv(char * const *argv)
191 {
192         char * const *orig_argv;
193         char **new_argv, **new_argv2;
194         size_t len;
195
196         orig_argv = argv;
197         for (len = 0; *argv != NULL; argv++)
198                 len++;
199
200         new_argv = malloc((len+1) * sizeof(char *));
201
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);
208                 }
209         }
210         *new_argv = NULL;
211
212         return(new_argv2);
213 }