OSDN Git Service

c2e2a41e6f02160b0a76adb5130d34f8d745ac34
[pf3gnuchains/pf3gnuchains3x.git] / winsup / mingw / samples / fixargv / fixargv.c
1 /*
2  * fixargv.c
3  *
4  * A special function which "fixes" an argv array by replacing arguments
5  * that need quoting with quoted versions.
6  *
7  * NOTE: In order to be reasonably consistent there is some misuse of the
8  *       const keyword here-- which leads to compilation warnings. These
9  *       should be ok to ignore.
10  *
11  * This is a sample distributed as part of the Mingw32 package.
12  *
13  * Contributors:
14  *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
15  *
16  *  THIS SOFTWARE IS NOT COPYRIGHTED
17  *
18  *  This source code is offered for use in the public domain. You may
19  *  use, modify or distribute it freely.
20  *
21  *  This code is distributed in the hope that it will be useful but
22  *  WITHOUT ANY WARRANTY. ALL WARRENTIES, EXPRESS OR IMPLIED ARE HEREBY
23  *  DISCLAMED. This includes but is not limited to warrenties of
24  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25  *
26  * $Revision$
27  * $Author$
28  * $Date$
29  *
30  */
31
32 #include <string.h>
33 #include "fixargv.h"
34
35 /*
36  * This takes a single string and fixes it, enclosing it in quotes if it
37  * contains any spaces and/or escaping the quotes it contains.
38  */
39 char*
40 fix_arg (const char* szArg)
41 {
42         int     nQuoteAll;      /* Does the whole arg need quoting? */
43         int     nBkSlRun;       /* How may backslashes in a row? */
44         char*   sz;
45         char*   szNew;
46         size_t  sizeLen;
47
48         nQuoteAll = 0;
49         nBkSlRun = 0;
50         sz = szArg;
51         sizeLen = 1;
52
53         /* First we figure out how much bigger the new string has to be
54          * than the old one. */
55         while (*sz != '\0')
56         {
57                 /*
58                  * Arguments containing whitespace of wildcards will be
59                  * quoted to preserve tokenization and/or those special
60                  * characters (i.e. wildcarding will NOT be done at the
61                  * other end-- they will get the * and ? characters as is).
62                  * TODO: Is this the best way? Do we want to enable wildcards?
63                  *       If so, when?
64                  */
65                 if (!nQuoteAll &&
66                     (*sz == ' ' || *sz == '\t' || *sz == '*' || *sz == '?'))
67                 {
68                         nQuoteAll = 1;
69                 }
70                 else if (*sz == '\\')
71                 {
72                         nBkSlRun++;
73                 }
74                 else
75                 {
76                         if (*sz == '\"')
77                         {
78                                 sizeLen += nBkSlRun + 1;
79                         }
80                         nBkSlRun = 0;
81                 }
82
83                 sizeLen++;
84                 sz++;
85         }
86
87         if (nQuoteAll)
88         {
89                 sizeLen += 2;
90         }
91
92         /*
93          * Make a new string big enough.
94          */
95         szNew = (char*) malloc (sizeLen);
96         if (!szNew)
97         {
98                 return NULL;
99         }
100         sz = szNew;
101
102         /* First enclosing quote for fully quoted args. */
103         if (nQuoteAll)
104         {
105                 *sz = '\"';
106                 sz++;
107         }
108
109         /*
110          * Go through the string putting backslashes in front of quotes,
111          * and doubling all backslashes immediately in front of quotes.
112          */
113         nBkSlRun = 0;
114         while (*szArg != '\0')
115         {
116                 if (*szArg == '\\')
117                 {
118                         nBkSlRun++;
119                 }
120                 else
121                 {
122                         if (*szArg == '\"')
123                         {
124                                 while (nBkSlRun > 0)
125                                 {
126                                         *sz = '\\';
127                                         sz++;
128                                         nBkSlRun--;
129                                 }
130                                 *sz = '\\';
131                                 sz++;
132                         }
133                         nBkSlRun = 0;
134                 }
135
136                 *sz = *szArg;
137                 sz++;
138                 szArg++;
139         }
140
141         /* Closing quote for fully quoted args. */
142         if (nQuoteAll)
143         {
144                 *sz = '\"';
145                 sz++;
146         }
147
148         *sz = '\0';
149         return szNew;
150 }
151
152 /*
153  * Takes argc and argv and returns a new argv with escaped members. Pass
154  * this fixed argv (along with the old one) to free_fixed_argv after
155  * you finish with it. Pass in an argc of -1 and make sure the argv vector
156  * ends with a null pointer to have fix_argv count the arguments for you.
157  */
158 char* const*
159 fix_argv (int argc, char* const* szaArgv)
160 {
161         char**  szaNew;
162         char*   sz;
163         int     i;
164
165         if (!szaArgv)
166         {
167                 return NULL;
168         }
169
170         /*
171          * Count the arguments if asked.
172          */
173         if (argc == -1)
174         {
175                 for (i = 0; szaArgv[i]; i++)
176                         ;
177
178                 argc = i;
179         }
180
181         /*
182          * If there are no args or only one arg then do no escaping.
183          */
184         if (argc < 2)
185         {
186                 return szaArgv;
187         }
188
189         for (i = 1, szaNew = NULL; i < argc; i++)
190         {
191                 sz = szaArgv[i];
192
193                 /*
194                  * If an argument needs fixing, then fix it.
195                  */
196                 if (strpbrk (sz, "\" \t*?"))
197                 {
198                         /*
199                          * If we haven't created a new argv list already
200                          * then make one.
201                          */
202                         if (!szaNew)
203                         {
204                                 szaNew = (char**) malloc ((argc + 1) *
205                                         sizeof (char*));
206                                 if (!szaNew)
207                                 {
208                                         return NULL;
209                                 }
210
211                                 /*
212                                  * Copy previous args from old to new.
213                                  */
214                                 memcpy (szaNew, szaArgv, sizeof(char*) * i);
215                         }
216
217                         /*
218                          * Now do the fixing.
219                          */
220                         szaNew[i] = fix_arg (sz);
221                         if (!szaNew[i])
222                         {
223                                 /* Fixing failed, free up and return error. */
224                                 free_fixed_argv (szaNew, szaArgv);
225                                 return NULL;
226                         }
227                 }
228                 else if (szaNew)
229                 {
230                         szaNew[i] = sz;
231                 }
232         }
233
234         if (szaNew)
235         {
236                 /* If we have created a new argv list then we might as well
237                  * terminate it nicely. (And we depend on it in
238                  * free_fixed_argv.) */
239                 szaNew[argc] = NULL;
240         }
241         else
242         {
243                 /* If we didn't create a new argv list then return the
244                  * original. */
245                 return szaArgv;
246         }
247
248         return szaNew;
249 }
250
251 void
252 free_fixed_argv (char* const* szaFixed, char* const* szaOld)
253 {
254         char* const*    sza;
255
256         /*
257          * Check for error conditions. Also note that if no corrections
258          * were required the fixed argv will actually be the same as
259          * the old one, and we don't need to do anything.
260          */
261         if (!szaFixed || !szaOld || szaFixed == szaOld)
262         {
263                 return;
264         }
265
266         /*
267          * Go through all members of the argv list. If any of the
268          * members in the fixed list are different from the old
269          * list we free those members.
270          * NOTE: The first member is never modified, so we don't need to
271          * check.
272          */
273         sza = szaFixed + 1;
274         szaOld++;
275         while (*sza)
276         {
277                 if (*sza != *szaOld)
278                 {
279                         free (*sza);
280                 }
281                 sza++;
282                 szaOld++;
283         }
284
285         /*
286          * Now we can free the array of char pointers itself.
287          */
288         free (szaFixed);
289 }
290