~ubuntu-branches/ubuntu/trusty/bash/trusty-security

« back to all changes in this revision

Viewing changes to arrayfunc.c

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2014-03-03 22:52:05 UTC
  • mfrom: (1.3.5) (2.2.6 experimental)
  • Revision ID: package-import@ubuntu.com-20140303225205-87ltrt5kspeq0g1b
Tags: 4.3-1ubuntu1
* Merge with Debian; remaining changes:
  - skel.bashrc:
    - Run lesspipe.
    - Enable ls aliases.
    - Set options in ll alias to -alF.
    - Define an alert alias.
    - Enabled colored grep aliases.
  - etc.bash.bashrc:
    - Add sudo hint.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* arrayfunc.c -- High-level array functions used by other parts of the shell. */
 
2
 
 
3
/* Copyright (C) 2001-2011 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
 
8
   it under the terms of the GNU General Public License as published by
 
9
   the Free Software Foundation, either version 3 of the License, or
 
10
   (at your option) any later version.
 
11
 
 
12
   Bash is distributed in the hope that it will be useful,
 
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
   GNU General Public License for more details.
 
16
 
 
17
   You should have received a copy of the GNU General Public License
 
18
   along with Bash.  If not, see <http://www.gnu.org/licenses/>.
 
19
*/
 
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
#include "pathexp.h"
 
34
 
 
35
#include "shmbutil.h"
 
36
 
 
37
#include "builtins/common.h"
 
38
 
 
39
extern char *this_command_name;
 
40
extern int last_command_exit_value;
 
41
extern int array_needs_making;
 
42
 
 
43
static SHELL_VAR *bind_array_var_internal __P((SHELL_VAR *, arrayind_t, char *, char *, int));
 
44
static SHELL_VAR *assign_array_element_internal __P((SHELL_VAR *, char *, char *, char *, int, char *, int));
 
45
 
 
46
static char *quote_assign __P((const char *));
 
47
static void quote_array_assignment_chars __P((WORD_LIST *));
 
48
static char *array_value_internal __P((char *, int, int, int *, arrayind_t *));
 
49
 
 
50
/* Standard error message to use when encountering an invalid array subscript */
 
51
const char * const bash_badsub_errmsg = N_("bad array subscript");
 
52
 
 
53
/* **************************************************************** */
 
54
/*                                                                  */
 
55
/*  Functions to manipulate array variables and perform assignments */
 
56
/*                                                                  */
 
57
/* **************************************************************** */
 
58
 
 
59
/* Convert a shell variable to an array variable.  The original value is
 
60
   saved as array[0]. */
 
61
SHELL_VAR *
 
62
convert_var_to_array (var)
 
63
     SHELL_VAR *var;
 
64
{
 
65
  char *oldval;
 
66
  ARRAY *array;
 
67
 
 
68
  oldval = value_cell (var);
 
69
  array = array_create ();
 
70
  if (oldval)
 
71
    array_insert (array, 0, oldval);
 
72
 
 
73
  FREE (value_cell (var));
 
74
  var_setarray (var, array);
 
75
 
 
76
  /* these aren't valid anymore */
 
77
  var->dynamic_value = (sh_var_value_func_t *)NULL;
 
78
  var->assign_func = (sh_var_assign_func_t *)NULL;
 
79
 
 
80
  INVALIDATE_EXPORTSTR (var);
 
81
  if (exported_p (var))
 
82
    array_needs_making++;
 
83
 
 
84
  VSETATTR (var, att_array);
 
85
  VUNSETATTR (var, att_invisible);
 
86
 
 
87
  return var;
 
88
}
 
89
 
 
90
/* Convert a shell variable to an array variable.  The original value is
 
91
   saved as array[0]. */
 
92
SHELL_VAR *
 
93
convert_var_to_assoc (var)
 
94
     SHELL_VAR *var;
 
95
{
 
96
  char *oldval;
 
97
  HASH_TABLE *hash;
 
98
 
 
99
  oldval = value_cell (var);
 
100
  hash = assoc_create (0);
 
101
  if (oldval)
 
102
    assoc_insert (hash, savestring ("0"), oldval);
 
103
 
 
104
  FREE (value_cell (var));
 
105
  var_setassoc (var, hash);
 
106
 
 
107
  /* these aren't valid anymore */
 
108
  var->dynamic_value = (sh_var_value_func_t *)NULL;
 
109
  var->assign_func = (sh_var_assign_func_t *)NULL;
 
110
 
 
111
  INVALIDATE_EXPORTSTR (var);
 
112
  if (exported_p (var))
 
113
    array_needs_making++;
 
114
 
 
115
  VSETATTR (var, att_assoc);
 
116
  VUNSETATTR (var, att_invisible);
 
117
 
 
118
  return var;
 
119
}
 
120
 
 
121
char *
 
122
make_array_variable_value (entry, ind, key, value, flags)
 
123
     SHELL_VAR *entry;
 
124
     arrayind_t ind;
 
125
     char *key;
 
126
     char *value;
 
127
     int flags;
 
