Re: g_setenv g_unsetenv



OK, here's a patch.  It does a putenv dance for everything and doesn't
twiddle 'environ'.  I've also added some test code to testglib.c.  There is
also some Win32 code which I did according to MS docs, but not sure if it's
correct as I couldn't even compile it of course.  Now in case we're not on
Win32 and putenv is not available, the functions are no-ops.  Unsetenv of
course only works if putenv can remove variables.  Also note that
g_setenv ("FOO", "", TRUE); on a sunbox is equivalent to g_unsetenv ("FOO");
due to the way putenv works there (apparently).  Somewhere putenv ("VAR")
removes variables, somewhere it's putenv ("VAR=").  But POSIX says nothing of
the sort.  In fact according to POSIX I couldn't find a good way to unset a
variable.  Well in the worst case the VAR will not be removed but set to
an empty string, which is the next best thing.

George

-- 
George <jirka 5z com>
   Originality is undetected plagiarism.
                       -- Dean W. R. Inge
Index: configure.in
===================================================================
RCS file: /cvs/gnome/glib/configure.in,v
retrieving revision 1.140
diff -u -p -r1.140 configure.in
--- configure.in	2000/09/06 15:01:03	1.140
+++ configure.in	2000/09/08 00:52:30
@@ -221,7 +221,7 @@ AC_HEADER_STDC
 # Checks for library functions.
 AC_FUNC_VPRINTF
 
-AC_CHECK_FUNCS(atexit on_exit)
+AC_CHECK_FUNCS(atexit on_exit setenv unsetenv putenv)
 
 AC_CHECK_SIZEOF(char)
 AC_CHECK_SIZEOF(short)
