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