128
{
 
129
  SHELL_VAR *dentry;
 
130
  char *newval;
 
131
 
 
132
  /* If we're appending, we need the old value of the array reference, so
 
133
     fake out make_variable_value with a dummy SHELL_VAR */
 
134
  if (flags & ASS_APPEND)
 
135
    {
 
136
      dentry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
 
137
      dentry->name = savestring (entry->name);
 
138
      if (assoc_p (entry))
 
139
        newval = assoc_reference (assoc_cell (entry), key);
 
140
      else
 
141
        newval = array_reference (array_cell (entry), ind);
 
142
      if (newval)
 
143
        dentry->value = savestring (newval);
 
144
      else
 
145
        {
 
146
          dentry->value = (char *)xmalloc (1);
 
147
          dentry->value[0] = '\0';
 
148
        }
 
149
      dentry->exportstr = 0;
 
150
      dentry->attributes = entry->attributes & ~(att_array|att_assoc|att_exported);
 
151
      /* Leave the rest of the members uninitialized; the code doesn't look
 
152
         at them. */
 
153
      newval = make_variable_value (dentry, value, flags);       
 
154
      dispose_variable (dentry);
 
155
    }
 
156
  else
 
157
    newval = make_variable_value (entry, value, flags);
 
158
 
 
159
  return newval;
 
160
}
 
161
  
 
162
static SHELL_VAR *
 
163
bind_array_var_internal (entry, ind, key, value, flags)
 
164
     SHELL_VAR *entry;
 
165
     arrayind_t ind;
 
166
     char *key;
 
167
     char *value;
 
168
     int flags;
 
169
{
 
170
  char *newval;
 
171
 
 
172
  newval = make_array_variable_value (entry, ind, key, value, flags);
 
173
 
 
174
  if (entry->assign_func)
 
175
    (*entry->assign_func) (entry, newval, ind, key);
 
176
  else if (assoc_p (entry))
 
177
    assoc_insert (assoc_cell (entry), key, newval);
 
178
  else
 
179
    array_insert (array_cell (entry), ind, newval);
 
180
  FREE (newval);
 
181
 
 
182
  return (entry);
 
183
}
 
184
 
 
185
/* Perform an array assignment name[ind]=value.  If NAME already exists and
 
186
   is not an array, and IND is 0, perform name=value instead.  If NAME exists
 
187
   and is not an array, and IND is not 0, convert it into an array with the
 
188
   existing value as name[0].
 
189
 
 
190
   If NAME does not exist, just create an array variable, no matter what
 
191
   IND's value may be. */
 
192
SHELL_VAR *
 
193
bind_array_variable (name, ind, value, flags)
 
194
     char *name;
 
195
     arrayind_t ind;
 
196
     char *value;
 
197
     int flags;
 
198
{
 
199
  SHELL_VAR *entry;
 
200
 
 
201
  entry = find_shell_variable (name);
 
202
 
 
203
  if (entry == (SHELL_VAR *) 0)
 
204
    entry = make_new_array_variable (name);
 
205
  else if (readonly_p (entry) || noassign_p (entry))
 
206
    {
 
207
      if (readonly_p (entry))
 
208
        err_readonly (name);
 
209
      return (entry);
 
210
    }
 
211
  else if (array_p (entry) == 0)
 
212
    entry = convert_var_to_array (entry);
 
213
 
 
214
  /* ENTRY is an array variable, and ARRAY points to the value. */
 
215
  return (bind_array_var_internal (entry, ind, 0, value, flags));
 
216
}
 
217
 
 
218
SHELL_VAR *
 
219
bind_array_element (entry, ind, value, flags)
 
220
     SHELL_VAR *entry;
 
221
     arrayind_t ind;
 
222
     char *value;
 
223
     int flags;
 
224
{
 
225
  return (bind_array_var_internal (entry, ind, 0, value, flags));
 
226
}
 
227
                    
 
228
SHELL_VAR *
 
229
bind_assoc_variable (entry, name, key, value, flags)
 
230
     SHELL_VAR *entry;
 
231
     char *name;
 
232
     char *key;
 
233
     char *value;
 
234
     int flags;
 
235
{
 
236
  SHELL_VAR *dentry;
 
237
  char *newval;
 
238
 
 
239
  if (readonly_p (entry) || noassign_p (entry))
 
240
    {
 
241
      if (readonly_p (entry))
 
242
        err_readonly (name);
 
243
      return (entry);
 
244
    }
 
245
 
 
246
  return (bind_array_var_internal (entry, 0, key, value, flags));
 
247
}
 
248
 
 
249
/* Parse NAME, a lhs of an assignment statement of the form v[s], and
 
250
   assign VALUE to that array element by calling bind_array_variable(). */
 
251
SHELL_VAR *
 
252
assign_array_element (name, value, flags)
 
253
     char *name, *value;
 
254
     int flags;
 
255
{
 
256
  char *sub, *vname;
 
257
  int sublen;
 
258
  SHELL_VAR *entry;
 
259
 
 
260
  vname = array_variable_name (name, &sub, &sublen);
 
261
 
 
262
  if (vname == 0)
 
263
    return ((SHELL_VAR *)NULL);
 
264
 
 
265
  if ((ALL_ELEMENT_SUB (sub[0]) && sub[1] == ']') || (sublen <= 1))
 
266
    {
 
267
      free (vname);
 
268
      err_badarraysub (name);
 
269
      return ((SHELL_VAR *)NULL);
 
270
    }
 
271
 
 
272
  entry = find_variable (vname);
 
273
  entry = assign_array_element_internal (entry, name, vname, sub, sublen, value, flags);
 
274
 
 
275
  free (vname);
 
276
  return entry;
 
277
}
 
278
 
 
279
static SHELL_VAR *
 
280
assign_array_element_internal (entry, name, vname, sub, sublen, value, flags)
 
