(root)/
glibc-2.38/
string/
envz.c
       1  /* Routines for dealing with '\0' separated environment vectors
       2     Copyright (C) 1995-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <malloc.h>
      20  #include <string.h>
      21  
      22  #include <envz.h>
      23  
      24  /* The character separating names from values in an envz.  */
      25  #define SEP '='
      26  
      27  /* Returns a pointer to the entry in ENVZ for NAME, or 0 if there is none.
      28     If NAME contains the separator character, only the portion before it is
      29     used in the comparison.  */
      30  char *
      31  envz_entry (const char *envz, size_t envz_len, const char *name)
      32  {
      33    while (envz_len)
      34      {
      35        const char *p = name;
      36        const char *entry = envz;	/* Start of this entry. */
      37  
      38        /* See how far NAME and ENTRY match.  */
      39        while (envz_len && *p == *envz && *p && *p != SEP)
      40  	p++, envz++, envz_len--;
      41  
      42        if ((*envz == '\0' || *envz == SEP) && (*p == '\0' || *p == SEP))
      43  	/* Bingo! */
      44  	return (char *) entry;
      45  
      46        /* No match, skip to the next entry.  */
      47        while (envz_len && *envz)
      48  	envz++, envz_len--;
      49        if (envz_len)
      50  	envz++, envz_len--;	/* skip '\0' */
      51      }
      52  
      53    return 0;
      54  }
      55  libc_hidden_def (envz_entry)
      56  
      57  /* Returns a pointer to the value portion of the entry in ENVZ for NAME, or 0
      58     if there is none.  */
      59  char *
      60  envz_get (const char *envz, size_t envz_len, const char *name)
      61  {
      62    char *entry = envz_entry (envz, envz_len, name);
      63    if (entry)
      64      {
      65        while (*entry && *entry != SEP)
      66  	entry++;
      67        if (*entry)
      68  	entry++;
      69        else
      70  	entry = 0;		/* A null entry.  */
      71      }
      72    return entry;
      73  }
      74  
      75  /* Remove the entry for NAME from ENVZ & ENVZ_LEN, if any.  */
      76  void
      77  envz_remove (char **envz, size_t *envz_len, const char *name)
      78  {
      79    char *entry = envz_entry (*envz, *envz_len, name);
      80    if (entry)
      81      argz_delete (envz, envz_len, entry);
      82  }
      83  libc_hidden_def (envz_remove)
      84  
      85  /* Adds an entry for NAME with value VALUE to ENVZ & ENVZ_LEN.  If an entry
      86     with the same name already exists in ENVZ, it is removed.  If VALUE is
      87     NULL, then the new entry will a special null one, for which envz_get will
      88     return NULL, although envz_entry will still return an entry; this is handy
      89     because when merging with another envz, the null entry can override an
      90     entry in the other one.  Null entries can be removed with envz_strip ().  */
      91  error_t
      92  envz_add (char **envz, size_t *envz_len, const char *name, const char *value)
      93  {
      94    envz_remove (envz, envz_len, name);
      95  
      96    if (value)
      97      /* Add the new value, if there is one.  */
      98      {
      99        size_t name_len = strlen (name);
     100        size_t value_len = strlen (value);
     101        size_t old_envz_len = *envz_len;
     102        size_t new_envz_len = old_envz_len + name_len + 1 + value_len + 1;
     103        char *new_envz = realloc (*envz, new_envz_len);
     104  
     105        if (new_envz)
     106  	{
     107  	  memcpy (new_envz + old_envz_len, name, name_len);
     108  	  new_envz[old_envz_len + name_len] = SEP;
     109  	  memcpy (new_envz + old_envz_len + name_len + 1, value, value_len);
     110  	  new_envz[new_envz_len - 1] = 0;
     111  
     112  	  *envz = new_envz;
     113  	  *envz_len = new_envz_len;
     114  
     115  	  return 0;
     116  	}
     117        else
     118  	return ENOMEM;
     119      }
     120    else
     121      /* Add a null entry.  */
     122      return __argz_add (envz, envz_len, name);
     123  }
     124  
     125  /* Adds each entry in ENVZ2 to ENVZ & ENVZ_LEN, as if with envz_add().  If
     126     OVERRIDE is true, then values in ENVZ2 will supersede those with the same
     127     name in ENV, otherwise not.  */
     128  error_t
     129  envz_merge (char **envz, size_t *envz_len, const char *envz2,
     130  	    size_t envz2_len, int override)
     131  {
     132    error_t err = 0;
     133  
     134    while (envz2_len && ! err)
     135      {
     136        char *old = envz_entry (*envz, *envz_len, envz2);
     137        size_t new_len = strlen (envz2) + 1;
     138  
     139        if (! old)
     140  	err = __argz_append (envz, envz_len, envz2, new_len);
     141        else if (override)
     142  	{
     143  	  argz_delete (envz, envz_len, old);
     144  	  err = __argz_append (envz, envz_len, envz2, new_len);
     145  	}
     146  
     147        envz2 += new_len;
     148        envz2_len -= new_len;
     149      }
     150  
     151    return err;
     152  }
     153  
     154  /* Remove null entries.  */
     155  void
     156  envz_strip (char **envz, size_t *envz_len)
     157  {
     158    char *entry = *envz;
     159    size_t left = *envz_len;
     160    while (left)
     161      {
     162        size_t entry_len = strlen (entry) + 1;
     163        left -= entry_len;
     164        if (! strchr (entry, SEP))
     165  	/* Null entry. */
     166  	memmove (entry, entry + entry_len, left);
     167        else
     168  	entry += entry_len;
     169      }
     170    *envz_len = entry - *envz;
     171  }