2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * DESCRIPTION Routines to expand environment-variables into strings.
21 * Will understand both $ENV and ${ENV} -type variables.
23 * WRITTEN BY Sverre H. Huseby
28 * UPDATED migo - 21/Jun/1999 - added getFirstEnv, some changes
32 /* ---------------------------- included header files ---------------------- */
41 /* ---------------------------- local definitions -------------------------- */
44 #define FHaveUnsetenv 1
46 #define unsetenv(x) do { } while (0)
47 #define FHaveUnsetenv 0
50 /* ---------------------------- local macros ------------------------------- */
52 #define ENV_LIST_INC 10
57 /* ---------------------------- imports ------------------------------------ */
59 /* ---------------------------- included code files ------------------------ */
61 /* ---------------------------- local types -------------------------------- */
69 /* ---------------------------- forward declarations ----------------------- */
71 /* ---------------------------- local variables ---------------------------- */
73 /* ---------------------------- exported variables (globals) --------------- */
75 /* ---------------------------- local functions ---------------------------- */
77 /*-------------------------------------------------------------------------
81 * FUNCTION Delete characters from a string.
83 * INPUT s the string to delete characters from.
84 * idx index of first character to delete.
85 * n number of characters to delete.
87 * OUTPUT s string with characters deleted.
89 * DESCRIPTION Deletes characters from a string by moving following
93 static void strDel(char *s
, int idx
, int n
)
98 if (idx
>= (l
= strlen(s
)))
109 /*-------------------------------------------------------------------------
113 * FUNCTION Insert a string into a string.
115 * INPUT s the string to insert into.
116 * ins the string to insert.
117 * idx index of where to insert the string.
118 * maxstrlen max length of s, including '\0'.
120 * OUTPUT s string with characters inserted.
122 * DESCRIPTION The insertion will be done even if the string gets to
123 * long, but characters will be sacrificed at the end of s.
124 * The string is always '\0'-terminated.
127 static void strIns(char *s
, const char *ins
, int idx
, int maxstrlen
)
132 if (idx
> (l
= strlen(s
)))
137 move
= l
- idx
+ 1; /* include '\0' in move */
140 while (p2
>= s
+ maxstrlen
) {
148 if (idx
+ li
>= maxstrlen
)
150 li
= maxstrlen
- idx
- 1;
154 s
[maxstrlen
- 1] = '\0';
157 /*-------------------------------------------------------------------------
161 * FUNCTION Find first environment variable in a string.
163 * INPUT s the string to scan.
165 * OUTPUT len length of variable, including $ and { }.
167 * RETURNS Pointer to the $ that introduces the variable, or NULL
168 * if no variable is found.
170 * DESCRIPTION Searches for matches like $NAME and ${NAME}, where NAME is
171 * a sequence of characters, digits and underscores, of which
172 * the first can not be a digit.
174 * NOTE This function will only return `legal' variables. There
175 * may be $'s in the string that are not followed by what
176 * is considered a legal variable name introducer. Such
177 * occurrences are skipped.
180 static char *findEnvVar(const char *s
, int *len
)
191 (isalpha(*next
) || *next
== '_' || *next
== '{')) {
197 while (*s
&& (isalnum(*s
) || *s
== '_'))
214 /*-------------------------------------------------------------------------
216 * FUNCTION Look up environment variable.
218 * INPUT name name of environment variable to look up. This
219 * may include $ and { }.
220 * len length for environment variable name (0 - ignore).
222 * RETURNS The variable contents, or "" if not found.
225 static const char *getEnv(const char *name
, int len
)
227 static char *empty
= "";
228 char *ret
= NULL
, *tmp
, *p
, *p2
;
230 if ((tmp
= safestrdup(name
)) == NULL
)
231 return empty
; /* better than no test at all. */
237 if ((p2
= strchr(p
, '}')) != NULL
)
240 if (len
> 0 && len
< strlen(tmp
)) tmp
[len
] = '\0';
241 if ((ret
= getenv(p
)) == NULL
)
247 /* ---------------------------- interface functions ------------------------ */
250 * FUNCTION Expand environment variables in a string.
252 * SYNOPSIS #include "envvar.h"
253 * int envExpand(char *s, int maxstrlen);
255 * INPUT s string to expand environment variables in.
256 * maxstrlen max length of string, including '\0'.
258 * OUTPUT s the string with environment variables expanded.
260 * RETURNS Number of changes done.
262 * NOTES A non-existing variable is substituted with the empty
266 int envExpand(char *s
, int maxstrlen
)
273 while ((var
= findEnvVar(s2
, &len
)) != NULL
) {
275 env
= getEnv(var
, len
);
276 strDel(s
, var
- s
, len
);
277 strIns(s
, env
, var
- s
, maxstrlen
);
278 s2
= var
+ strlen(env
);
284 * FUNCTION Expand environment variables into a new string.
286 * SYNOPSIS #include "envvar.h"
287 * char *envDupExpand(const char *s, int extra);
289 * INPUT s string to expand environment variables in.
290 * extra number of extra bytes to allocate in the
291 * string, in addition to the string contents
292 * and the terminating '\0'.
294 * RETURNS A dynamically allocated string with environment
295 * variables expanded.
296 * Use free() to deallocate the buffer when it is no
298 * NULL is returned if there is not enough memory.
300 * NOTES A non-existing variable is substituted with the empty
304 char *envDupExpand(const char *s
, int extra
)
307 const char *env
, *s2
;
308 int len
, slen
, elen
, bufflen
;
311 * calculate length needed.
315 bufflen
= slen
+ 1 + extra
;
316 while ((var
= findEnvVar(s2
, &len
)) != NULL
) {
317 env
= getEnv(var
, len
);
319 /* need to make a buffer the maximum possible size, else we
320 * may get trouble while expanding. */
321 bufflen
+= len
> elen
? len
: elen
;
324 if (bufflen
< slen
+ 1)
327 ret
= safemalloc(bufflen
);
330 * now do the real expansion.
333 envExpand(ret
, bufflen
- extra
);
339 * FUNCTION Search for the first environment variable and return
340 * its contents and coordinates in the given string.
342 * INPUT s the string to scan.
343 * may include $ and { } that introduce variable.
345 * OUTPUT beg index in the string of matching $.
346 * end index in the string, first after matching var.
348 * RETURNS The variable contents; "" if env variable has legal name,
349 * but does not exist; or NULL if no env variables found.
350 * Returned constant string must not be deallocated.
352 * NOTE This function will only return `legal' variables. There
353 * may be $'s in the string that are not followed by what
354 * is considered a legal variable name introducer. Such
355 * occurrences are skipped.
356 * If nothing is found returns NULL and sets beg and end to 0.
358 * EXAMPLE getFirstEnv("echo $HOME/.fvwm/config", &beg, &end)
359 * returns "/home/username" and beg=5, end=10.
362 const char* getFirstEnv(const char *s
, int *beg
, int *end
)
369 if ((var
= findEnvVar(s
, &len
)) == NULL
) return NULL
;
370 env
= getEnv(var
, len
);
378 /* If env is NULL, var is removed from the environment list */
379 static void add_to_envlist(char *var
, char *env
)
381 static env_list_item
*env_list
= NULL
;
382 static unsigned int env_len
= 0;
383 static unsigned int env_len_allocated
= 0;
386 /* find string in list */
387 if (env_list
&& env_len
)
389 for (i
= 0; i
< env_len
; i
++)
391 if (strcmp(var
, env_list
[i
].var
) != 0)
395 /* found it - replace old string */
396 free(env_list
[i
].var
);
397 free(env_list
[i
].env
);
403 env_list
[env_len
].var
;
405 env_list
[env_len
].env
;
410 env_list
[i
].var
= var
;
411 env_list
[i
].env
= env
;
422 if (env_list
== NULL
)
424 /* list is still empty */
425 env_len_allocated
= ENV_LIST_INC
;
426 env_list
= (env_list_item
*)safecalloc(
427 sizeof(env_list_item
), env_len_allocated
);
429 else if (env_len
>= env_len_allocated
&& env
!= NULL
)
431 /* need more memory */
432 env_len_allocated
= env_len
+ ENV_LIST_INC
;
433 env_list
= (env_list_item
*)saferealloc(
434 (void *)env_list
, (env_len_allocated
) *
435 sizeof(env_list_item
));
437 env_list
[env_len
].var
= var
;
438 env_list
[env_len
].env
= env
;
444 /* This function keeps a list of all strings that were set in the environment.
445 * If a variable is written again, the old memory is freed. This function
446 * should be called instead of putenv().
448 * var - environement variable name
449 * env - environment string ("variable=value")
451 * Both arguments are copied internally and should be freed after calling this
454 void flib_putenv(char *var
, char *env
)
463 add_to_envlist(var
, env
);
468 void flib_unsetenv(const char *name
)
478 /* try putenv without '=' */
479 rc
= putenv((char *)name
);
480 if (rc
== 0 || getenv(name
) != NULL
)
482 /* failed, write empty string */
483 flib_putenv((char *)name
, "");
487 add_to_envlist((char *)name
, NULL
);