281
     SHELL_VAR *entry;
 
282
     char *name;                /* only used for error messages */
 
283
     char *vname;
 
284
     char *sub;
 
285
     int sublen;
 
286
     char *value;
 
287
     int flags;
 
288
{
 
289
  char *akey;
 
290
  arrayind_t ind;
 
291
 
 
292
  if (entry && assoc_p (entry))
 
293
    {
 
294
      sub[sublen-1] = '\0';
 
295
      akey = expand_assignment_string_to_string (sub, 0);       /* [ */
 
296
      sub[sublen-1] = ']';
 
297
      if (akey == 0 || *akey == 0)
 
298
        {
 
299
          err_badarraysub (name);
 
300
          FREE (akey);
 
301
          return ((SHELL_VAR *)NULL);
 
302
        }
 
303
      entry = bind_assoc_variable (entry, vname, akey, value, flags);
 
304
    }
 
305
  else
 
306
    {
 
307
      ind = array_expand_index (entry, sub, sublen);
 
308
      /* negative subscripts to indexed arrays count back from end */
 
309
      if (entry && ind < 0)
 
310
        ind = (array_p (entry) ? array_max_index (array_cell (entry)) : 0) + 1 + ind;
 
311
      if (ind < 0)
 
312
        {
 
313
          err_badarraysub (name);
 
314
          return ((SHELL_VAR *)NULL);
 
315
        }
 
316
      entry = bind_array_variable (vname, ind, value, flags);
 
317
    }
 
318
 
 
319
  return (entry);
 
320
}
 
321
 
 
322
/* Find the array variable corresponding to NAME.  If there is no variable,
 
323
   create a new array variable.  If the variable exists but is not an array,
 
324
   convert it to an indexed array.  If FLAGS&1 is non-zero, an existing
 
325
   variable is checked for the readonly or noassign attribute in preparation
 
326
   for assignment (e.g., by the `read' builtin).  If FLAGS&2 is non-zero, we
 
327
   create an associative array. */
 
328
SHELL_VAR *
 
329
find_or_make_array_variable (name, flags)
 
330
     char *name;
 
331
     int flags;
 
332
{
 
333
  SHELL_VAR *var;
 
334
 
 
335
  var = find_variable (name);
 
336
  if (var == 0)
 
337
    {
 
338
      /* See if we have a nameref pointing to a variable that hasn't been
 
339
         created yet. */
 
340
      var = find_variable_last_nameref (name);
 
341
      if (var && nameref_p (var))
 
342
        var = (flags & 2) ? make_new_assoc_variable (nameref_cell (var)) : make_new_array_variable (nameref_cell (var));
 
343
    }
 
344
 
 
345
  if (var == 0)
 
346
    var = (flags & 2) ? make_new_assoc_variable (name) : make_new_array_variable (name);
 
347
  else if ((flags & 1) && (readonly_p (var) || noassign_p (var)))
 
348
    {
 
349
      if (readonly_p (var))
 
350
        err_readonly (name);
 
351
      return ((SHELL_VAR *)NULL);
 
352
    }
 
353
  else if ((flags & 2) && array_p (var))
 
354
    {
 
355
      last_command_exit_value = 1;
 
356
      report_error (_("%s: cannot convert indexed to associative array"), name);
 
357
      return ((SHELL_VAR *)NULL);
 
358
    }
 
359
  else if (array_p (var) == 0 && assoc_p (var) == 0)
 
360
    var = convert_var_to_array (var);
 
361
 
 
362
  return (var);
 
363
}
 
364
  
 
365
/* Perform a compound assignment statement for array NAME, where VALUE is
 
366
   the text between the parens:  NAME=( VALUE ) */
 
367
SHELL_VAR *
 
368
assign_array_from_string (name, value, flags)
 
369
     char *name, *value;
 
370
     int flags;
 
371
{
 
372
  SHELL_VAR *var;
 
373
  int vflags;
 
374
 
 
375
  vflags = 1;
 
376
  if (flags & ASS_MKASSOC)
 
377
    vflags |= 2;
 
378
 
 
379
  var = find_or_make_array_variable (name, vflags);
 
380
  if (var == 0)
 
381
    return ((SHELL_VAR *)NULL);
 
382
 
 
383
  return (assign_array_var_from_string (var, value, flags));
 
384
}
 
385
 
 
386
/* Sequentially assign the indices of indexed array variable VAR from the
 
387
   words in LIST. */
 
388
SHELL_VAR *
 
389
assign_array_var_from_word_list (var, list, flags)
 
390
     SHELL_VAR *var;
 
391
     WORD_LIST *list;
 
392
     int flags;
 
393
{
 
394
  register arrayind_t i;
 
395
  register WORD_LIST *l;
 
396
  ARRAY *a;
 
397
 
 
398
  a = array_cell (var);
 
399
  i = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0;
 
400
 
 
401
  for (l = list; l; l = l->next, i++)
 
402
    if (var->assign_func)
 
403
      (*var->assign_func) (var, l->word->word, i, 0);
 
404
    else
 
405
      array_insert (a, i, l->word->word);
 
406
  return var;
 
407
}
 
408
 
 
409
WORD_LIST *
 
410
expand_compound_array_assignment (var, value, flags)
 
411
     SHELL_VAR *var;
 
412
     char *value;
 
413
     int flags;
 
