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