1 /*
2 * args.c -- handles command arguments
3 *
4 * Yet Another FTP Client
5 * Copyright (C) 1998-2001, Martin Hedenfalk <mhe@stacken.kth.se>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version. See COPYING for more details.
11 */
12
13 #include "syshdr.h"
14 #include "args.h"
15 #include "strq.h"
16
args_create(void)17 args_t *args_create(void)
18 {
19 args_t *args = xmalloc(sizeof(args_t));
20 return args;
21 }
22
args_destroy(args_t * args)23 void args_destroy(args_t *args)
24 {
25 if (!args)
26 return;
27
28 args_clear(args);
29 free(args);
30 }
31
args_clear(args_t * args)32 void args_clear(args_t *args)
33 {
34 if(!args)
35 return;
36
37 args_del(args, 0, args->argc);
38 free(args->argv);
39 args->argv = NULL;
40 args->argc = 0;
41 }
42
alloc_argv(unsigned n)43 static char **alloc_argv(unsigned n)
44 {
45 return xmalloc(n * sizeof(char *));
46 }
47
args_init3(args_t * args,int argc,char ** argv,unsigned int first,unsigned int last)48 void args_init3(args_t *args, int argc, char **argv, unsigned int first,
49 unsigned int last)
50 {
51 int i;
52
53 last++;
54 if(last > argc)
55 last = argc;
56 if(last <= first)
57 return;
58
59 args_clear(args);
60
61 if(last == first)
62 return;
63
64 args->argv = alloc_argv(last - first);
65
66 for(i=first; i<last; i++)
67 args->argv[args->argc++] = xstrdup(argv[i]);
68 }
69
args_init2(args_t * args,int argc,char ** argv,unsigned int first)70 void args_init2(args_t *args, int argc, char **argv, unsigned int first)
71 {
72 args_init3(args, argc, argv, first, argc);
73 }
74
args_init(args_t * args,int argc,char ** argv)75 void args_init(args_t *args, int argc, char **argv)
76 {
77 args_init2(args, argc, argv, 0);
78 }
79
args_del(args_t * args,unsigned int first,unsigned int n)80 void args_del(args_t *args, unsigned int first, unsigned int n)
81 {
82 unsigned int i;
83 unsigned int deleted = 0;
84
85 if(!args)
86 return;
87
88 for(i=first; deleted<n && i<args->argc; i++, deleted++)
89 free(args->argv[i]);
90
91 for(i=first+n; i<args->argc; i++) {
92 args->argv[i-n] = args->argv[i];
93 args->argv[i] = 0;
94 }
95
96 args->argc -= deleted;
97 }
98
args_cat(int argc,char ** argv,unsigned int first)99 char *args_cat(int argc, char **argv, unsigned int first)
100 {
101 int i;
102 char *e;
103 size_t s = 0;
104
105 for(i=first; i<argc; i++)
106 s += strlen(argv[i]) + 1;
107 e = xmalloc(s);
108 for(i=first; i<argc; i++) {
109 strcat(e, argv[i]);
110 if(i+1 < argc)
111 strcat(e, " ");
112 }
113 return e;
114 }
115
args_cat2(const args_t * args,unsigned int first)116 char *args_cat2(const args_t *args, unsigned int first)
117 {
118 return args_cat(args->argc, args->argv, first);
119 }
120
split_args(const char * str)121 static args_t *split_args(const char *str)
122 {
123 args_t *args = args_create();
124 char *c, *orgc;
125 char *e;
126
127 c = orgc = xstrdup(str);
128
129 args->argv = alloc_argv(strqnchr(str, ' ')+1);
130 /* allocated argv might be way too big if there are many
131 * adjacent spaces in str */
132
133 while(c && (e = strqsep(&c, ' ')) != 0)
134 args->argv[args->argc++] = xstrdup(e);
135
136 if(args->argc == 0) {
137 args_clear(args);
138 goto clean;
139 }
140 args->argv = xrealloc(args->argv, args->argc * sizeof(char *));
141
142 clean:
143 free(orgc);
144 return args;
145 }
146
args_add_args3(args_t * args,const args_t * add_args,unsigned int first,unsigned int last)147 void args_add_args3(args_t *args, const args_t *add_args, unsigned int first,
148 unsigned int last)
149 {
150 int i;
151 char **argv;
152 int argc = 0;
153
154 last++;
155 if(last > add_args->argc)
156 last = add_args->argc;
157
158 if(last <= first)
159 return;
160
161 argv = alloc_argv(args->argc + (last - first));
162
163 /* copy orig args */
164 for(i=0; i<args->argc; i++)
165 argv[argc++] = args->argv[i];
166
167 /* append add_args */
168 for(i=first; i <last; i++)
169 argv[argc++] = xstrdup(add_args->argv[i]);
170
171 free(args->argv);
172 args->argv = argv;
173 args->argc = argc;
174 }
175
args_add_args2(args_t * args,const args_t * add_args,unsigned int first)176 void args_add_args2(args_t *args, const args_t *add_args, unsigned int first)
177 {
178 args_add_args3(args, add_args, first, add_args->argc);
179 }
180
args_add_args(args_t * args,const args_t * add_args)181 void args_add_args(args_t *args, const args_t *add_args)
182 {
183 args_add_args2(args, add_args, 0);
184 }
185
args_add_null(args_t * args)186 void args_add_null(args_t *args)
187 {
188 args_t *add_args = args_create();
189 add_args->argv = alloc_argv(1);
190 add_args->argv[0] = 0;
191 add_args->argc = 1;
192 args_add_args(args, add_args);
193 args_destroy(add_args);
194 }
195
args_push_back(args_t * args,const char * str)196 void args_push_back(args_t *args, const char *str)
197 {
198 args_t *add_args = split_args(str);
199 args_add_args(args, add_args);
200 args_destroy(add_args);
201 }
202
args_push_back_nosplit(args_t * args,const char * str)203 void args_push_back_nosplit(args_t *args, const char *str)
204 {
205 args_t *add_args = args_create();
206 add_args->argv = alloc_argv(1);
207 add_args->argv[0] = xstrdup(str);
208 add_args->argc = 1;
209 args_add_args(args, add_args);
210 args_destroy(add_args);
211 }
212
args_push_front(args_t * args,const char * str)213 void args_push_front(args_t *args, const char *str)
214 {
215 args_t *a = split_args(str);
216 args_add_args(a, args);
217 args_clear(args);
218 args->argc = a->argc;
219 args->argv = a->argv;
220 free(a);
221 }
222
223 /* removes zero-length arguments
224 */
args_remove_empty(args_t * args)225 void args_remove_empty(args_t *args)
226 {
227 int i;
228
229 for(i=0;i<args->argc;) {
230 if(!args->argv[i] || strlen(args->argv[i]) == 0)
231 args_del(args, i, 1);
232 else
233 i++;
234 }
235 }
236
237 /* unquotes each argument in args
238 */
args_unquote(args_t * args)239 void args_unquote(args_t *args)
240 {
241 int i;
242
243 for(i=0;i<args->argc;i++)
244 unquote(args->argv[i]);
245 }
246
247 /* inserts STR into ARGS at index INDEX
248 */
args_insert_string(args_t * args,unsigned int index,const char * str)249 void args_insert_string(args_t *args, unsigned int index, const char *str)
250 {
251 args_t *a;
252
253 if(!args || !str)
254 return;
255
256 if(index > args->argc)
257 return;
258
259 a = args_create();
260 args_init2(a, args->argc, args->argv, index);
261 args_del(args, index, args->argc - index);
262 args_push_back(args, str);
263 args_add_args(args, a);
264 free(a);
265 }
266
267 /* inserts INSARGS between FIRST and LAST (and ALWAYS?) into ARGS at index INDEX
268 */
args_insert_args(args_t * args,unsigned int index,const args_t * insargs,unsigned int first,unsigned int last)269 void args_insert_args(args_t *args, unsigned int index, const args_t *insargs,
270 unsigned int first, unsigned int last)
271 {
272 args_t *a;
273
274 if(!args || !insargs)
275 return;
276
277 if(index > args->argc)
278 return;
279
280 a = args_create();
281 args_init2(a, args->argc, args->argv, index);
282 args_del(args, index, args->argc - index);
283 args_add_args3(args, insargs, first, last);
284 args_add_args(args, a);
285 free(a);
286 }
287