414
{
 
415
  WORD_LIST *list, *nlist;
 
416
  WORD_LIST *hd, *tl, *t, *n;
 
417
  char *val;
 
418
  int ni;
 
419
 
 
420
  /* This condition is true when invoked from the declare builtin with a
 
421
     command like
 
422
        declare -a d='([1]="" [2]="bdef" [5]="hello world" "test")' */
 
423
  if (*value == '(')    /*)*/
 
424
    {
 
425
      ni = 1;
 
426
      val = extract_array_assignment_list (value, &ni);
 
427
      if (val == 0)
 
428
        return (WORD_LIST *)NULL;
 
429
    }
 
430
  else
 
431
    val = value;
 
432
 
 
433
  /* Expand the value string into a list of words, performing all the
 
434
     shell expansions including pathname generation and word splitting. */
 
435
  /* First we split the string on whitespace, using the shell parser
 
436
     (ksh93 seems to do this). */
 
437
  list = parse_string_to_word_list (val, 1, "array assign");
 
438
 
 
439
  if (var && assoc_p (var))
 
440
    {
 
441
      if (val != value)
 
442
        free (val);
 
443
      return list;
 
444
    }
 
445
 
 
446
  /* If we're using [subscript]=value, we need to quote each [ and ] to
 
447
     prevent unwanted filename expansion.  This doesn't need to be done
 
448
     for associative array expansion, since that uses a different expansion
 
449
     function (see assign_compound_array_list below). */
 
450
  if (list)
 
451
    quote_array_assignment_chars (list);
 
452
 
 
453
  /* Now that we've split it, perform the shell expansions on each
 
454
     word in the list. */
 
455
  nlist = list ? expand_words_no_vars (list) : (WORD_LIST *)NULL;
 
456
 
 
457
  dispose_words (list);
 
458
 
 
459
  if (val != value)
 
460
    free (val);
 
461
 
 
462
  return nlist;
 
463
}
 
464
 
 
465
/* Callers ensure that VAR is not NULL */
 
466
void
 
467
assign_compound_array_list (var, nlist, flags)
 
468
     SHELL_VAR *var;
 
469
     WORD_LIST *nlist;
 
470
     int flags;
 
