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