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