471
{
 
472
  ARRAY *a;
 
473
  HASH_TABLE *h;
 
474
  WORD_LIST *list;
 
475
  char *w, *val, *nval;
 
476
  int len, iflags, free_val;
 
477
  arrayind_t ind, last_ind;
 
478
  char *akey;
 
479
 
 
480
  a = (var && array_p (var)) ? array_cell (var) : (ARRAY *)0;
 
481
  h = (var && assoc_p (var)) ? assoc_cell (var) : (HASH_TABLE *)0;
 
482
 
 
483
  akey = (char *)0;
 
484
  ind = 0;
 
485
 
 
486
  /* Now that we are ready to assign values to the array, kill the existing
 
487
     value. */
 
488
  if ((flags & ASS_APPEND) == 0)
 
489
    {
 
490
      if (a && array_p (var))
 
491
        array_flush (a);
 
492
      else if (h && assoc_p (var))
 
493
        assoc_flush (h);
 
494
    }
 
495
 
 
496
  last_ind = (a && (flags & ASS_APPEND)) ? array_max_index (a) + 1 : 0;
 
497
 
 
498
  for (list = nlist; list; list = list->next)
 
499
    {
 
500
      iflags = flags;
 
501
      w = list->word->word;
 
502
 
 
503
      /* We have a word of the form [ind]=value */
 
504
      if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[')
 
505
        {
 
506
          /* Don't have to handle embedded quotes specially any more, since
 
507
             associative array subscripts have not been expanded yet (see
 
508
             above). */
 
509
          len = skipsubscript (w, 0, 0);
 
510
 
 
511
          /* XXX - changes for `+=' */
 
512
          if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
 
513
            {
 
514
              if (assoc_p (var))
 
515
                {
 
516
                  err_badarraysub (w);
 
517
                  continue;
 
518
                }
 
519
              nval = make_variable_value (var, w, flags);
 
520
              if (var->assign_func)
 
521
                (*var->assign_func) (var, nval, last_ind, 0);
 
522
              else
 
523
                array_insert (a, last_ind, nval);
 
524
              FREE (nval);
 
525
              last_ind++;
 
526
              continue;
 
527
            }
 
528
 
 
529
          if (len == 1)
 
530
            {
 
531
              err_badarraysub (w);
 
532
              continue;
 
533
            }
 
534
 
 
535
          if (ALL_ELEMENT_SUB (w[1]) && len == 2)
 
536
            {
 
537
              last_command_exit_value = 1;
 
538
              if (assoc_p (var))
 
539
                report_error (_("%s: invalid associative array key"), w);
 
540
              else
 
541
                report_error (_("%s: cannot assign to non-numeric index"), w);
 
542
              continue;
 
543
            }
 
544
 
 
545
          if (array_p (var))
 
546
            {
 
547
              ind = array_expand_index (var, w + 1, len);
 
548
              /* negative subscripts to indexed arrays count back from end */
 
549
              if (ind < 0)
 
550
                ind = array_max_index (array_cell (var)) + 1 + ind;
 
551
              if (ind < 0)
 
552
                {
 
553
                  err_badarraysub (w);
 
554
                  continue;
 
555
                }
 
556
 
 
557
              last_ind = ind;
 
558
            }
 
559
          else if (assoc_p (var))
 
560
            {
 
561
              /* This is not performed above, see expand_compound_array_assignment */
 
562
              w[len] = '\0';    /*[*/
 
563
              akey = expand_assignment_string_to_string (w+1, 0);
 
564
              w[len] = ']';
 
565
              /* And we need to expand the value also, see below */
 
566
              if (akey == 0 || *akey == 0)
 
567
                {
 
568
                  err_badarraysub (w);
 
569
                  FREE (akey);
 
570
                  continue;
 
571
                }
 
572
            }
 
573
 
 
574
          /* XXX - changes for `+=' -- just accept the syntax.  ksh93 doesn't do this */
 
575
          if (w[len + 1] == '+' && w[len + 2] == '=')
 
576
            {
 
577
              iflags |= ASS_APPEND;
 
578
              val = w + len + 3;
 
579
            }
 
580
          else
 
581
            val = w + len + 2;      
 
582
        }
 
583
      else if (assoc_p (var))
 
584
        {
 
585
          last_command_exit_value = 1;
 
586
          report_error (_("%s: %s: must use subscript when assigning associative array"), var->name, w);
 
587
          continue;
 
588
        }
 
589
      else              /* No [ind]=value, just a stray `=' */
 
590
        {
 
591
          ind = last_ind;
 
592
          val = w;
 
593
        }
 
594
 
 
595
      free_val = 0;
 
596
      /* See above; we need to expand the value here */
 
597
      if (assoc_p (var))
 
598
        {
 
599
          val = expand_assignment_string_to_string (val, 0);
 
600
          free_val = 1;
 
601
        }
 
602
 
 
603
      if (integer_p (var))
 
604
        this_command_name = (char *)NULL;       /* no command name for errors */
 
605
      bind_array_var_internal (var, ind, akey, val, iflags);
 
606
      last_ind++;
 
607
 
 
608
      if (free_val)
 
609
        free (val);
 
610
    }
 
611
}
 
612
 
 
613
/* Perform a compound array assignment:  VAR->name=( VALUE ).  The
 
614
   VALUE has already had the parentheses stripped. */
 
615
SHELL_VAR *
 
616
assign_array_var_from_string (var, value, flags)
 
617
     SHELL_VAR *var;
 
618
     char *value;
 
619
     int flags;
 
620
{
 
621
  WORD_LIST *nlist;
 
622
 
 
623
  if (value == 0)
 
624
    return var;
 
625
 
 
626
  nlist = expand_compound_array_assignment (var, value, flags);
 
627
  assign_compound_array_list (var, nlist, flags);
 
628
 
 
629
  if (nlist)
 
630
    dispose_words (nlist);
 
631
  return (var);
 
632
}
 
633
 
 
634
/* Quote globbing chars and characters in $IFS before the `=' in an assignment
 
635
   statement (usually a compound array assignment) to protect them from
 
636
   unwanted filename expansion or word splitting. */
 
637
static char *
 
638
quote_assign (string)
 
639
     const char *string;
 
640
{
 
641
  size_t slen;
 
642
  int saw_eq;
 
643
  char *temp, *t, *subs;
 
644
  const char *s, *send;
 
645
  int ss, se;
 
646
  DECLARE_MBSTATE;
 
647
 
 
648
  slen = strlen (string);
 
649
  send = string + slen;
 
650
 
 
651
  t = temp = (char *)xmalloc (slen * 2 + 1);
 
652
  saw_eq = 0;
 
653
  for (s = string; *s; )
 
654
    {
 
655
      if (*s == '=')
 
656
        saw_eq = 1;
 
657
      if (saw_eq == 0 && *s == '[')             /* looks like a subscript */
 
658
        {
 
659
          ss = s - string;
 
660
          se = skipsubscript (string, ss, 0);
 
661
          subs = substring (s, ss, se);
 
662
          *t++ = '\\';
 
663
          strcpy (t, subs);
 
664
          t += se - ss;
 
665
          *t++ = '\\';
 
666
          *t++ = ']';
 
667
          s += se + 1;
 
668
          free (subs);
 
669
          continue;
 
670
        }
 
671
      if (saw_eq == 0 && (glob_char_p (s) || isifs (*s)))
 
672
        *t++ = '\\';
 
673
 
 
674
      COPY_CHAR_P (t, s, send);
 
675
    }
 
676
  *t = '\0';
 
677
  return temp;
 
678
}
 
679
 
 
680
/* For each word in a compound array assignment, if the word looks like
 
681
   [ind]=value, quote globbing chars and characters in $IFS before the `='. */
 
682
static void
 
683
quote_array_assignment_chars (list)
 
684
     WORD_LIST *list;
 
685
{
 
686
  char *nword;
 
687
  WORD_LIST *l;
 
688
 
 
689
  for (l = list; l; l = l->next)
 
690
    {
 
691
      if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0')
 
692
        continue;       /* should not happen, but just in case... */
 
693
      /* Don't bother if it hasn't been recognized as an assignment or
 
694
         doesn't look like [ind]=value */
 
695
      if ((l->word->flags & W_ASSIGNMENT) == 0)
 
696
        continue;
 
697
      if (l->word->word[0] != '[' || mbschr (l->word->word, '=') == 0) /* ] */
 
698
        continue;
 
699
 
 
700
      nword = quote_assign (l->word->word);
 
701
      free (l->word->word);
 
702
      l->word->word = nword;
 
703
      l->word->flags |= W_NOGLOB;       /* XXX - W_NOSPLIT also? */
 
704
    }
 
705
}
 
706
 
 
707
/* skipsubscript moved to subst.c to use private functions. 2009/02/24. */
 
708
 
 
709
/* This function is called with SUB pointing to just after the beginning
 
710
   `[' of an array subscript and removes the array element to which SUB
 
711
   expands from array VAR.  A subscript of `*' or `@' unsets the array. */
 
712
int
 
713
unbind_array_element (var, sub)
 
714
     SHELL_VAR *var;
 
715
     char *sub;
 
716
{
 
717
  int len;
 
718
  arrayind_t ind;
 
719
  char *akey;
 
720
  ARRAY_ELEMENT *ae;
 
721
 
 
722
  len = skipsubscript (sub, 0, 0);
 
723
  if (sub[len] != ']' || len == 0)
 
724
    {
 
725
      builtin_error ("%s[%s: %s", var->name, sub, _(bash_badsub_errmsg));
 
726
      return -1;
 
727
    }
 
728
  sub[len] = '\0';
 
729
 
 
730
  if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0)
 
731
    {
 
732
      unbind_variable (var->name);
 
733
      return (0);
 
734
    }
 
735
 
 
736
  if (assoc_p (var))
 
737
    {
 
738
      akey = expand_assignment_string_to_string (sub, 0);     /* [ */
 
739
      if (akey == 0 || *akey == 0)
 
740
        {
 
741
          builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
 
742
          FREE (akey);
 
743
          return -1;
 
744
        }
 
745
      assoc_remove (assoc_cell (var), akey);
 
746
      free (akey);
 
747
    }
 
748
  else
 
749
    {
 
750
      ind = array_expand_index (var, sub, len+1);
 
751
      /* negative subscripts to indexed arrays count back from end */
 
752
      if (ind < 0)
 
753
        ind = array_max_index (array_cell (var)) + 1 + ind;
 
754
      if (ind < 0)
 
755
        {
 
756
          builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
 
757
          return -1;
 
758
        }
 
759
      ae = array_remove (array_cell (var), ind);
 
760
      if (ae)
 
761
        array_dispose_element (ae);
 
762
    }
 
763
 
 
764
  return 0;
 
765
}
 
