]> git.ipfire.org Git - thirdparty/bash.git/blob - arrayfunc.c
Imported from ../bash-3.0.16.tar.gz.
[thirdparty/bash.git] / arrayfunc.c
1 /* arrayfunc.c -- High-level array functions used by other parts of the shell. */
2
3 /* Copyright (C) 2001-2003 Free Software Foundation, Inc.
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
7 Bash is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with Bash; see the file COPYING. If not, write to the Free Software
19 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
20
21 #include "config.h"
22
23 #if defined (ARRAY_VARS)
24
25 #if defined (HAVE_UNISTD_H)
26 # include <unistd.h>
27 #endif
28 #include <stdio.h>
29
30 #include "bashintl.h"
31
32 #include "shell.h"
33
34 #include "shmbutil.h"
35
36 #include "builtins/common.h"
37
38 extern char *this_command_name;
39 extern int last_command_exit_value;
40
41 static void quote_array_assignment_chars __P((WORD_LIST *));
42 static char *array_value_internal __P((char *, int, int, int *));
43
44 /* Standard error message to use when encountering an invalid array subscript */
45 char *bash_badsub_errmsg = N_("bad array subscript");
46
47 /* **************************************************************** */
48 /* */
49 /* Functions to manipulate array variables and perform assignments */
50 /* */
51 /* **************************************************************** */
52
53 /* Convert a shell variable to an array variable. The original value is
54 saved as array[0]. */
55 SHELL_VAR *
56 convert_var_to_array (var)
57 SHELL_VAR *var;
58 {
59 char *oldval;
60 ARRAY *array;
61
62 oldval = value_cell (var);
63 array = array_create ();
64 if (oldval)
65 array_insert (array, 0, oldval);
66
67 FREE (value_cell (var));
68 var_setarray (var, array);
69
70 /* these aren't valid anymore */
71 var->dynamic_value = (sh_var_value_func_t *)NULL;
72 var->assign_func = (sh_var_assign_func_t *)NULL;
73
74 INVALIDATE_EXPORTSTR (var);
75
76 VSETATTR (var, att_array);
77 VUNSETATTR (var, att_invisible);
78
79 return var;
80 }
81
82 /* Perform an array assignment name[ind]=value. If NAME already exists and
83 is not an array, and IND is 0, perform name=value instead. If NAME exists
84 and is not an array, and IND is not 0, convert it into an array with the
85 existing value as name[0].
86
87 If NAME does not exist, just create an array variable, no matter what
88 IND's value may be. */
89 SHELL_VAR *
90 bind_array_variable (name, ind, value)
91 char *name;
92 arrayind_t ind;
93 char *value;
94 {
95 SHELL_VAR *entry;
96 char *newval;
97
98 entry = var_lookup (name, shell_variables);
99
100 if (entry == (SHELL_VAR *) 0)
101 entry = make_new_array_variable (name);
102 else if (readonly_p (entry) || noassign_p (entry))
103 {
104 if (readonly_p (entry))
105 err_readonly (name);
106 return (entry);
107 }
108 else if (array_p (entry) == 0)
109 entry = convert_var_to_array (entry);
110
111 /* ENTRY is an array variable, and ARRAY points to the value. */
112 newval = make_variable_value (entry, value);
113 if (entry->assign_func)
114 (*entry->assign_func) (entry, newval, ind);
115 else
116 array_insert (array_cell (entry), ind, newval);
117 FREE (newval);
118
119 return (entry);
120 }
121
122 /* Parse NAME, a lhs of an assignment statement of the form v[s], and
123 assign VALUE to that array element by calling bind_array_variable(). */
124 SHELL_VAR *
125 assign_array_element (name, value)
126 char *name, *value;
127 {
128 char *sub, *vname;
129 arrayind_t ind;
130 int sublen;
131 SHELL_VAR *entry;
132
133 vname = array_variable_name (name, &sub, &sublen);
134
135 if (vname == 0)
136 return ((SHELL_VAR *)NULL);
137
138 if ((ALL_ELEMENT_SUB (sub[0]) && sub[1] == ']') || (sublen <= 1))
139 {
140 free (vname);
141 err_badarraysub (name);
142 return ((SHELL_VAR *)NULL);
143 }
144
145 ind = array_expand_index (sub, sublen);
146 if (ind < 0)
147 {
148 free (vname);
149 err_badarraysub (name);
150 return ((SHELL_VAR *)NULL);
151 }
152
153 entry = bind_array_variable (vname, ind, value);
154
155 free (vname);
156 return (entry);
157 }
158
159 /* Find the array variable corresponding to NAME. If there is no variable,
160 create a new array variable. If the variable exists but is not an array,
161 convert it to an indexed array. If CHECK_FLAGS is non-zero, an existing
162 variable is checked for the readonly or noassign attribute in preparation
163 for assignment (e.g., by the `read' builtin). */
164 SHELL_VAR *
165 find_or_make_array_variable (name, check_flags)
166 char *name;
167 int check_flags;
168 {
169 SHELL_VAR *var;
170
171 var = find_variable (name);
172
173 if (var == 0)
174 var = make_new_array_variable (name);
175 else if (check_flags && (readonly_p (var) || noassign_p (var)))
176 {
177 if (readonly_p (var))
178 err_readonly (name);
179 return ((SHELL_VAR *)NULL);
180 }
181 else if (array_p (var) == 0)
182 var = convert_var_to_array (var);
183
184 return (var);
185 }
186
187 /* Perform a compound assignment statement for array NAME, where VALUE is
188 the text between the parens: NAME=( VALUE ) */
189 SHELL_VAR *
190 assign_array_from_string (name, value)
191 char *name, *value;
192 {
193 SHELL_VAR *var;
194
195 var = find_or_make_array_variable (name, 1);
196 if (var == 0)
197 return ((SHELL_VAR *)NULL);
198
199 return (assign_array_var_from_string (var, value));
200 }
201
202 /* Sequentially assign the indices of indexed array variable VAR from the
203 words in LIST. */
204 SHELL_VAR *
205 assign_array_var_from_word_list (var, list)
206 SHELL_VAR *var;
207 WORD_LIST *list;
208 {
209 register arrayind_t i;
210 register WORD_LIST *l;
211 ARRAY *a;
212
213 for (a = array_cell (var), l = list, i = 0; l; l = l->next, i++)
214 if (var->assign_func)
215 (*var->assign_func) (var, l->word->word, i);
216 else
217 array_insert (a, i, l->word->word);
218 return var;
219 }
220
221 /* Perform a compound array assignment: VAR->name=( VALUE ). The
222 VALUE has already had the parentheses stripped. */
223 SHELL_VAR *
224 assign_array_var_from_string (var, value)
225 SHELL_VAR *var;
226 char *value;
227 {
228 ARRAY *a;
229 WORD_LIST *list, *nlist;
230 char *w, *val, *nval;
231 int ni, len;
232 arrayind_t ind, last_ind;
233
234 if (value == 0)
235 return var;
236
237 /* If this is called from declare_builtin, value[0] == '(' and
238 xstrchr(value, ')') != 0. In this case, we need to extract
239 the value from between the parens before going on. */
240 if (*value == '(') /*)*/
241 {
242 ni = 1;
243 val = extract_array_assignment_list (value, &ni);
244 if (val == 0)
245 return var;
246 }
247 else
248 val = value;
249
250 /* Expand the value string into a list of words, performing all the
251 shell expansions including pathname generation and word splitting. */
252 /* First we split the string on whitespace, using the shell parser
253 (ksh93 seems to do this). */
254 list = parse_string_to_word_list (val, 1, "array assign");
255
256 /* If we're using [subscript]=value, we need to quote each [ and ] to
257 prevent unwanted filename expansion. */
258 if (list)
259 quote_array_assignment_chars (list);
260
261 /* Now that we've split it, perform the shell expansions on each
262 word in the list. */
263 nlist = list ? expand_words_no_vars (list) : (WORD_LIST *)NULL;
264
265 dispose_words (list);
266
267 if (val != value)
268 free (val);
269
270 a = array_cell (var);
271
272 /* Now that we are ready to assign values to the array, kill the existing
273 value. */
274 if (a)
275 array_flush (a);
276
277 for (last_ind = 0, list = nlist; list; list = list->next)
278 {
279 w = list->word->word;
280
281 /* We have a word of the form [ind]=value */
282 if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[')
283 {
284 len = skipsubscript (w, 0);
285
286 if (w[len] != ']' || w[len+1] != '=')
287 {
288 nval = make_variable_value (var, w);
289 if (var->assign_func)
290 (*var->assign_func) (var, nval, last_ind);
291 else
292 array_insert (a, last_ind, nval);
293 FREE (nval);
294 last_ind++;
295 continue;
296 }
297
298 if (len == 1)
299 {
300 err_badarraysub (w);
301 continue;
302 }
303
304 if (ALL_ELEMENT_SUB (w[1]) && len == 2)
305 {
306 report_error (_("%s: cannot assign to non-numeric index"), w);
307 continue;
308 }
309
310 ind = array_expand_index (w + 1, len);
311 if (ind < 0)
312 {
313 err_badarraysub (w);
314 continue;
315 }
316 last_ind = ind;
317 val = w + len + 2;
318 }
319 else /* No [ind]=value, just a stray `=' */
320 {
321 ind = last_ind;
322 val = w;
323 }
324
325 if (integer_p (var))
326 this_command_name = (char *)NULL; /* no command name for errors */
327 nval = make_variable_value (var, val);
328 if (var->assign_func)
329 (*var->assign_func) (var, nval, ind);
330 else
331 array_insert (a, ind, nval);
332 FREE (nval);
333 last_ind++;
334 }
335
336 dispose_words (nlist);
337 return (var);
338 }
339
340 /* For each word in a compound array assignment, if the word looks like
341 [ind]=value, quote the `[' and `]' before the `=' to protect them from
342 unwanted filename expansion. */
343 static void
344 quote_array_assignment_chars (list)
345 WORD_LIST *list;
346 {
347 char *s, *t, *nword;
348 int saw_eq;
349 WORD_LIST *l;
350
351 for (l = list; l; l = l->next)
352 {
353 if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0')
354 continue; /* should not happen, but just in case... */
355 /* Don't bother if it doesn't look like [ind]=value */
356 if (l->word->word[0] != '[' || xstrchr (l->word->word, '=') == 0) /* ] */
357 continue;
358 s = nword = (char *)xmalloc (strlen (l->word->word) * 2 + 1);
359 saw_eq = 0;
360 for (t = l->word->word; *t; )
361 {
362 if (*t == '=')
363 saw_eq = 1;
364 if (saw_eq == 0 && (*t == '[' || *t == ']'))
365 *s++ = '\\';
366 *s++ = *t++;
367 }
368 *s = '\0';
369 free (l->word->word);
370 l->word->word = nword;
371 }
372 }
373
374 /* This function assumes s[i] == '['; returns with s[ret] == ']' if
375 an array subscript is correctly parsed. */
376 int
377 skipsubscript (s, i)
378 const char *s;
379 int i;
380 {
381 int count, c;
382 #if defined (HANDLE_MULTIBYTE)
383 mbstate_t state, state_bak;
384 size_t slength, mblength;
385 size_t mb_cur_max;
386 #endif
387
388 #if defined (HANDLE_MULTIBYTE)
389 memset (&state, '\0', sizeof (mbstate_t));
390 slength = strlen (s + i);
391 mb_cur_max = MB_CUR_MAX;
392 #endif
393
394 count = 1;
395 while (count)
396 {
397 /* Advance one (possibly multibyte) character in S starting at I. */
398 #if defined (HANDLE_MULTIBYTE)
399 if (mb_cur_max > 1)
400 {
401 state_bak = state;
402 mblength = mbrlen (s + i, slength, &state);
403
404 if (MB_INVALIDCH (mblength))
405 {
406 state = state_bak;
407 i++;
408 slength--;
409 }
410 else if (MB_NULLWCH (mblength))
411 return i;
412 else
413 {
414 i += mblength;
415 slength -= mblength;
416 }
417 }
418 else
419 #endif
420 ++i;
421
422 c = s[i];
423
424 if (c == 0)
425 break;
426 else if (c == '[')
427 count++;
428 else if (c == ']')
429 count--;
430 }
431
432 return i;
433 }
434
435 /* This function is called with SUB pointing to just after the beginning
436 `[' of an array subscript and removes the array element to which SUB
437 expands from array VAR. A subscript of `*' or `@' unsets the array. */
438 int
439 unbind_array_element (var, sub)
440 SHELL_VAR *var;
441 char *sub;
442 {
443 int len;
444 arrayind_t ind;
445 ARRAY_ELEMENT *ae;
446
447 len = skipsubscript (sub, 0);
448 if (sub[len] != ']' || len == 0)
449 {
450 builtin_error ("%s[%s: %s", var->name, sub, _(bash_badsub_errmsg));
451 return -1;
452 }
453 sub[len] = '\0';
454
455 if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0)
456 {
457 unbind_variable (var->name);
458 return (0);
459 }
460 ind = array_expand_index (sub, len+1);
461 if (ind < 0)
462 {
463 builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
464 return -1;
465 }
466 ae = array_remove (array_cell (var), ind);
467 if (ae)
468 array_dispose_element (ae);
469 return 0;
470 }
471
472 /* Format and output an array assignment in compound form VAR=(VALUES),
473 suitable for re-use as input. */
474 void
475 print_array_assignment (var, quoted)
476 SHELL_VAR *var;
477 int quoted;
478 {
479 char *vstr;
480
481 vstr = array_to_assign (array_cell (var), quoted);
482
483 if (vstr == 0)
484 printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
485 else
486 {
487 printf ("%s=%s\n", var->name, vstr);
488 free (vstr);
489 }
490 }
491
492 /***********************************************************************/
493 /* */
494 /* Utility functions to manage arrays and their contents for expansion */
495 /* */
496 /***********************************************************************/
497
498 /* Return 1 if NAME is a properly-formed array reference v[sub]. */
499 int
500 valid_array_reference (name)
501 char *name;
502 {
503 char *t;
504 int r, len;
505
506 t = xstrchr (name, '['); /* ] */
507 if (t)
508 {
509 *t = '\0';
510 r = legal_identifier (name);
511 *t = '[';
512 if (r == 0)
513 return 0;
514 /* Check for a properly-terminated non-blank subscript. */
515 len = skipsubscript (t, 0);
516 if (t[len] != ']' || len == 1)
517 return 0;
518 for (r = 1; r < len; r++)
519 if (whitespace (t[r]) == 0)
520 return 1;
521 return 0;
522 }
523 return 0;
524 }
525
526 /* Expand the array index beginning at S and extending LEN characters. */
527 arrayind_t
528 array_expand_index (s, len)
529 char *s;
530 int len;
531 {
532 char *exp, *t;
533 int expok;
534 arrayind_t val;
535
536 exp = (char *)xmalloc (len);
537 strncpy (exp, s, len - 1);
538 exp[len - 1] = '\0';
539 t = expand_string_to_string (exp, 0);
540 this_command_name = (char *)NULL;
541 val = evalexp (t, &expok);
542 free (t);
543 free (exp);
544 if (expok == 0)
545 {
546 last_command_exit_value = EXECUTION_FAILURE;
547 jump_to_top_level (DISCARD);
548 }
549 return val;
550 }
551
552 /* Return the name of the variable specified by S without any subscript.
553 If SUBP is non-null, return a pointer to the start of the subscript
554 in *SUBP. If LENP is non-null, the length of the subscript is returned
555 in *LENP. This returns newly-allocated memory. */
556 char *
557 array_variable_name (s, subp, lenp)
558 char *s, **subp;
559 int *lenp;
560 {
561 char *t, *ret;
562 int ind, ni;
563
564 t = xstrchr (s, '[');
565 if (t == 0)
566 {
567 if (subp)
568 *subp = t;
569 if (lenp)
570 *lenp = 0;
571 return ((char *)NULL);
572 }
573 ind = t - s;
574 ni = skipsubscript (s, ind);
575 if (ni <= ind + 1 || s[ni] != ']')
576 {
577 err_badarraysub (s);
578 if (subp)
579 *subp = t;
580 if (lenp)
581 *lenp = 0;
582 return ((char *)NULL);
583 }
584
585 *t = '\0';
586 ret = savestring (s);
587 *t++ = '['; /* ] */
588
589 if (subp)
590 *subp = t;
591 if (lenp)
592 *lenp = ni - ind;
593
594 return ret;
595 }
596
597 /* Return the variable specified by S without any subscript. If SUBP is
598 non-null, return a pointer to the start of the subscript in *SUBP.
599 If LENP is non-null, the length of the subscript is returned in *LENP. */
600 SHELL_VAR *
601 array_variable_part (s, subp, lenp)
602 char *s, **subp;
603 int *lenp;
604 {
605 char *t;
606 SHELL_VAR *var;
607
608 t = array_variable_name (s, subp, lenp);
609 if (t == 0)
610 return ((SHELL_VAR *)NULL);
611 var = find_variable (t);
612
613 free (t);
614 return (var == 0 || invisible_p (var)) ? (SHELL_VAR *)0 : var;
615 }
616
617 /* Return a string containing the elements in the array and subscript
618 described by S. If the subscript is * or @, obeys quoting rules akin
619 to the expansion of $* and $@ including double quoting. If RTYPE
620 is non-null it gets 1 if the array reference is name[@] or name[*]
621 and 0 otherwise. */
622 static char *
623 array_value_internal (s, quoted, allow_all, rtype)
624 char *s;
625 int quoted, allow_all, *rtype;
626 {
627 int len;
628 arrayind_t ind;
629 char *retval, *t, *temp;
630 WORD_LIST *l;
631 SHELL_VAR *var;
632
633 var = array_variable_part (s, &t, &len);
634
635 /* Expand the index, even if the variable doesn't exist, in case side
636 effects are needed, like ${w[i++]} where w is unset. */
637 #if 0
638 if (var == 0)
639 return (char *)NULL;
640 #endif
641
642 if (len == 0)
643 return ((char *)NULL); /* error message already printed */
644
645 /* [ */
646 if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
647 {
648 if (rtype)
649 *rtype = 1;
650 if (allow_all == 0)
651 {
652 err_badarraysub (s);
653 return ((char *)NULL);
654 }
655 else if (var == 0)
656 return ((char *)NULL);
657 else if (array_p (var) == 0)
658 l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL);
659 else
660 {
661 l = array_to_word_list (array_cell (var));
662 if (l == (WORD_LIST *)NULL)
663 return ((char *) NULL);
664 }
665
666 if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
667 {
668 temp = string_list_dollar_star (l);
669 retval = quote_string (temp);
670 free (temp);
671 }
672 else /* ${name[@]} or unquoted ${name[*]} */
673 retval = string_list_dollar_at (l, quoted);
674
675 dispose_words (l);
676 }
677 else
678 {
679 if (rtype)
680 *rtype = 0;
681 ind = array_expand_index (t, len);
682 if (ind < 0)
683 {
684 if (var)
685 err_badarraysub (var->name);
686 else
687 {
688 t[-1] = '\0';
689 err_badarraysub (s);
690 t[-1] = '['; /* ] */
691 }
692 return ((char *)NULL);
693 }
694 if (var == 0)
695 return ((char *)NULL);
696 if (array_p (var) == 0)
697 return (ind == 0 ? value_cell (var) : (char *)NULL);
698 retval = array_reference (array_cell (var), ind);
699 }
700
701 return retval;
702 }
703
704 /* Return a string containing the elements described by the array and
705 subscript contained in S, obeying quoting for subscripts * and @. */
706 char *
707 array_value (s, quoted, rtype)
708 char *s;
709 int quoted, *rtype;
710 {
711 return (array_value_internal (s, quoted, 1, rtype));
712 }
713
714 /* Return the value of the array indexing expression S as a single string.
715 If ALLOW_ALL is 0, do not allow `@' and `*' subscripts. This is used
716 by other parts of the shell such as the arithmetic expression evaluator
717 in expr.c. */
718 char *
719 get_array_value (s, allow_all, rtype)
720 char *s;
721 int allow_all, *rtype;
722 {
723 return (array_value_internal (s, 0, allow_all, rtype));
724 }
725
726 char *
727 array_keys (s, quoted)
728 char *s;
729 int quoted;
730 {
731 int len;
732 char *retval, *t, *temp;
733 WORD_LIST *l;
734 SHELL_VAR *var;
735
736 var = array_variable_part (s, &t, &len);
737
738 /* [ */
739 if (var == 0 || ALL_ELEMENT_SUB (t[0]) == 0 || t[1] != ']')
740 return (char *)NULL;
741
742 if (array_p (var) == 0)
743 l = add_string_to_list ("0", (WORD_LIST *)NULL);
744 else
745 {
746 l = array_keys_to_word_list (array_cell (var));
747 if (l == (WORD_LIST *)NULL)
748 return ((char *) NULL);
749 }
750
751 if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
752 {
753 temp = string_list_dollar_star (l);
754 retval = quote_string (temp);
755 free (temp);
756 }
757 else /* ${!name[@]} or unquoted ${!name[*]} */
758 retval = string_list_dollar_at (l, quoted);
759
760 dispose_words (l);
761 return retval;
762 }
763 #endif /* ARRAY_VARS */