Re: g_setenv g_unsetenv



On Wed, Sep 06, 2000 at 12:37:39PM +0200, Tim Janik wrote:
> > I think this should go into glib and I'd be willing to write it.  Now the
> > question is, would it be accepted?
> 
> i'd love to see portable versions for this.

Here's what I have after about an hour of research.  First after looking and
seeing that while putenv is on most systems, it works somewhat differently, I
started implementing a scheme that something like "screen" uses.  That is on
first g_putenv (or whatever it would be named), the entire environment is
copied onto the heap.  Then we can do good memory management upon it.  Then
it hit me.  If another part of the program did a putenv, we'd get majorly
screwed, so I think that approach is too fragile.  Another approach might be
keeping some bookkeeping information, however, I'm not sure that the cost of
this is actually worth plugging the leaks which are not too bad.  So I
decided that on systems without setenv, g_setenv would just leak each time
you do it, that's the only sane / portable way to get this to work
apparently.  The other problem is unsetenv.  Different systems with putenv
seem to handle it differently, namely either putenv("name") or
putenv("name="), if they handle the case at all.  It's however quite easy to
implement unsetenv by hand by just twiddling the "environ" global (which
should be standard C as far as I know).  In fact as far as I could tell, the
only ANSI-C parts are the environ, and getenv.  So apparently there could be
systems out there that do not have setenv nor putenv.  So I intend to write
support for those as well.  Well here's my current stab at it (doesn't
include windows stuff as apparently it would need to use some windows
specific functions, but as far as I could tell those should be in the spirit
of setenv, also this is not tested at all, just posted here as food for
thought):

gint
g_setenv (const gchar *name, const gchar *value, gboolean overwrite)
{
#if defined(HAVE_SETENV)
  return setenv (name, value, overwrite);
#elif defined(G_OS_WIN32)
  /* FOO */
#else
  gchar *string;

  if ( ! overwrite &&
      g_getenv (name) != NULL)
    return 0;

  /* A leak.  But there is absolutely no apparent
   * way to get around this other then an incredible
   * mess with the environ variable */
  string = g_strconcat (name, '=', value, NULL);
  return putenv (string);
#endif
}

/* We will need this for unsetenv if there
 * is no unsetenv */
#if !defined(HAVE_SETENV) && !defined(G_OS_WIN32)
extern gchar **environ;
#endif

void
g_unsetenv (const gchar *name)
{
#if defined(HAVE_SETENV)
  unsetenv (name);
#elif defined(G_OS_WIN32)
  /* FOO */
#else
  gint i;
  gint len;

  len = strlen (name);

  /* Mess directly with the environ array, apparently
   * this seems to be the only portable way to do this */
  for (i = 0; environ[i] != NULL; i++)
    {
      if (strncmp (environ[i], name, len) == 0 &&
	  environ[i][len + 1] == '=')
	break;
    }

  while (environ[i] != NULL)
    {
      environ[i] = environ[i + 1];
      i++;
    }
#endif
}


Now the question is, how far should this be taken.  Do we want book keeping?
Or do we just accept memleaks.  Note that bookkeeping will never be perfect
if intermixed with normal setenv, putenv calls, and may be more expensive
then the memleaks.

George

-- 
George <jirka 5z com>
   Man will occasionally stumble over the truth, 
   but most times he will pick himself up and carry on.
                       -- Winston Churchill




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]