1 /* xputenv.c: set an environment variable without return. */
2 
3 /* Copyright 1993-98, 2008, 2009 Karl Berry.
4    Copyright 2003-05 Olaf Weber.
5 
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10 
11    This library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15 
16    You should have received a copy of the GNU Lesser General Public License
17    along with this library; if not, see <http://www.gnu.org/licenses/>.  */
18 
19 
20 #include <kpathsea/config.h>
21 #include <kpathsea/types.h>
22 
23 #ifdef WIN32
24 #include <stdlib.h>
25 #else
26 #if !HAVE_DECL_PUTENV
27 extern int putenv (char* entry);
28 #endif
29 #endif /* not WIN32 */
30 
31 /*
32  * We have different arguments from the "standard" function.  A separate
33  * var and value tends to be much more practical.
34  *
35  * The standards for putenv are clear: put the passed string into the
36  * environment, and if you alter that string, the environment changes.
37  * Of course various implementations are broken in a number of ways,
38  * which include making copies of the passed string, and more.
39  */
40 void
kpathsea_xputenv(kpathsea kpse,const char * var,const char * value)41 kpathsea_xputenv(kpathsea kpse, const char *var, const char *value)
42 {
43     char  *cur_item;
44     char  *old_item;
45     char  *new_item;
46     size_t var_lim;
47     int    cur_loc;
48 
49     /* kpse_debug2(KPSE_DEBUG_VARS, "kpse_putenv($%s,%s)", var, value); */
50 
51     old_item = NULL;
52     cur_item = concat3(var, "=", value);
53     /* Include '=' in length. */
54     var_lim = strlen(var) + 1;
55 
56     /* Have we stored something for this value already?  */
57     for (cur_loc = 0; cur_loc != kpse->saved_count; ++cur_loc) {
58         if (strncmp(kpse->saved_env[cur_loc], cur_item, var_lim) == 0) {
59             /* Get the old value.  We need this is case another part
60              * of the program didn't use us to change the environment.
61              */
62             old_item = getenv(var);
63             break;
64         }
65     }
66 
67     if (old_item && strcmp(old_item, cur_item+var_lim) == 0) {
68         /* Set same value as is in environment, don't bother to set. */
69         free(cur_item);
70         return;
71     } else {
72         /* We set a different value. */
73         if (putenv(cur_item) < 0)
74             LIB_FATAL1("putenv(%s)", cur_item);
75         /* Get the new string. */
76         new_item = getenv(var);
77         if (new_item != cur_item+var_lim) {
78             /* Our new string isn't used, don't keep it around. */
79             free(cur_item);
80             return;
81         }
82     }
83 
84     /* If we get here, it means getenv() returned a reference to cur_item.
85        So we save cur_item, and free the old string we also owned.  */
86     if (cur_loc == kpse->saved_count) {
87       /* No old string. */
88       kpse->saved_count++;
89       XRETALLOC(kpse->saved_env, kpse->saved_count, char *);
90     } else {
91       /* We owned the old string. */
92       free(kpse->saved_env[cur_loc]);
93     }
94     kpse->saved_env[cur_loc] = cur_item;
95 
96     return;
97 }
98 
99 /* A special case for setting a variable to a numeric value
100    (specifically, KPATHSEA_DPI).  We don't need to dynamically allocate
101    and free the string for the number, since it's saved as part of the
102    environment value.  */
103 
104 void
kpathsea_xputenv_int(kpathsea kpse,const_string var_name,int num)105 kpathsea_xputenv_int (kpathsea kpse, const_string var_name,  int num)
106 {
107   char str[MAX_INT_LENGTH];
108   sprintf (str, "%d", num);
109 
110   kpathsea_xputenv (kpse, var_name, str);
111 }
112 
113 #if defined (KPSE_COMPAT_API)
114 void
xputenv(const char * var,const char * value)115 xputenv (const char *var, const char *value)
116 {
117   kpathsea_xputenv (kpse_def, var, value);
118 }
119 
120 void
xputenv_int(const_string var_name,int num)121 xputenv_int (const_string var_name,  int num)
122 {
123   kpathsea_xputenv_int(kpse_def, var_name, num);
124 }
125 #endif
126