0d644b121f6cecaadd1d603c21a2cf07acca1e0f
[platform/upstream/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 */