Back to index

tetex-bin  3.0
xputenv.c
Go to the documentation of this file.
00001 /* xputenv.c: set an environment variable without return.
00002 
00003 Copyright (C) 1993, 94, 95, 96, 97, 98 Karl Berry.
00004 
00005 This library is free software; you can redistribute it and/or
00006 modify it under the terms of the GNU Library General Public
00007 License as published by the Free Software Foundation; either
00008 version 2 of the License, or (at your option) any later version.
00009 
00010 This library is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 Library General Public License for more details.
00014 
00015 You should have received a copy of the GNU Library General Public
00016 License along with this library; if not, write to the Free Software
00017 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
00018 
00019 #include <kpathsea/config.h>
00020 
00021 #ifdef WIN32
00022 #include <stdlib.h>
00023 #else
00024 /* Avoid implicit declaration warning.  But since some systems do
00025    declare it, don't use a prototype, for fear of conflicts.  */
00026 extern int putenv ();
00027 #endif /* not WIN32 */
00028 
00029 /* This `x' function is different from the others in that it takes
00030    different parameters than the standard function; but I find it much
00031    more convenient to pass the variable and the value separately.  Also,
00032    this way we can guarantee that the environment value won't become
00033    garbage.  Also, putenv just overwrites old entries with
00034    the new, and we want to reclaim that space -- this may be called
00035    hundreds of times on a run.
00036    
00037    But naturally, some systems do it differently. In this case, it's
00038    net2 that is smart and does its own saving/freeing.  configure tries
00039    to determine this.  */
00040 
00041 void
00042 xputenv P2C(const_string, var_name,  const_string, value)
00043 {
00044   string old_item = NULL;
00045   string new_item = concat3 (var_name, "=", value);
00046   unsigned name_len = strlen (var_name);
00047 
00048 #ifndef SMART_PUTENV
00049 
00050   static const_string *saved_env_items = NULL;
00051   static unsigned saved_len;
00052   boolean found = false;
00053 
00054   /* Check if we have saved anything yet.  */
00055   if (!saved_env_items)
00056     {
00057       saved_env_items = XTALLOC1 (const_string);
00058       saved_env_items[0] = var_name;
00059       saved_len = 1;
00060     }
00061   else
00062     {
00063       /* Check if we've assigned VAR_NAME before.  */
00064       unsigned i;
00065       for (i = 0; i < saved_len && !found; i++)
00066         {
00067           if (STREQ (saved_env_items[i], var_name))
00068             {
00069               found = true;
00070               old_item = getenv (var_name);
00071 #if defined (WIN32) || defined (DJGPP)
00072              /* win32 putenv() removes the variable if called with
00073                "VAR=". So we have to cope with this case. Distinction
00074                is not made between the value being "" or the variable
00075                not set. */
00076              if (old_item)
00077               old_item -= (name_len + 1);
00078 #else
00079               assert (old_item);
00080               /* Back up to the `NAME=' in the environment before the
00081                  value that getenv returns.  */
00082               old_item -= (name_len + 1);
00083 #endif
00084             }
00085         }
00086 
00087       if (!found)
00088         {
00089           /* If we haven't seen VAR_NAME before, save it.  Assume it is
00090              in safe storage.  */
00091           saved_len++;
00092           XRETALLOC (saved_env_items, saved_len, const_string);
00093           saved_env_items[saved_len - 1] = var_name;
00094         }
00095     }
00096 #endif /* not SMART_PUTENV */
00097 
00098   /* If the old and the new values are identical, don't do anything.
00099      This is both more memory-efficient and safer as far as our
00100      assumptions (about how putenv is implemented in libc) go.  */
00101   if (!old_item || !STREQ (old_item, new_item))
00102     {
00103       char *new_val;
00104       /* As far as I can see there's no way to distinguish between the
00105          various errors; putenv doesn't have errno values.  */
00106       if (putenv (new_item) < 0)
00107         FATAL1 ("putenv (%s) failed", new_item);
00108 
00109       /* If their putenv copied `new_item', we can free it.  */
00110       new_val = getenv (var_name);
00111       if (new_val && new_val - name_len - 1 != new_item)
00112         free (new_item);
00113 
00114 #ifndef SMART_PUTENV
00115       /* Can't free `new_item' because its contained value is now in
00116          `environ', but we can free `old_item', since it's been replaced.  */
00117 #ifndef WIN32
00118       /* ... except on Win32, where old_item points to garbage.
00119          Or at least non free-able memory. Or at least, that's what
00120          BoundsChecker says... FP, 06/10/98) */
00121       if (old_item)
00122         free (old_item);
00123 #endif
00124 #endif /* not SMART_PUTENV */
00125     }
00126 }
00127 
00128 
00129 /* A special case for setting a variable to a numeric value
00130    (specifically, KPATHSEA_DPI).  We don't need to dynamically allocate
00131    and free the string for the number, since it's saved as part of the
00132    environment value.  */
00133 
00134 void
00135 xputenv_int P2C(const_string, var_name,  int, num)
00136 {
00137   char str[MAX_INT_LENGTH];
00138   sprintf (str, "%d", num);
00139   
00140   xputenv (var_name, str);
00141 }