dvitomp fix from Akira
[mplib] / src / texk / kpathsea / xputenv.c
1 /* xputenv.c: set an environment variable without return. */
2
3 /* Copyright 1993-98, 2008 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
22 #ifdef WIN32
23 #include <stdlib.h>
24 #else
25 /* Avoid implicit declaration warning.  But since some systems do
26    declare it, don't use a prototype, for fear of conflicts.  */
27 extern int putenv ();
28 #endif /* not WIN32 */
29
30 /* These record the strings we've set and have to keep around.
31  * This function can be called many times during a run, and this
32  * allows us to reclaim memory we allocated.
33  */
34 static char **saved_env;
35 static int    saved_count;
36
37 /*
38  * We have different arguments from the "standard" function.  A separate
39  * var and value tends to be much more practical.
40  *
41  * The standards for putenv are clear: put the passed string into the
42  * environment, and if you alter that string, the environment changes.
43  * Of course various implementations are broken in a number of ways,
44  * which include making copies of the passed string, and more.
45  */
46 void
47 xputenv(const char *var, const char *value)
48 {
49     char  *cur_item;
50     char  *old_item;
51     char  *new_item;
52     size_t var_lim;
53     int    cur_loc;
54
55     /* kpse_debug2(KPSE_DEBUG_VARS, "kpse_putenv($%s,%s)", var, value); */
56     
57     old_item = NULL;
58     cur_item = concat3(var, "=", value);
59     /* Include '=' in length. */
60     var_lim = strlen(var) + 1;
61     
62     /* Have we stored something for this value already?  */
63     for (cur_loc = 0; cur_loc != saved_count; ++cur_loc) {
64         if (strncmp(saved_env[cur_loc], cur_item, var_lim) == 0) {
65             /* Get the old value.  We need this is case another part
66              * of the program didn't use us to change the environment.
67              */
68             old_item = getenv(var);
69             break;
70         }
71     }
72
73     if (old_item && strcmp(old_item, cur_item+var_lim) == 0) {
74         /* Set same value as is in environment, don't bother to set. */
75         free(cur_item);
76         return;
77     } else {
78         /* We set a different value. */
79         if (putenv(cur_item) < 0)
80             FATAL1("putenv(%s)", cur_item);
81         /* Get the new string. */
82         new_item = getenv(var);
83         if (new_item != cur_item+var_lim) {
84             /* Our new string isn't used, don't keep it around. */
85             free(cur_item);
86             return;
87         }
88     }
89
90     /* If we get here, it means getenv() returned a reference to cur_item.
91      * So we save cur_item, and free the old string we also owned.
92      */
93     if (cur_loc == saved_count) {
94         /* No old string. */
95         saved_count++;
96         saved_env = XRETALLOC(saved_env, saved_count, char *);
97     } else {
98         /* We owned the old string. */
99         free(saved_env[cur_loc]);
100     }
101     saved_env[cur_loc] = cur_item;
102
103     return;
104 }
105
106 /* A special case for setting a variable to a numeric value
107    (specifically, KPATHSEA_DPI).  We don't need to dynamically allocate
108    and free the string for the number, since it's saved as part of the
109    environment value.  */
110
111 void
112 xputenv_int P2C(const_string, var_name,  int, num)
113 {
114   char str[MAX_INT_LENGTH];
115   sprintf (str, "%d", num);
116   
117   xputenv (var_name, str);
118 }