]>
Commit | Line | Data |
---|---|---|
1 | /* copy_command.c -- copy a COMMAND structure. This is needed | |
2 | primarily for making function definitions, but I'm not sure | |
3 | that anyone else will need it. */ | |
4 | ||
5 | /* Copyright (C) 1987-2020,2022 Free Software Foundation, Inc. | |
6 | ||
7 | This file is part of GNU Bash, the Bourne Again SHell. | |
8 | ||
9 | Bash is free software: you can redistribute it and/or modify | |
10 | it under the terms of the GNU General Public License as published by | |
11 | the Free Software Foundation, either version 3 of the License, or | |
12 | (at your option) any later version. | |
13 | ||
14 | Bash is distributed in the hope that it will be useful, | |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | GNU General Public License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with Bash. If not, see <http://www.gnu.org/licenses/>. | |
21 | */ | |
22 | ||
23 | #include "config.h" | |
24 | ||
25 | #include "bashtypes.h" | |
26 | ||
27 | #if defined (HAVE_UNISTD_H) | |
28 | # include <unistd.h> | |
29 | #endif | |
30 | ||
31 | #include <stdio.h> | |
32 | ||
33 | #include "shell.h" | |
34 | ||
35 | static PATTERN_LIST *copy_case_clause (PATTERN_LIST *); | |
36 | static PATTERN_LIST *copy_case_clauses (PATTERN_LIST *); | |
37 | static FOR_COM *copy_for_command (FOR_COM *); | |
38 | #if defined (ARITH_FOR_COMMAND) | |
39 | static ARITH_FOR_COM *copy_arith_for_command (ARITH_FOR_COM *); | |
40 | #endif | |
41 | static GROUP_COM *copy_group_command (GROUP_COM *); | |
42 | static SUBSHELL_COM *copy_subshell_command (SUBSHELL_COM *); | |
43 | static COPROC_COM *copy_coproc_command (COPROC_COM *); | |
44 | static CASE_COM *copy_case_command (CASE_COM *); | |
45 | static WHILE_COM *copy_while_command (WHILE_COM *); | |
46 | static IF_COM *copy_if_command (IF_COM *); | |
47 | #if defined (DPAREN_ARITHMETIC) | |
48 | static ARITH_COM *copy_arith_command (ARITH_COM *); | |
49 | #endif | |
50 | #if defined (COND_COMMAND) | |
51 | static COND_COM *copy_cond_command (COND_COM *); | |
52 | #endif | |
53 | static SIMPLE_COM *copy_simple_command (SIMPLE_COM *); | |
54 | ||
55 | WORD_DESC * | |
56 | copy_word (WORD_DESC *w) | |
57 | { | |
58 | WORD_DESC *new_word; | |
59 | ||
60 | new_word = make_bare_word (w->word); | |
61 | new_word->flags = w->flags; | |
62 | return (new_word); | |
63 | } | |
64 | ||
65 | /* Copy the chain of words in LIST. Return a pointer to | |
66 | the new chain. */ | |
67 | WORD_LIST * | |
68 | copy_word_list (WORD_LIST *list) | |
69 | { | |
70 | WORD_LIST *new_list, *tl; | |
71 | ||
72 | for (new_list = tl = (WORD_LIST *)NULL; list; list = list->next) | |
73 | { | |
74 | if (new_list == 0) | |
75 | new_list = tl = make_word_list (copy_word (list->word), new_list); | |
76 | else | |
77 | { | |
78 | tl->next = make_word_list (copy_word (list->word), (WORD_LIST *)NULL); | |
79 | tl = tl->next; | |
80 | } | |
81 | } | |
82 | ||
83 | return (new_list); | |
84 | } | |
85 | ||
86 | static PATTERN_LIST * | |
87 | copy_case_clause (PATTERN_LIST *clause) | |
88 | { | |
89 | PATTERN_LIST *new_clause; | |
90 | ||
91 | new_clause = (PATTERN_LIST *)xmalloc (sizeof (PATTERN_LIST)); | |
92 | new_clause->patterns = copy_word_list (clause->patterns); | |
93 | new_clause->action = copy_command (clause->action); | |
94 | new_clause->flags = clause->flags; | |
95 | return (new_clause); | |
96 | } | |
97 | ||
98 | static PATTERN_LIST * | |
99 | copy_case_clauses (PATTERN_LIST *clauses) | |
100 | { | |
101 | PATTERN_LIST *new_list, *new_clause; | |
102 | ||
103 | for (new_list = (PATTERN_LIST *)NULL; clauses; clauses = clauses->next) | |
104 | { | |
105 | new_clause = copy_case_clause (clauses); | |
106 | new_clause->next = new_list; | |
107 | new_list = new_clause; | |
108 | } | |
109 | return (REVERSE_LIST (new_list, PATTERN_LIST *)); | |
110 | } | |
111 | ||
112 | /* Copy a single redirect. */ | |
113 | REDIRECT * | |
114 | copy_redirect (REDIRECT *redirect) | |
115 | { | |
116 | REDIRECT *new_redirect; | |
117 | ||
118 | new_redirect = (REDIRECT *)xmalloc (sizeof (REDIRECT)); | |
119 | *new_redirect = *redirect; /* let the compiler do the fast structure copy */ | |
120 | ||
121 | if (redirect->rflags & REDIR_VARASSIGN) | |
122 | new_redirect->redirector.filename = copy_word (redirect->redirector.filename); | |
123 | ||
124 | switch (redirect->instruction) | |
125 | { | |
126 | case r_reading_until: | |
127 | case r_deblank_reading_until: | |
128 | new_redirect->here_doc_eof = redirect->here_doc_eof ? savestring (redirect->here_doc_eof) : 0; | |
129 | /*FALLTHROUGH*/ | |
130 | case r_reading_string: | |
131 | case r_appending_to: | |
132 | case r_output_direction: | |
133 | case r_input_direction: | |
134 | case r_inputa_direction: | |
135 | case r_err_and_out: | |
136 | case r_append_err_and_out: | |
137 | case r_input_output: | |
138 | case r_output_force: | |
139 | case r_duplicating_input_word: | |
140 | case r_duplicating_output_word: | |
141 | case r_move_input_word: | |
142 | case r_move_output_word: | |
143 | new_redirect->redirectee.filename = copy_word (redirect->redirectee.filename); | |
144 | break; | |
145 | case r_duplicating_input: | |
146 | case r_duplicating_output: | |
147 | case r_move_input: | |
148 | case r_move_output: | |
149 | case r_close_this: | |
150 | break; | |
151 | } | |
152 | return (new_redirect); | |
153 | } | |
154 | ||
155 | REDIRECT * | |
156 | copy_redirects (REDIRECT *list) | |
157 | { | |
158 | REDIRECT *new_list, *temp; | |
159 | ||
160 | for (new_list = (REDIRECT *)NULL; list; list = list->next) | |
161 | { | |
162 | temp = copy_redirect (list); | |
163 | temp->next = new_list; | |
164 | new_list = temp; | |
165 | } | |
166 | return (REVERSE_LIST (new_list, REDIRECT *)); | |
167 | } | |
168 | ||
169 | static FOR_COM * | |
170 | copy_for_command (FOR_COM *com) | |
171 | { | |
172 | FOR_COM *new_for; | |
173 | ||
174 | new_for = (FOR_COM *)xmalloc (sizeof (FOR_COM)); | |
175 | new_for->flags = com->flags; | |
176 | new_for->line = com->line; | |
177 | new_for->name = copy_word (com->name); | |
178 | new_for->map_list = copy_word_list (com->map_list); | |
179 | new_for->action = copy_command (com->action); | |
180 | return (new_for); | |
181 | } | |
182 | ||
183 | #if defined (ARITH_FOR_COMMAND) | |
184 | static ARITH_FOR_COM * | |
185 | copy_arith_for_command (ARITH_FOR_COM *com) | |
186 | { | |
187 | ARITH_FOR_COM *new_arith_for; | |
188 | ||
189 | new_arith_for = (ARITH_FOR_COM *)xmalloc (sizeof (ARITH_FOR_COM)); | |
190 | new_arith_for->flags = com->flags; | |
191 | new_arith_for->line = com->line; | |
192 | new_arith_for->init = copy_word_list (com->init); | |
193 | new_arith_for->test = copy_word_list (com->test); | |
194 | new_arith_for->step = copy_word_list (com->step); | |
195 | new_arith_for->action = copy_command (com->action); | |
196 | return (new_arith_for); | |
197 | } | |
198 | #endif /* ARITH_FOR_COMMAND */ | |
199 | ||
200 | static GROUP_COM * | |
201 | copy_group_command (GROUP_COM *com) | |
202 | { | |
203 | GROUP_COM *new_group; | |
204 | ||
205 | new_group = (GROUP_COM *)xmalloc (sizeof (GROUP_COM)); | |
206 | new_group->command = copy_command (com->command); | |
207 | return (new_group); | |
208 | } | |
209 | ||
210 | static SUBSHELL_COM * | |
211 | copy_subshell_command (SUBSHELL_COM *com) | |
212 | { | |
213 | SUBSHELL_COM *new_subshell; | |
214 | ||
215 | new_subshell = (SUBSHELL_COM *)xmalloc (sizeof (SUBSHELL_COM)); | |
216 | new_subshell->command = copy_command (com->command); | |
217 | new_subshell->flags = com->flags; | |
218 | new_subshell->line = com->line; | |
219 | return (new_subshell); | |
220 | } | |
221 | ||
222 | static COPROC_COM * | |
223 | copy_coproc_command (COPROC_COM *com) | |
224 | { | |
225 | COPROC_COM *new_coproc; | |
226 | ||
227 | new_coproc = (COPROC_COM *)xmalloc (sizeof (COPROC_COM)); | |
228 | new_coproc->name = savestring (com->name); | |
229 | new_coproc->command = copy_command (com->command); | |
230 | new_coproc->flags = com->flags; | |
231 | return (new_coproc); | |
232 | } | |
233 | ||
234 | static CASE_COM * | |
235 | copy_case_command (CASE_COM *com) | |
236 | { | |
237 | CASE_COM *new_case; | |
238 | ||
239 | new_case = (CASE_COM *)xmalloc (sizeof (CASE_COM)); | |
240 | new_case->flags = com->flags; | |
241 | new_case->line = com->line; | |
242 | new_case->word = copy_word (com->word); | |
243 | new_case->clauses = copy_case_clauses (com->clauses); | |
244 | return (new_case); | |
245 | } | |
246 | ||
247 | static WHILE_COM * | |
248 | copy_while_command (WHILE_COM *com) | |
249 | { | |
250 | WHILE_COM *new_while; | |
251 | ||
252 | new_while = (WHILE_COM *)xmalloc (sizeof (WHILE_COM)); | |
253 | new_while->flags = com->flags; | |
254 | new_while->test = copy_command (com->test); | |
255 | new_while->action = copy_command (com->action); | |
256 | return (new_while); | |
257 | } | |
258 | ||
259 | static IF_COM * | |
260 | copy_if_command (IF_COM *com) | |
261 | { | |
262 | IF_COM *new_if; | |
263 | ||
264 | new_if = (IF_COM *)xmalloc (sizeof (IF_COM)); | |
265 | new_if->flags = com->flags; | |
266 | new_if->test = copy_command (com->test); | |
267 | new_if->true_case = copy_command (com->true_case); | |
268 | new_if->false_case = com->false_case ? copy_command (com->false_case) : com->false_case; | |
269 | return (new_if); | |
270 | } | |
271 | ||
272 | #if defined (DPAREN_ARITHMETIC) | |
273 | static ARITH_COM * | |
274 | copy_arith_command (ARITH_COM *com) | |
275 | { | |
276 | ARITH_COM *new_arith; | |
277 | ||
278 | new_arith = (ARITH_COM *)xmalloc (sizeof (ARITH_COM)); | |
279 | new_arith->flags = com->flags; | |
280 | new_arith->exp = copy_word_list (com->exp); | |
281 | new_arith->line = com->line; | |
282 | ||
283 | return (new_arith); | |
284 | } | |
285 | #endif | |
286 | ||
287 | #if defined (COND_COMMAND) | |
288 | static COND_COM * | |
289 | copy_cond_command (COND_COM *com) | |
290 | { | |
291 | COND_COM *new_cond; | |
292 | ||
293 | new_cond = (COND_COM *)xmalloc (sizeof (COND_COM)); | |
294 | new_cond->flags = com->flags; | |
295 | new_cond->line = com->line; | |
296 | new_cond->type = com->type; | |
297 | new_cond->op = com->op ? copy_word (com->op) : com->op; | |
298 | new_cond->left = com->left ? copy_cond_command (com->left) : (COND_COM *)NULL; | |
299 | new_cond->right = com->right ? copy_cond_command (com->right) : (COND_COM *)NULL; | |
300 | ||
301 | return (new_cond); | |
302 | } | |
303 | #endif | |
304 | ||
305 | static SIMPLE_COM * | |
306 | copy_simple_command (SIMPLE_COM *com) | |
307 | { | |
308 | SIMPLE_COM *new_simple; | |
309 | ||
310 | new_simple = (SIMPLE_COM *)xmalloc (sizeof (SIMPLE_COM)); | |
311 | new_simple->flags = com->flags; | |
312 | new_simple->words = copy_word_list (com->words); | |
313 | new_simple->redirects = com->redirects ? copy_redirects (com->redirects) : (REDIRECT *)NULL; | |
314 | new_simple->line = com->line; | |
315 | return (new_simple); | |
316 | } | |
317 | ||
318 | FUNCTION_DEF * | |
319 | copy_function_def_contents (FUNCTION_DEF *old, FUNCTION_DEF *new_def) | |
320 | { | |
321 | new_def->name = copy_word (old->name); | |
322 | new_def->command = old->command ? copy_command (old->command) : old->command; | |
323 | new_def->flags = old->flags; | |
324 | new_def->line = old->line; | |
325 | new_def->source_file = old->source_file ? savestring (old->source_file) : old->source_file; | |
326 | return (new_def); | |
327 | } | |
328 | ||
329 | FUNCTION_DEF * | |
330 | copy_function_def (FUNCTION_DEF *com) | |
331 | { | |
332 | FUNCTION_DEF *new_def; | |
333 | ||
334 | new_def = (FUNCTION_DEF *)xmalloc (sizeof (FUNCTION_DEF)); | |
335 | new_def = copy_function_def_contents (com, new_def); | |
336 | return (new_def); | |
337 | } | |
338 | ||
339 | /* Copy the command structure in COMMAND. Return a pointer to the | |
340 | copy. Don't you forget to dispose_command () on this pointer | |
341 | later! */ | |
342 | COMMAND * | |
343 | copy_command (COMMAND *command) | |
344 | { | |
345 | COMMAND *new_command; | |
346 | ||
347 | if (command == NULL) | |
348 | return (command); | |
349 | ||
350 | new_command = (COMMAND *)xmalloc (sizeof (COMMAND)); | |
351 | FASTCOPY ((char *)command, (char *)new_command, sizeof (COMMAND)); | |
352 | new_command->flags = command->flags; | |
353 | new_command->line = command->line; | |
354 | ||
355 | if (command->redirects) | |
356 | new_command->redirects = copy_redirects (command->redirects); | |
357 | ||
358 | switch (command->type) | |
359 | { | |
360 | case cm_for: | |
361 | new_command->value.For = copy_for_command (command->value.For); | |
362 | break; | |
363 | ||
364 | #if defined (ARITH_FOR_COMMAND) | |
365 | case cm_arith_for: | |
366 | new_command->value.ArithFor = copy_arith_for_command (command->value.ArithFor); | |
367 | break; | |
368 | #endif | |
369 | ||
370 | #if defined (SELECT_COMMAND) | |
371 | case cm_select: | |
372 | new_command->value.Select = | |
373 | (SELECT_COM *)copy_for_command ((FOR_COM *)command->value.Select); | |
374 | break; | |
375 | #endif | |
376 | ||
377 | case cm_group: | |
378 | new_command->value.Group = copy_group_command (command->value.Group); | |
379 | break; | |
380 | ||
381 | case cm_subshell: | |
382 | new_command->value.Subshell = copy_subshell_command (command->value.Subshell); | |
383 | break; | |
384 | ||
385 | case cm_coproc: | |
386 | new_command->value.Coproc = copy_coproc_command (command->value.Coproc); | |
387 | break; | |
388 | ||
389 | case cm_case: | |
390 | new_command->value.Case = copy_case_command (command->value.Case); | |
391 | break; | |
392 | ||
393 | case cm_until: | |
394 | case cm_while: | |
395 | new_command->value.While = copy_while_command (command->value.While); | |
396 | break; | |
397 | ||
398 | case cm_if: | |
399 | new_command->value.If = copy_if_command (command->value.If); | |
400 | break; | |
401 | ||
402 | #if defined (DPAREN_ARITHMETIC) | |
403 | case cm_arith: | |
404 | new_command->value.Arith = copy_arith_command (command->value.Arith); | |
405 | break; | |
406 | #endif | |
407 | ||
408 | #if defined (COND_COMMAND) | |
409 | case cm_cond: | |
410 | new_command->value.Cond = copy_cond_command (command->value.Cond); | |
411 | break; | |
412 | #endif | |
413 | ||
414 | case cm_simple: | |
415 | new_command->value.Simple = copy_simple_command (command->value.Simple); | |
416 | break; | |
417 | ||
418 | case cm_connection: | |
419 | { | |
420 | CONNECTION *new_connection; | |
421 | ||
422 | new_connection = (CONNECTION *)xmalloc (sizeof (CONNECTION)); | |
423 | new_connection->connector = command->value.Connection->connector; | |
424 | new_connection->first = copy_command (command->value.Connection->first); | |
425 | new_connection->second = copy_command (command->value.Connection->second); | |
426 | new_command->value.Connection = new_connection; | |
427 | break; | |
428 | } | |
429 | ||
430 | case cm_function_def: | |
431 | new_command->value.Function_def = copy_function_def (command->value.Function_def); | |
432 | break; | |
433 | } | |
434 | return (new_command); | |
435 | } |