LCOV - code coverage report
Current view: top level - bash-4.4.23 - assoc.c (source / functions) Hit Total Coverage
Test: cov-bash.info Lines: 6 252 2.4 %
Date: 2020-10-29 14:49:28 Functions: 1 19 5.3 %

          Line data    Source code
       1             : /*
       2             :  * assoc.c - functions to manipulate associative arrays
       3             :  *
       4             :  * Associative arrays are standard shell hash tables.
       5             :  *
       6             :  * Chet Ramey
       7             :  * chet@ins.cwru.edu
       8             :  */
       9             : 
      10             : /* Copyright (C) 2008,2009,2011 Free Software Foundation, Inc.
      11             : 
      12             :    This file is part of GNU Bash, the Bourne Again SHell.
      13             : 
      14             :    Bash is free software: you can redistribute it and/or modify
      15             :    it under the terms of the GNU General Public License as published by
      16             :    the Free Software Foundation, either version 3 of the License, or
      17             :    (at your option) any later version.
      18             : 
      19             :    Bash is distributed in the hope that it will be useful,
      20             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      21             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      22             :    GNU General Public License for more details.
      23             : 
      24             :    You should have received a copy of the GNU General Public License
      25             :    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
      26             : */
      27             : 
      28             : #include "config.h"
      29             : 
      30             : #if defined (ARRAY_VARS)
      31             : 
      32             : #if defined (HAVE_UNISTD_H)
      33             : #  ifdef _MINIX
      34             : #    include <sys/types.h>
      35             : #  endif
      36             : #  include <unistd.h>
      37             : #endif
      38             : 
      39             : #include <stdio.h>
      40             : #include "bashansi.h"
      41             : 
      42             : #include "shell.h"
      43             : #include "array.h"
      44             : #include "assoc.h"
      45             : #include "builtins/common.h"
      46             : 
      47             : static WORD_LIST *assoc_to_word_list_internal __P((HASH_TABLE *, int));
      48             : 
      49             : /* assoc_create == hash_create */
      50             : 
      51             : void
      52           0 : assoc_dispose (hash)
      53             :      HASH_TABLE *hash;
      54             : {
      55           0 :   if (hash)
      56             :     {
      57           0 :       hash_flush (hash, 0);
      58           0 :       hash_dispose (hash);
      59             :     }
      60           0 : }
      61             : 
      62             : void
      63           0 : assoc_flush (hash)
      64             :      HASH_TABLE *hash;
      65             : {
      66           0 :   hash_flush (hash, 0);
      67           0 : }
      68             : 
      69             : int
      70           0 : assoc_insert (hash, key, value)
      71             :      HASH_TABLE *hash;
      72             :      char *key;
      73             :      char *value;
      74             : {
      75           0 :   BUCKET_CONTENTS *b;
      76             : 
      77           0 :   b = hash_search (key, hash, HASH_CREATE);
      78           0 :   if (b == 0)
      79             :     return -1;
      80             :   /* If we are overwriting an existing element's value, we're not going to
      81             :      use the key.  Nothing in the array assignment code path frees the key
      82             :      string, so we can free it here to avoid a memory leak. */
      83           0 :   if (b->key != key)
      84           0 :     free (key);
      85           0 :   FREE (b->data);
      86           0 :   b->data = value ? savestring (value) : (char *)0;
      87           0 :   return (0);
      88             : }
      89             : 
      90             : /* Like assoc_insert, but returns b->data instead of freeing it */
      91             : PTR_T
      92           0 : assoc_replace (hash, key, value)
      93             :      HASH_TABLE *hash;
      94             :      char *key;
      95             :      char *value;
      96             : {
      97           0 :   BUCKET_CONTENTS *b;
      98           0 :   PTR_T t;
      99             : 
     100           0 :   b = hash_search (key, hash, HASH_CREATE);
     101           0 :   if (b == 0)
     102             :     return (PTR_T)0;
     103             :   /* If we are overwriting an existing element's value, we're not going to
     104             :      use the key.  Nothing in the array assignment code path frees the key
     105             :      string, so we can free it here to avoid a memory leak. */
     106           0 :   if (b->key != key)
     107           0 :     free (key);
     108           0 :   t = b->data;
     109           0 :   b->data = value ? savestring (value) : (char *)0;
     110           0 :   return t;
     111             : }
     112             : 
     113             : void
     114           0 : assoc_remove (hash, string)
     115             :      HASH_TABLE *hash;
     116             :      char *string;
     117             : {
     118           0 :   BUCKET_CONTENTS *b;
     119             : 
     120           0 :   b = hash_remove (string, hash, 0);
     121           0 :   if (b)
     122             :     {
     123           0 :       free ((char *)b->data);
     124           0 :       free (b->key);
     125           0 :       free (b);
     126             :     }
     127           0 : }
     128             : 
     129             : char *
     130           0 : assoc_reference (hash, string)
     131             :      HASH_TABLE *hash;
     132             :      char *string;
     133             : {
     134           0 :   BUCKET_CONTENTS *b;
     135             : 
     136           0 :   if (hash == 0)
     137             :     return (char *)0;
     138             : 
     139           0 :   b = hash_search (string, hash, 0);
     140           0 :   return (b ? (char *)b->data : 0);
     141             : }
     142             : 
     143             : /* Quote the data associated with each element of the hash table ASSOC,
     144             :    using quote_string */
     145             : HASH_TABLE *
     146           0 : assoc_quote (h)
     147             :      HASH_TABLE *h;
     148             : {
     149           0 :   int i;
     150           0 :   BUCKET_CONTENTS *tlist;
     151           0 :   char *t;
     152             : 
     153           0 :   if (h == 0 || assoc_empty (h))
     154             :     return ((HASH_TABLE *)NULL);
     155             :   
     156           0 :   for (i = 0; i < h->nbuckets; i++)
     157           0 :     for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
     158             :       {
     159           0 :         t = quote_string ((char *)tlist->data);
     160           0 :         FREE (tlist->data);
     161           0 :         tlist->data = t;
     162             :       }
     163             : 
     164             :   return h;
     165             : }
     166             : 
     167             : /* Quote escape characters in the data associated with each element
     168             :    of the hash table ASSOC, using quote_escapes */
     169             : HASH_TABLE *
     170           0 : assoc_quote_escapes (h)
     171             :      HASH_TABLE *h;
     172             : {
     173           0 :   int i;
     174           0 :   BUCKET_CONTENTS *tlist;
     175           0 :   char *t;
     176             : 
     177           0 :   if (h == 0 || assoc_empty (h))
     178             :     return ((HASH_TABLE *)NULL);
     179             :   
     180           0 :   for (i = 0; i < h->nbuckets; i++)
     181           0 :     for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
     182             :       {
     183           0 :         t = quote_escapes ((char *)tlist->data);
     184           0 :         FREE (tlist->data);
     185           0 :         tlist->data = t;
     186             :       }
     187             : 
     188             :   return h;
     189             : }
     190             : 
     191             : HASH_TABLE *
     192           0 : assoc_dequote (h)
     193             :      HASH_TABLE *h;
     194             : {
     195           0 :   int i;
     196           0 :   BUCKET_CONTENTS *tlist;
     197           0 :   char *t;
     198             : 
     199           0 :   if (h == 0 || assoc_empty (h))
     200             :     return ((HASH_TABLE *)NULL);
     201             :   
     202           0 :   for (i = 0; i < h->nbuckets; i++)
     203           0 :     for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
     204             :       {
     205           0 :         t = dequote_string ((char *)tlist->data);
     206           0 :         FREE (tlist->data);
     207           0 :         tlist->data = t;
     208             :       }
     209             : 
     210             :   return h;
     211             : }
     212             : 
     213             : HASH_TABLE *
     214           0 : assoc_dequote_escapes (h)
     215             :      HASH_TABLE *h;
     216             : {
     217           0 :   int i;
     218           0 :   BUCKET_CONTENTS *tlist;
     219           0 :   char *t;
     220             : 
     221           0 :   if (h == 0 || assoc_empty (h))
     222             :     return ((HASH_TABLE *)NULL);
     223             :   
     224           0 :   for (i = 0; i < h->nbuckets; i++)
     225           0 :     for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
     226             :       {
     227           0 :         t = dequote_escapes ((char *)tlist->data);
     228           0 :         FREE (tlist->data);
     229           0 :         tlist->data = t;
     230             :       }
     231             : 
     232             :   return h;
     233             : }
     234             : 
     235             : HASH_TABLE *
     236           0 : assoc_remove_quoted_nulls (h)
     237             :      HASH_TABLE *h;
     238             : {
     239           0 :   int i;
     240           0 :   BUCKET_CONTENTS *tlist;
     241           0 :   char *t;
     242             : 
     243           0 :   if (h == 0 || assoc_empty (h))
     244             :     return ((HASH_TABLE *)NULL);
     245             :   
     246           0 :   for (i = 0; i < h->nbuckets; i++)
     247           0 :     for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
     248             :       {
     249           0 :         t = remove_quoted_nulls ((char *)tlist->data);
     250           0 :         tlist->data = t;
     251             :       }
     252             : 
     253             :   return h;
     254             : }
     255             : 
     256             : /*
     257             :  * Return a string whose elements are the members of array H beginning at
     258             :  * the STARTth element and spanning NELEM members.  Null elements are counted.
     259             :  */
     260             : char *
     261           0 : assoc_subrange (hash, start, nelem, starsub, quoted)
     262             : HASH_TABLE *hash;
     263             : arrayind_t start, nelem;
     264             : int starsub, quoted;
     265             : {
     266           0 :   WORD_LIST *l, *save, *h, *t;
     267           0 :   int i, j;
     268           0 :   char *ret;
     269             : 
     270           0 :   if (assoc_empty (hash))
     271             :     return ((char *)NULL);
     272             : 
     273           0 :   save = l = assoc_to_word_list (hash);
     274           0 :   if (save == 0)
     275             :     return ((char *)NULL);
     276             : 
     277           0 :   for (i = 1; l && i < start; i++)
     278           0 :     l = l->next;
     279           0 :   if (l == 0)
     280             :     {
     281           0 :       dispose_words (save);
     282           0 :       return ((char *)NULL);
     283             :     }
     284           0 :   for (j = 0,h = t = l; l && j < nelem; j++)
     285             :     {
     286           0 :       t = l;
     287           0 :       l = l->next;
     288             :     }
     289             : 
     290           0 :   t->next = (WORD_LIST *)NULL;
     291             : 
     292           0 :   ret = string_list_pos_params (starsub ? '*' : '@', h, quoted);
     293             : 
     294           0 :   if (t != l)
     295           0 :     t->next = l;
     296             : 
     297           0 :   dispose_words (save);
     298           0 :   return (ret);
     299             : 
     300             : }
     301             : 
     302             : char *
     303           0 : assoc_patsub (h, pat, rep, mflags)
     304             :      HASH_TABLE *h;
     305             :      char *pat, *rep;
     306             :      int mflags;
     307             : {
     308           0 :   BUCKET_CONTENTS *tlist;
     309           0 :   int i, slen;
     310           0 :   HASH_TABLE *h2;
     311           0 :   char  *t, *sifs, *ifs;
     312             : 
     313           0 :   if (h == 0 || assoc_empty (h))
     314             :     return ((char *)NULL);
     315             : 
     316           0 :   h2 = assoc_copy (h);
     317           0 :   for (i = 0; i < h2->nbuckets; i++)
     318           0 :     for (tlist = hash_items (i, h2); tlist; tlist = tlist->next)
     319             :       {
     320           0 :         t = pat_subst ((char *)tlist->data, pat, rep, mflags);
     321           0 :         FREE (tlist->data);
     322           0 :         tlist->data = t;
     323             :       }
     324             : 
     325           0 :   if (mflags & MATCH_QUOTED)
     326           0 :     assoc_quote (h2);
     327             :   else
     328           0 :     assoc_quote_escapes (h2);
     329             : 
     330           0 :   if (mflags & MATCH_STARSUB)
     331             :     {
     332           0 :       assoc_remove_quoted_nulls (h2);
     333           0 :       sifs = ifs_firstchar ((int *)NULL);
     334           0 :       t = assoc_to_string (h2, sifs, 0);
     335           0 :       free (sifs);
     336             :     }
     337           0 :   else if (mflags & MATCH_QUOTED)
     338             :     {
     339             :       /* ${array[@]} */
     340           0 :       sifs = ifs_firstchar (&slen);
     341           0 :       ifs = getifs ();
     342           0 :       if (ifs == 0 || *ifs == 0)
     343             :         {
     344           0 :           if (slen < 2)
     345           0 :             sifs = xrealloc (sifs, 2);
     346           0 :           sifs[0] = ' ';
     347           0 :           sifs[1] = '\0';
     348             :         }
     349           0 :       t = assoc_to_string (h2, sifs, 0);
     350           0 :       free(sifs);
     351             :     }
     352             :   else
     353           0 :     t = assoc_to_string (h2, " ", 0);
     354             : 
     355           0 :   assoc_dispose (h2);
     356             : 
     357           0 :   return t;
     358             : }
     359             : 
     360             : char *
     361           0 : assoc_modcase (h, pat, modop, mflags)
     362             :      HASH_TABLE *h;
     363             :      char *pat;
     364             :      int modop;
     365             :      int mflags;
     366             : {
     367           0 :   BUCKET_CONTENTS *tlist;
     368           0 :   int i, slen;
     369           0 :   HASH_TABLE *h2;
     370           0 :   char  *t, *sifs, *ifs;
     371             : 
     372           0 :   if (h == 0 || assoc_empty (h))
     373             :     return ((char *)NULL);
     374             : 
     375           0 :   h2 = assoc_copy (h);
     376           0 :   for (i = 0; i < h2->nbuckets; i++)
     377           0 :     for (tlist = hash_items (i, h2); tlist; tlist = tlist->next)
     378             :       {
     379           0 :         t = sh_modcase ((char *)tlist->data, pat, modop);
     380           0 :         FREE (tlist->data);
     381           0 :         tlist->data = t;
     382             :       }
     383             : 
     384           0 :   if (mflags & MATCH_QUOTED)
     385           0 :     assoc_quote (h2);
     386             :   else
     387           0 :     assoc_quote_escapes (h2);
     388             : 
     389           0 :   if (mflags & MATCH_STARSUB)
     390             :     {
     391           0 :       assoc_remove_quoted_nulls (h2);
     392           0 :       sifs = ifs_firstchar ((int *)NULL);
     393           0 :       t = assoc_to_string (h2, sifs, 0);
     394           0 :       free (sifs);
     395             :     }
     396           0 :   else if (mflags & MATCH_QUOTED)
     397             :     {
     398             :       /* ${array[@]} */
     399           0 :       sifs = ifs_firstchar (&slen);
     400           0 :       ifs = getifs ();
     401           0 :       if (ifs == 0 || *ifs == 0)
     402             :         {
     403           0 :           if (slen < 2)
     404           0 :             sifs = xrealloc (sifs, 2);
     405           0 :           sifs[0] = ' ';
     406           0 :           sifs[1] = '\0';
     407             :         }
     408           0 :       t = assoc_to_string (h2, sifs, 0);
     409           0 :       free(sifs);
     410             :     }
     411             :   else
     412           0 :     t = assoc_to_string (h2, " ", 0);
     413             : 
     414           0 :   assoc_dispose (h2);
     415             : 
     416           0 :   return t;
     417             : }
     418             : 
     419             : char *
     420         358 : assoc_to_assign (hash, quoted)
     421             :      HASH_TABLE *hash;
     422             :      int quoted;
     423             : {
     424         358 :   char *ret;
     425         358 :   char *istr, *vstr;
     426         358 :   int i, rsize, rlen, elen;
     427         358 :   BUCKET_CONTENTS *tlist;
     428             : 
     429         358 :   if (hash == 0 || assoc_empty (hash))
     430             :     return (char *)0;
     431             : 
     432           0 :   ret = xmalloc (rsize = 128);
     433           0 :   ret[0] = '(';
     434           0 :   rlen = 1;
     435             : 
     436           0 :   for (i = 0; i < hash->nbuckets; i++)
     437           0 :     for (tlist = hash_items (i, hash); tlist; tlist = tlist->next)
     438             :       {
     439           0 :         if (ansic_shouldquote (tlist->key))
     440           0 :           istr = ansic_quote (tlist->key, 0, (int *)0);
     441           0 :         else if (sh_contains_shell_metas (tlist->key))
     442           0 :           istr = sh_double_quote (tlist->key);
     443           0 :         else if (ALL_ELEMENT_SUB (tlist->key[0]) && tlist->key[1] == '\0')
     444           0 :           istr = sh_double_quote (tlist->key);       
     445             :         else
     446             :           istr = tlist->key; 
     447             : 
     448           0 :         vstr = tlist->data ? (ansic_shouldquote ((char *)tlist->data) ?
     449           0 :                                 ansic_quote ((char *)tlist->data, 0, (int *)0) :
     450           0 :                                 sh_double_quote ((char *)tlist->data))
     451           0 :                            : (char *)0;
     452             : 
     453           0 :         elen = STRLEN (istr) + 8 + STRLEN (vstr);
     454           0 :         RESIZE_MALLOCED_BUFFER (ret, rlen, (elen+1), rsize, rsize);
     455             : 
     456           0 :         ret[rlen++] = '[';
     457           0 :         strcpy (ret+rlen, istr);
     458           0 :         rlen += STRLEN (istr);
     459           0 :         ret[rlen++] = ']';
     460           0 :         ret[rlen++] = '=';
     461           0 :         if (vstr)
     462             :           {
     463           0 :             strcpy (ret + rlen, vstr);
     464           0 :             rlen += STRLEN (vstr);
     465             :           }
     466           0 :         ret[rlen++] = ' ';
     467             : 
     468             : 
     469           0 :         if (istr != tlist->key)
     470           0 :           FREE (istr);
     471             : 
     472           0 :         FREE (vstr);
     473             :     }
     474             : 
     475           0 :   RESIZE_MALLOCED_BUFFER (ret, rlen, 1, rsize, 8);
     476           0 :   ret[rlen++] = ')';
     477           0 :   ret[rlen] = '\0';
     478             : 
     479           0 :   if (quoted)
     480             :     {
     481           0 :       vstr = sh_single_quote (ret);
     482           0 :       free (ret);
     483           0 :       ret = vstr;
     484             :     }
     485             : 
     486             :   return ret;
     487             : }
     488             : 
     489             : static WORD_LIST *
     490           0 : assoc_to_word_list_internal (h, t)
     491             :      HASH_TABLE *h;
     492             :      int t;
     493             : {
     494           0 :   WORD_LIST *list;
     495           0 :   int i;
     496           0 :   BUCKET_CONTENTS *tlist;
     497           0 :   char *w;
     498             : 
     499           0 :   if (h == 0 || assoc_empty (h))
     500             :     return((WORD_LIST *)NULL);
     501             :   list = (WORD_LIST *)NULL;
     502             :   
     503           0 :   for (i = 0; i < h->nbuckets; i++)
     504           0 :     for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
     505             :       {
     506           0 :         w = (t == 0) ? (char *)tlist->data : (char *)tlist->key;
     507           0 :         list = make_word_list (make_bare_word(w), list);
     508             :       }
     509           0 :   return (REVERSE_LIST(list, WORD_LIST *));
     510             : }
     511             : 
     512             : WORD_LIST *
     513           0 : assoc_to_word_list (h)
     514             :      HASH_TABLE *h;
     515             : {
     516           0 :   return (assoc_to_word_list_internal (h, 0));
     517             : }
     518             : 
     519             : WORD_LIST *
     520           0 : assoc_keys_to_word_list (h)
     521             :      HASH_TABLE *h;
     522             : {
     523           0 :   return (assoc_to_word_list_internal (h, 1));
     524             : }
     525             : 
     526             : char *
     527           0 : assoc_to_string (h, sep, quoted)
     528             :      HASH_TABLE *h;
     529             :      char *sep;
     530             :      int quoted;
     531             : {
     532           0 :   BUCKET_CONTENTS *tlist;
     533           0 :   int i;
     534           0 :   char *result, *t, *w;
     535           0 :   WORD_LIST *list, *l;
     536             : 
     537           0 :   if (h == 0)
     538             :     return ((char *)NULL);
     539           0 :   if (assoc_empty (h))
     540           0 :     return (savestring (""));
     541             : 
     542             :   result = NULL;
     543             :   l = list = NULL;
     544             :   /* This might be better implemented directly, but it's simple to implement
     545             :      by converting to a word list first, possibly quoting the data, then
     546             :      using list_string */
     547           0 :   for (i = 0; i < h->nbuckets; i++)
     548           0 :     for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
     549             :       {
     550           0 :         w = (char *)tlist->data;
     551           0 :         if (w == 0)
     552             :           continue;
     553           0 :         t = quoted ? quote_string (w) : savestring (w);
     554           0 :         list = make_word_list (make_bare_word(t), list);
     555           0 :         FREE (t);
     556             :       }
     557             : 
     558           0 :   l = REVERSE_LIST(list, WORD_LIST *);
     559             : 
     560           0 :   result = l ? string_list_internal (l, sep) : savestring ("");
     561           0 :   dispose_words (l);  
     562             : 
     563           0 :   return result;
     564             : }
     565             : 
     566             : #endif /* ARRAY_VARS */

Generated by: LCOV version 1.14.0.6.4058