766
 
 
767
/* Format and output an array assignment in compound form VAR=(VALUES),
 
768
   suitable for re-use as input. */
 
769
void
 
770
print_array_assignment (var, quoted)
 
771
     SHELL_VAR *var;
 
772
     int quoted;
 
773
{
 
774
  char *vstr;
 
775
 
 
776
  vstr = array_to_assign (array_cell (var), quoted);
 
777
 
 
778
  if (vstr == 0)
 
779
    printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
 
780
  else
 
781
    {
 
782
      printf ("%s=%s\n", var->name, vstr);
 
783
      free (vstr);
 
784
    }
 
785
}
 
786
 
 
787
/* Format and output an associative array assignment in compound form
 
788
   VAR=(VALUES), suitable for re-use as input. */
 
789
void
 
790
print_assoc_assignment (var, quoted)
 
791
     SHELL_VAR *var;
 
792
     int quoted;
 
793
{
 
794
  char *vstr;
 
795
 
 
796
  vstr = assoc_to_assign (assoc_cell (var), quoted);
 
797
 
 
798
  if (vstr == 0)
 
799
    printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
 
800
  else
 
801
    {
 
802
      printf ("%s=%s\n", var->name, vstr);
 
803
      free (vstr);
 
804
    }
 
805
}
 
806
 
 
807
/***********************************************************************/
 
808
/*                                                                     */
 
809
/* Utility functions to manage arrays and their contents for expansion */
 
810
/*                                                                     */
 
811
/***********************************************************************/
 
812
 
 
813
/* Return 1 if NAME is a properly-formed array reference v[sub]. */
 
814
int
 
815
valid_array_reference (name)
 
816
     char *name;
 
817
{
 
818
  char *t;
 
819
  int r, len;
 
820
 
 
821
  t = mbschr (name, '[');       /* ] */
 
822
  if (t)
 
823
    {
 
824
      *t = '\0';
 
825
      r = legal_identifier (name);
 
826
      *t = '[';
 
827
      if (r == 0)
 
828
        return 0;
 
829
      /* Check for a properly-terminated non-blank subscript. */
 
830
      len = skipsubscript (t, 0, 0);
 
831
      if (t[len] != ']' || len == 1)
 
832
        return 0;
 
833
      for (r = 1; r < len; r++)
 
834
        if (whitespace (t[r]) == 0)
 
835
          return 1;
 
836
      return 0;
 
837
    }
 
838
  return 0;
 
839
}
 
840
 
 
841
/* Expand the array index beginning at S and extending LEN characters. */
 
842
arrayind_t
 
843
array_expand_index (var, s, len)
 
844
     SHELL_VAR *var;
 
845
     char *s;
 
846
     int len;
 
847
{
 
848
  char *exp, *t;
 
849
  int expok;
 
850
  arrayind_t val;
 
851
 
 
852
  exp = (char *)xmalloc (len);
 
853
  strncpy (exp, s, len - 1);
 
854
  exp[len - 1] = '\0';
 
855
  t = expand_arith_string (exp, 0);
 
856
  this_command_name = (char *)NULL;
 
857
  val = evalexp (t, &expok);
 
858
  free (t);
 
859
  free (exp);
 
860
  if (expok == 0)
 
861
    {
 
862
      last_command_exit_value = EXECUTION_FAILURE;
 
863
 
 
864
      top_level_cleanup ();      
 
865
      jump_to_top_level (DISCARD);
 
866
    }
 
867
  return val;
 
868
}
 