Index: glib.h
===================================================================
RCS file: /cvs/gnome/glib/glib.h,v
retrieving revision 1.196
diff -u -p -r1.196 glib.h
--- glib.h	2000/09/07 23:08:25	1.196
+++ glib.h	2000/09/08 00:52:31
@@ -1788,6 +1788,20 @@ gchar*	g_path_get_dirname	(const gchar *
 /* return the environment string for the variable. The returned memory
  * must not be freed. */
 gchar*  g_getenv		(const gchar *variable);
+/* Set an environment variable.  if 'overwrite' is false and
+ * variable already exists, then nothing happens, returns 0
+ * on success, -1 on error.  Note that it may call putenv
+ * and leak memory if setenv doesn't exist on a system.
+ * Thus you should never use this in a loop or anywhere
+ * where leaks are a problem. */
+gint	g_setenv		(const gchar *variable,
+				 const gchar *value,
+				 gboolean overwrite);
+/* Unset an environment variable.  This function may not
+ * be 100% reliable on systems with no unsetenv and a
+ * broken putenv implementation.  It could also leak
+ * memory on such broken systems. */
+void	g_unsetenv		(const gchar *variable);
 
 /* we use a GLib function as a replacement for ATEXIT, so
  * the programmer is not required to check the return value
Index: gutils.c
===================================================================
RCS file: /cvs/gnome/glib/gutils.c,v
retrieving revision 1.67
diff -u -p -r1.67 gutils.c
--- gutils.c	2000/09/07 23:08:25	1.67
+++ gutils.c	2000/09/08 00:52:32
@@ -540,6 +540,130 @@ g_getenv (const gchar *variable)
 #endif
 }
 
+G_LOCK_DEFINE_STATIC (g_setenv_global);
+
+/* Setting environment, much hairier if setenv is not present. */
+gint
+g_setenv (const gchar *variable, const gchar *value, gboolean overwrite)
+{
+  g_return_val_if_fail (variable != NULL, -1);
+  g_return_val_if_fail (value != NULL, -1);
+
+#if defined(HAVE_SETENV)
+  return setenv (variable, value, overwrite);
+#elif defined(G_OS_WIN32)
+  {
+    gboolean return_value;
+
+    G_LOCK (g_setenv_global);
+
+    if ( ! overwrite &&
+         g_getenv (variable) != NULL)
+      {
+        G_UNLOCK (g_setenv_global);
+        return 0;
+      }
+
+    return_value = SetEnvironmentVariable (variable, value);
+
+    G_UNLOCK (g_setenv_global);
+
+    return return_value ? 0 : -1;
+#elif defined(HAVE_PUTENV)
+  {
+    gchar *string;
+    gint return_value;
+
+    G_LOCK (g_setenv_global);
+
+    if ( ! overwrite &&
+        g_getenv (variable) != NULL)
+      {
+        G_UNLOCK (g_setenv_global);
+        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 (variable, "=", value, NULL);
+    return_value = putenv (string);
+
+    /* If things went bad, we can safely free the string
+     * as it's not in the environment */
+    if (return_value < 0)
+      g_free (string);
+
+    G_UNLOCK (g_setenv_global);
+
+    return return_value;
+  }
+#else
+  /* no putenv, no setenv, no nuthin' */
+  return -1;
+#endif
+}
+
+void
+g_unsetenv (const gchar *variable)
+{
+  g_return_if_fail (variable != NULL);
+
+#if defined(HAVE_UNSETENV)
+  unsetenv (variable);
+#elif defined(G_OS_WIN32)
+  SetEnvironmentVariable (variable, NULL);
+#elif defined(HAVE_PUTENV)
+  {
+    char *string;
+
+    /* Things "could" go mucho wrong if variable
+     * includes a '=' */
+    g_return_if_fail (strchr (variable, '=') == NULL);
+
+    G_LOCK (g_setenv_global);
+
+    /* To avoid unneccesary leaks, etc,
+     * check if it's even there */
+    if (g_getenv (variable) == NULL)
+      {
+        G_UNLOCK (g_setenv_global);
+        return;
+      }
+
+    /* Possible leak.  If neither putenv ("VAR")
+     * nor putenv ("VAR=") kill the environ variable,
+     * then our string would end up in the
+     * environment itself */
+    string = g_strdup (variable);
+    if (putenv (string) < 0)
+      {
+        g_free (string);
+        string = g_strconcat (variable, "=", NULL);
+        if (putenv (string) < 0)
+          {
+	    /* We can safely free the string as
+	     * things just plain went wrong */
+	    g_free (string);
+	    string = NULL;
+	  }
+      }
+
+    /* if the variable is not in the evnironment,
+     * then putenv worked and got rid of it.  And
+     * we can safely free string */
+    if (string != NULL &&
+        g_getenv (variable) == NULL)
+      g_free (string);
+
+    G_UNLOCK (g_setenv_global);
+  }
+#else
+  /* no putenv, no unsetenv, no nuthin' */
+  return;
+#endif
+}
+
 
 G_LOCK_DEFINE_STATIC (g_utils_global);
 
Index: testglib.c
===================================================================
RCS file: /cvs/gnome/glib/testglib.c,v
retrieving revision 1.38
diff -u -p -r1.38 testglib.c
--- testglib.c	2000/09/07 23:08:25	1.38
+++ testglib.c	2000/09/08 00:52:32
@@ -398,6 +398,32 @@ main (int   argc,
   if (n_dirname_checks)
     g_print ("ok\n");
 
+  {
+    gboolean env_ok = TRUE;
+
+    g_print ("checking g_setenv/g_unsetenv...");
+    if (g_setenv ("GLIB_TESTING", "FOO", TRUE) < 0)
+      {
+        g_print ("\nfailed to set GLIB_TESTING to \"FOO\"\n");
+	env_ok = FALSE;
+      }
+    if (g_getenv ("GLIB_TESTING") == NULL ||
+	strcmp (g_getenv ("GLIB_TESTING"), "FOO") != 0)
+      {
+        g_print ("\nfailed, GLIB_TESTING is not set or not set to \"FOO\"\n");
+	env_ok = FALSE;
+      }
+    g_unsetenv ("GLIB_TESTING");
+    if (g_getenv ("GLIB_TESTING") != NULL)
+      {
+        g_print ("\nfailed, unsetenv failed\n");
+	env_ok = FALSE;
+      }
+
+    if (env_ok)
+      g_print ("ok\n");
+  }
+
   g_print ("checking doubly linked lists...");
 
   list = NULL;


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