1 /** 2 * Functions for modifying environment variables. 3 * 4 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 5 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 6 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/env.d, env.d) 7 * Documentation: https://dlang.org/phobos/dmd_root_env.html 8 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/env.d 9 */ 10 11 module dmd.root.env; 12 13 import core.stdc.string; 14 import core.sys.posix.stdlib; 15 import dmd.root.array; 16 import dmd.root.rmem; 17 import dmd.root.string; 18 19 version (Windows) 20 private extern (C) int putenv(const char*) nothrow; 21 22 nothrow: 23 24 /** 25 Construct a variable from `name` and `value` and put it in the environment while saving 26 the previous value of the environment variable into a global list so it can be restored later. 27 Params: 28 name = the name of the variable 29 value = the value of the variable 30 Returns: 31 true on error, false on success 32 */ 33 bool putenvRestorable(const(char)[] name, const(char)[] value) nothrow 34 { 35 saveEnvVar(name); 36 const nameValue = allocNameValue(name, value); 37 const result = putenv(cast(char*)nameValue.ptr); 38 version (Windows) 39 mem.xfree(cast(void*)nameValue.ptr); 40 else 41 { 42 if (result) 43 mem.xfree(cast(void*)nameValue.ptr); 44 } 45 return result ? true : false; 46 } 47 48 /** 49 Allocate a new variable via xmalloc that can be added to the global environment. The 50 resulting string will be null-terminated immediately after the end of the array. 51 Params: 52 name = name of the variable 53 value = value of the variable 54 Returns: 55 a newly allocated variable that can be added to the global environment 56 */ 57 string allocNameValue(const(char)[] name, const(char)[] value) nothrow 58 { 59 const length = name.length + 1 + value.length; 60 auto str = (cast(char*)mem.xmalloc(length + 1))[0 .. length]; 61 str[0 .. name.length] = name[]; 62 str[name.length] = '='; 63 str[name.length + 1 .. length] = value[]; 64 str.ptr[length] = '\0'; 65 return cast(string)str; 66 } 67 68 /// Holds the original values of environment variables when they are overwritten. 69 private __gshared string[string] envNameValues; 70 71 /// Restore the original environment. 72 void restoreEnvVars() nothrow 73 { 74 foreach (var; envNameValues.values) 75 { 76 if (putenv(cast(char*)var.ptr)) 77 assert(0); 78 } 79 } 80 81 /// Save the environment variable `name` if not saved already. 82 void saveEnvVar(const(char)[] name) nothrow 83 { 84 if (!(name in envNameValues)) 85 { 86 envNameValues[name.idup] = allocNameValue(name, name.toCStringThen!(n => getenv(n.ptr)).toDString); 87 } 88 }