869
 
 
870
/* Return the name of the variable specified by S without any subscript.
 
871
   If SUBP is non-null, return a pointer to the start of the subscript
 
872
   in *SUBP. If LENP is non-null, the length of the subscript is returned
 
873
   in *LENP.  This returns newly-allocated memory. */
 
874
char *
 
875
array_variable_name (s, subp, lenp)
 
876
     char *s, **subp;
 
877
     int *lenp;
 
878
{
 
879
  char *t, *ret;
 
880
  int ind, ni;
 
881
 
 
882
  t = mbschr (s, '[');
 
883
  if (t == 0)
 
884
    {
 
885
      if (subp)
 
886
        *subp = t;
 
887
      if (lenp)
 
888
        *lenp = 0;
 
889
      return ((char *)NULL);
 
890
    }
 
891
  ind = t - s;
 
892
  ni = skipsubscript (s, ind, 0);
 
893
  if (ni <= ind + 1 || s[ni] != ']')
 
894
    {
 
895
      err_badarraysub (s);
 
896
      if (subp)
 
897
        *subp = t;
 
898
      if (lenp)
 
899
        *lenp = 0;
 
900
      return ((char *)NULL);
 
901
    }
 
902
 
 
903
  *t = '\0';
 
904
  ret = savestring (s);
 
905
  *t++ = '[';           /* ] */
 
906
 
 
907
  if (subp)
 
908
    *subp = t;
 
909
  if (lenp)
 
910
    *lenp = ni - ind;
 
911
 
 
912
  return ret;
 
913
}
 
914
 
 
915
/* Return the variable specified by S without any subscript.  If SUBP is
 
916
   non-null, return a pointer to the start of the subscript in *SUBP.
 
917
   If LENP is non-null, the length of the subscript is returned in *LENP. */
 
918
SHELL_VAR *
 
919
array_variable_part (s, subp, lenp)
 
920
     char *s, **subp;
 
921
     int *lenp;
 
922
{
 
923
  char *t;
 
924
  SHELL_VAR *var;
 
925
 
 
926
  t = array_variable_name (s, subp, lenp);
 
927
  if (t == 0)
 
928
    return ((SHELL_VAR *)NULL);
 
929
  var = find_variable (t);
 
930
 
 
931
  free (t);
 
932
#if 0
 
933
  return (var == 0 || invisible_p (var)) ? (SHELL_VAR *)0 : var;
 
934
#else
 
935
  return var;   /* now return invisible variables; caller must handle */
 
936
#endif
 
937
}
 
938
 
 
939
#define INDEX_ERROR() \
 
940
  do \
 
941
    { \
 
942
      if (var) \
 
943
        err_badarraysub (var->name); \
 
944
      else \
 
945
        { \
 
946
          t[-1] = '\0'; \
 
947
          err_badarraysub (s); \
 
948
          t[-1] = '[';  /* ] */\
 
949
        } \
 
950
      return ((char *)NULL); \
 
951
    } \
 
952
  while (0)
 
953
 
 
954
/* Return a string containing the elements in the array and subscript
 
955
   described by S.  If the subscript is * or @, obeys quoting rules akin
 
956
   to the expansion of $* and $@ including double quoting.  If RTYPE
 
957
   is non-null it gets 1 if the array reference is name[*], 2 if the
 
958
   reference is name[@], and 0 otherwise. */
 
959
static char *
 
960
array_value_internal (s, quoted, flags, rtype, indp)
 
961
     char *s;
 
962
     int quoted, flags, *rtype;
 
963
     arrayind_t *indp;
 
964
{
 
965
  int len;
 
966
  arrayind_t ind;
 
967
  char *akey;
 
968
  char *retval, *t, *temp;
 
969
  WORD_LIST *l;
 
970
  SHELL_VAR *var;
 
971
 
 
972
  var = array_variable_part (s, &t, &len);
 
973
 
 
974
  /* Expand the index, even if the variable doesn't exist, in case side
 
975
     effects are needed, like ${w[i++]} where w is unset. */
 
976
#if 0
 
977
  if (var == 0)
 
978
    return (char *)NULL;
 
979
#endif
 
980
 
 
981
  if (len == 0)
 
982
    return ((char *)NULL);      /* error message already printed */
 
983
 
 
984
  /* [ */
 
985
  akey = 0;
 
986
  if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
 
987
    {
 
988
      if (rtype)
 
989
        *rtype = (t[0] == '*') ? 1 : 2;
 
990
      if ((flags & AV_ALLOWALL) == 0)
 
991
        {
 
992
          err_badarraysub (s);
 
993
          return ((char *)NULL);
 
994
        }
 
995
      else if (var == 0 || value_cell (var) == 0)       /* XXX - check for invisible_p(var) ? */
 
996
        return ((char *)NULL);
 
997
      else if (array_p (var) == 0 && assoc_p (var) == 0)
 
998
        l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL);
 
999
      else if (assoc_p (var))
 
1000
        {
 
1001
          l = assoc_to_word_list (assoc_cell (var));
 
1002
          if (l == (WORD_LIST *)NULL)
 
1003
            return ((char *)NULL);
 
1004
        }
 
1005
      else
 
1006
        {
 
1007
          l = array_to_word_list (array_cell (var));
 
1008
          if (l == (WORD_LIST *)NULL)
 
1009
            return ((char *) NULL);
 
1010
        }
 
1011
 
 
1012
      if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
 
1013
        {
 
1014
          temp = string_list_dollar_star (l);
 
1015
          retval = quote_string (temp);         /* XXX - leak here */
 
1016
          free (temp);
 
1017
        }
 
1018
      else      /* ${name[@]} or unquoted ${name[*]} */
 
1019
        retval = string_list_dollar_at (l, quoted);     /* XXX - leak here */
 
1020
 
 
1021
      dispose_words (l);
 
1022
    }
 
1023
  else
 
1024
    {
 
1025
      if (rtype)
 
1026
        *rtype = 0;
 
1027
      if (var == 0 || array_p (var) || assoc_p (var) == 0)
 
1028
        {
 
1029
          if ((flags & AV_USEIND) == 0 || indp == 0)
 
1030
            {
 
1031
              ind = array_expand_index (var, t, len);
 
1032
              if (ind < 0)
 
1033
                {
 
1034
                  /* negative subscripts to indexed arrays count back from end */
 
1035
                  if (var && array_p (var))
 
1036
                    ind = array_max_index (array_cell (var)) + 1 + ind;
 
1037
                  if (ind < 0)
 
1038
                    INDEX_ERROR();
 
1039
                }
 
1040
              if (indp)
 
1041
                *indp = ind;
 
1042
            }
 
1043
          else if (indp)
 
1044
            ind = *indp;
 
1045
        }
 
1046
      else if (assoc_p (var))
 
1047
        {
 
1048
          t[len - 1] = '\0';
 
1049
          akey = expand_assignment_string_to_string (t, 0);     /* [ */
 
1050
          t[len - 1] = ']';
 
1051
          if (akey == 0 || *akey == 0)
 
1052
            {
 
1053
              FREE (akey);
 
1054
              INDEX_ERROR();
 
1055
            }
 
1056
        }
 
1057
     
 
1058
      if (var == 0 || value_cell (var) == 0)    /* XXX - check invisible_p(var) ? */
 
1059
        {
 
1060
          FREE (akey);
 
1061
          return ((char *)NULL);
 
1062
        }
 
1063
      if (array_p (var) == 0 && assoc_p (var) == 0)
 
1064
        return (ind == 0 ? value_cell (var) : (char *)NULL);
 
1065
      else if (assoc_p (var))
 
1066
        {
 
1067
          retval = assoc_reference (assoc_cell (var), akey);
 
1068
          free (akey);
 
1069
        }
 
1070
      else
 
1071
        retval = array_reference (array_cell (var), ind);
 
1072
    }
 
1073
 
 
1074
  return retval;
 
1075
}
 
1076
 
 
1077
/* Return a string containing the elements described by the array and
 
1078
   subscript contained in S, obeying quoting for subscripts * and @. */
 
1079
char *
 
1080
array_value (s, quoted, flags, rtype, indp)
 
1081
     char *s;
 
1082
     int quoted, flags, *rtype;
 
1083
     arrayind_t *indp;
 
1084
{
 
1085
  return (array_value_internal (s, quoted, flags|AV_ALLOWALL, rtype, indp));
 
1086
}
 
1087
 
 
1088
/* Return the value of the array indexing expression S as a single string.
 
1089
   If (FLAGS & AV_ALLOWALL) is 0, do not allow `@' and `*' subscripts.  This
 
1090
   is used by other parts of the shell such as the arithmetic expression
 
1091
   evaluator in expr.c. */
 
1092
char *
 
1093
get_array_value (s, flags, rtype, indp)
 
1094
     char *s;
 
1095
     int flags, *rtype;
 
1096
     arrayind_t *indp;
 
1097
{
 
1098
  return (array_value_internal (s, 0, flags, rtype, indp));
 
1099
}
 
1100
 
 
1101
char *
 
1102
array_keys (s, quoted)
 
1103
     char *s;
 
1104
     int quoted;
 
1105
{
 
1106
  int len;
 
1107
  char *retval, *t, *temp;
 
1108
  WORD_LIST *l;
 
1109
  SHELL_VAR *var;
 
1110
 
 
1111
  var = array_variable_part (s, &t, &len);
 
1112
 
 
1113
  /* [ */
 
1114
  if (var == 0 || ALL_ELEMENT_SUB (t[0]) == 0 || t[1] != ']')
 
1115
    return (char *)NULL;
 
1116
 
 
1117
  if (var_isset (var) == 0 || invisible_p (var))
 
1118
    return (char *)NULL;
 
1119
 
 
1120
  if (array_p (var) == 0 && assoc_p (var) == 0)
 
1121
    l = add_string_to_list ("0", (WORD_LIST *)NULL);
 
1122
  else if (assoc_p (var))
 
1123
    l = assoc_keys_to_word_list (assoc_cell (var));
 
1124
  else
 
1125
    l = array_keys_to_word_list (array_cell (var));
 
1126
  if (l == (WORD_LIST *)NULL)
 
1127
    return ((char *) NULL);
 
1128
 
 
1129
  if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
 
1130
    {
 
1131
      temp = string_list_dollar_star (l);
 
1132
      retval = quote_string (temp);
 
1133
      free (temp);
 
1134
    }
 
1135
  else  /* ${!name[@]} or unquoted ${!name[*]} */
 
1136
    retval = string_list_dollar_at (l, quoted);
 
1137
 
 
1138
  dispose_words (l);
 
1139
  return retval;
 
1140
}
 
1141
#endif /* ARRAY_VARS */