summaryrefslogtreecommitdiffstats
path: root/winpr/libwinpr/environment
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:24:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:24:41 +0000
commita9bcc81f821d7c66f623779fa5147e728eb3c388 (patch)
tree98676963bcdd537ae5908a067a8eb110b93486a6 /winpr/libwinpr/environment
parentInitial commit. (diff)
downloadfreerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.tar.xz
freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.zip
Adding upstream version 3.3.0+dfsg1.upstream/3.3.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'winpr/libwinpr/environment')
-rw-r--r--winpr/libwinpr/environment/CMakeLists.txt22
-rw-r--r--winpr/libwinpr/environment/ModuleOptions.cmake9
-rw-r--r--winpr/libwinpr/environment/environment.c708
-rw-r--r--winpr/libwinpr/environment/test/CMakeLists.txt28
-rw-r--r--winpr/libwinpr/environment/test/TestEnvironmentGetEnvironmentStrings.c43
-rw-r--r--winpr/libwinpr/environment/test/TestEnvironmentGetSetEB.c138
-rw-r--r--winpr/libwinpr/environment/test/TestEnvironmentMergeEnvironmentStrings.c34
-rw-r--r--winpr/libwinpr/environment/test/TestEnvironmentSetEnvironmentVariable.c72
8 files changed, 1054 insertions, 0 deletions
diff --git a/winpr/libwinpr/environment/CMakeLists.txt b/winpr/libwinpr/environment/CMakeLists.txt
new file mode 100644
index 0000000..53c2818
--- /dev/null
+++ b/winpr/libwinpr/environment/CMakeLists.txt
@@ -0,0 +1,22 @@
+# WinPR: Windows Portable Runtime
+# libwinpr-environment cmake build script
+#
+# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+winpr_module_add(environment.c)
+
+if(BUILD_TESTING)
+ add_subdirectory(test)
+endif()
diff --git a/winpr/libwinpr/environment/ModuleOptions.cmake b/winpr/libwinpr/environment/ModuleOptions.cmake
new file mode 100644
index 0000000..d7b39ae
--- /dev/null
+++ b/winpr/libwinpr/environment/ModuleOptions.cmake
@@ -0,0 +1,9 @@
+
+set(MINWIN_LAYER "1")
+set(MINWIN_GROUP "core")
+set(MINWIN_MAJOR_VERSION "2")
+set(MINWIN_MINOR_VERSION "0")
+set(MINWIN_SHORT_NAME "processenvironment")
+set(MINWIN_LONG_NAME "Process Environment Functions")
+set(MODULE_LIBRARY_NAME "api-ms-win-${MINWIN_GROUP}-${MINWIN_SHORT_NAME}-l${MINWIN_LAYER}-${MINWIN_MAJOR_VERSION}-${MINWIN_MINOR_VERSION}")
+
diff --git a/winpr/libwinpr/environment/environment.c b/winpr/libwinpr/environment/environment.c
new file mode 100644
index 0000000..c6df6bd
--- /dev/null
+++ b/winpr/libwinpr/environment/environment.c
@@ -0,0 +1,708 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Process Environment Functions
+ *
+ * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ * Copyright 2013 Thincast Technologies GmbH
+ * Copyright 2013 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <winpr/config.h>
+
+#include <winpr/crt.h>
+#include <winpr/platform.h>
+#include <winpr/error.h>
+#include <winpr/string.h>
+
+#include <winpr/environment.h>
+
+#ifndef _WIN32
+
+#ifdef WINPR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if defined(__IOS__)
+
+#elif defined(__MACOSX__)
+#include <crt_externs.h>
+#define environ (*_NSGetEnviron())
+#endif
+
+DWORD GetCurrentDirectoryA(DWORD nBufferLength, LPSTR lpBuffer)
+{
+ char* cwd = NULL;
+ size_t length = 0;
+
+ cwd = getcwd(NULL, 0);
+
+ if (!cwd)
+ return 0;
+
+ length = strlen(cwd);
+
+ if ((nBufferLength == 0) && (lpBuffer == NULL))
+ {
+ free(cwd);
+
+ return (DWORD)length;
+ }
+ else
+ {
+ if (lpBuffer == NULL)
+ {
+ free(cwd);
+ return 0;
+ }
+
+ if ((length + 1) > nBufferLength)
+ {
+ free(cwd);
+ return (DWORD)(length + 1);
+ }
+
+ memcpy(lpBuffer, cwd, length + 1);
+ free(cwd);
+ return (DWORD)length;
+ }
+}
+
+DWORD GetCurrentDirectoryW(DWORD nBufferLength, LPWSTR lpBuffer)
+{
+ return 0;
+}
+
+BOOL SetCurrentDirectoryA(LPCSTR lpPathName)
+{
+ return TRUE;
+}
+
+BOOL SetCurrentDirectoryW(LPCWSTR lpPathName)
+{
+ return TRUE;
+}
+
+DWORD SearchPathA(LPCSTR lpPath, LPCSTR lpFileName, LPCSTR lpExtension, DWORD nBufferLength,
+ LPSTR lpBuffer, LPSTR* lpFilePart)
+{
+ return 0;
+}
+
+DWORD SearchPathW(LPCWSTR lpPath, LPCWSTR lpFileName, LPCWSTR lpExtension, DWORD nBufferLength,
+ LPWSTR lpBuffer, LPWSTR* lpFilePart)
+{
+ return 0;
+}
+
+LPSTR GetCommandLineA(VOID)
+{
+ return NULL;
+}
+
+LPWSTR GetCommandLineW(VOID)
+{
+ return NULL;
+}
+
+BOOL NeedCurrentDirectoryForExePathA(LPCSTR ExeName)
+{
+ return TRUE;
+}
+
+BOOL NeedCurrentDirectoryForExePathW(LPCWSTR ExeName)
+{
+ return TRUE;
+}
+
+#endif
+
+#if !defined(_WIN32) || defined(_UWP)
+
+DWORD GetEnvironmentVariableA(LPCSTR lpName, LPSTR lpBuffer, DWORD nSize)
+{
+#if !defined(_UWP)
+ size_t length = 0;
+ char* env = NULL;
+
+ env = getenv(lpName);
+
+ if (!env)
+ {
+ SetLastError(ERROR_ENVVAR_NOT_FOUND);
+ return 0;
+ }
+
+ length = strlen(env);
+
+ if ((length + 1 > nSize) || (!lpBuffer))
+ return (DWORD)length + 1;
+
+ CopyMemory(lpBuffer, env, length);
+ lpBuffer[length] = '\0';
+
+ return (DWORD)length;
+#else
+ SetLastError(ERROR_ENVVAR_NOT_FOUND);
+ return 0;
+#endif
+}
+
+DWORD GetEnvironmentVariableW(LPCWSTR lpName, LPWSTR lpBuffer, DWORD nSize)
+{
+ SetLastError(ERROR_ENVVAR_NOT_FOUND);
+ return 0;
+}
+
+BOOL SetEnvironmentVariableA(LPCSTR lpName, LPCSTR lpValue)
+{
+#if !defined(_UWP)
+ if (!lpName)
+ return FALSE;
+
+ if (lpValue)
+ {
+ if (0 != setenv(lpName, lpValue, 1))
+ return FALSE;
+ }
+ else
+ {
+ if (0 != unsetenv(lpName))
+ return FALSE;
+ }
+
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+BOOL SetEnvironmentVariableW(LPCWSTR lpName, LPCWSTR lpValue)
+{
+ return FALSE;
+}
+
+/**
+ * GetEnvironmentStrings function:
+ * http://msdn.microsoft.com/en-us/library/windows/desktop/ms683187/
+ *
+ * The GetEnvironmentStrings function returns a pointer to a block of memory
+ * that contains the environment variables of the calling process (both the
+ * system and the user environment variables). Each environment block contains
+ * the environment variables in the following format:
+ *
+ * Var1=Value1\0
+ * Var2=Value2\0
+ * Var3=Value3\0
+ * ...
+ * VarN=ValueN\0\0
+ */
+
+extern char** environ;
+
+LPCH GetEnvironmentStringsA(VOID)
+{
+#if !defined(_UWP)
+ char* p = NULL;
+ size_t offset = 0;
+ size_t length = 0;
+ char** envp = NULL;
+ DWORD cchEnvironmentBlock = 0;
+ LPCH lpszEnvironmentBlock = NULL;
+
+ offset = 0;
+ envp = environ;
+
+ cchEnvironmentBlock = 128;
+ lpszEnvironmentBlock = (LPCH)calloc(cchEnvironmentBlock, sizeof(CHAR));
+ if (!lpszEnvironmentBlock)
+ return NULL;
+
+ while (*envp)
+ {
+ length = strlen(*envp);
+
+ while ((offset + length + 8) > cchEnvironmentBlock)
+ {
+ DWORD new_size = 0;
+ LPCH new_blk = NULL;
+
+ new_size = cchEnvironmentBlock * 2;
+ new_blk = (LPCH)realloc(lpszEnvironmentBlock, new_size * sizeof(CHAR));
+ if (!new_blk)
+ {
+ free(lpszEnvironmentBlock);
+ return NULL;
+ }
+
+ lpszEnvironmentBlock = new_blk;
+ cchEnvironmentBlock = new_size;
+ }
+
+ p = &(lpszEnvironmentBlock[offset]);
+
+ CopyMemory(p, *envp, length * sizeof(CHAR));
+ p[length] = '\0';
+
+ offset += (length + 1);
+ envp++;
+ }
+
+ lpszEnvironmentBlock[offset] = '\0';
+
+ return lpszEnvironmentBlock;
+#else
+ return NULL;
+#endif
+}
+
+LPWCH GetEnvironmentStringsW(VOID)
+{
+ return NULL;
+}
+
+BOOL SetEnvironmentStringsA(LPCH NewEnvironment)
+{
+ return TRUE;
+}
+
+BOOL SetEnvironmentStringsW(LPWCH NewEnvironment)
+{
+ return TRUE;
+}
+
+DWORD ExpandEnvironmentStringsA(LPCSTR lpSrc, LPSTR lpDst, DWORD nSize)
+{
+ return 0;
+}
+
+DWORD ExpandEnvironmentStringsW(LPCWSTR lpSrc, LPWSTR lpDst, DWORD nSize)
+{
+ return 0;
+}
+
+BOOL FreeEnvironmentStringsA(LPCH lpszEnvironmentBlock)
+{
+ free(lpszEnvironmentBlock);
+
+ return TRUE;
+}
+
+BOOL FreeEnvironmentStringsW(LPWCH lpszEnvironmentBlock)
+{
+ return TRUE;
+}
+
+#endif
+
+LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge)
+{
+ const char* cp = NULL;
+ char* p = NULL;
+ size_t offset = 0;
+ size_t length = 0;
+ const char* envp = NULL;
+ DWORD cchEnvironmentBlock = 0;
+ LPCH lpszEnvironmentBlock = NULL;
+ const char** mergeStrings = NULL;
+ size_t mergeStringLength = 0;
+ size_t mergeArraySize = 128;
+ size_t mergeLength = 0;
+ size_t foundMerge = 0;
+ char* foundEquals = NULL;
+
+ mergeStrings = (LPCSTR*)calloc(mergeArraySize, sizeof(char*));
+
+ if (!mergeStrings)
+ return NULL;
+
+ mergeStringLength = 0;
+
+ cp = merge;
+
+ while (*cp && *(cp + 1))
+ {
+ length = strlen(cp);
+
+ if (mergeStringLength == mergeArraySize)
+ {
+ const char** new_str = NULL;
+
+ mergeArraySize += 128;
+ new_str = (const char**)realloc((void*)mergeStrings, mergeArraySize * sizeof(char*));
+
+ if (!new_str)
+ {
+ free((void*)mergeStrings);
+ return NULL;
+ }
+ mergeStrings = new_str;
+ }
+
+ mergeStrings[mergeStringLength] = cp;
+ cp += length + 1;
+ mergeStringLength++;
+ }
+
+ offset = 0;
+
+ cchEnvironmentBlock = 128;
+ lpszEnvironmentBlock = (LPCH)calloc(cchEnvironmentBlock, sizeof(CHAR));
+
+ if (!lpszEnvironmentBlock)
+ {
+ free((void*)mergeStrings);
+ return NULL;
+ }
+
+ envp = original;
+
+ while ((original != NULL) && (*envp && *(envp + 1)))
+ {
+ size_t old_offset = offset;
+ length = strlen(envp);
+
+ while ((offset + length + 8) > cchEnvironmentBlock)
+ {
+ cchEnvironmentBlock *= 2;
+ LPCH tmp = (LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
+
+ if (!tmp)
+ {
+ free((void*)lpszEnvironmentBlock);
+ free((void*)mergeStrings);
+ return NULL;
+ }
+ lpszEnvironmentBlock = tmp;
+ }
+
+ p = &(lpszEnvironmentBlock[offset]);
+
+ // check if this value is in the mergeStrings
+ foundMerge = 0;
+ for (size_t run = 0; run < mergeStringLength; run++)
+ {
+ if (!mergeStrings[run])
+ continue;
+
+ mergeLength = strlen(mergeStrings[run]);
+ foundEquals = strstr(mergeStrings[run], "=");
+
+ if (!foundEquals)
+ continue;
+
+ if (strncmp(envp, mergeStrings[run], foundEquals - mergeStrings[run] + 1) == 0)
+ {
+ // found variable in merge list ... use this ....
+ if (*(foundEquals + 1) == '\0')
+ {
+ // check if the argument is set ... if not remove variable ...
+ foundMerge = 1;
+ }
+ else
+ {
+ while ((offset + mergeLength + 8) > cchEnvironmentBlock)
+ {
+ cchEnvironmentBlock *= 2;
+ LPCH tmp =
+ (LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
+
+ if (!tmp)
+ {
+ free((void*)lpszEnvironmentBlock);
+ free((void*)mergeStrings);
+ return NULL;
+ }
+ lpszEnvironmentBlock = tmp;
+ p = &(lpszEnvironmentBlock[old_offset]);
+ }
+
+ foundMerge = 1;
+ CopyMemory(p, mergeStrings[run], mergeLength);
+ mergeStrings[run] = NULL;
+ p[mergeLength] = '\0';
+ offset += (mergeLength + 1);
+ }
+ }
+ }
+
+ if (foundMerge == 0)
+ {
+ CopyMemory(p, envp, length * sizeof(CHAR));
+ p[length] = '\0';
+ offset += (length + 1);
+ }
+
+ envp += (length + 1);
+ }
+
+ // now merge the not already merged env
+ for (size_t run = 0; run < mergeStringLength; run++)
+ {
+ if (!mergeStrings[run])
+ continue;
+
+ mergeLength = strlen(mergeStrings[run]);
+
+ while ((offset + mergeLength + 8) > cchEnvironmentBlock)
+ {
+ cchEnvironmentBlock *= 2;
+ LPCH tmp = (LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
+
+ if (!tmp)
+ {
+ free((void*)lpszEnvironmentBlock);
+ free((void*)mergeStrings);
+ return NULL;
+ }
+
+ lpszEnvironmentBlock = tmp;
+ }
+
+ p = &(lpszEnvironmentBlock[offset]);
+
+ CopyMemory(p, mergeStrings[run], mergeLength);
+ mergeStrings[run] = NULL;
+ p[mergeLength] = '\0';
+ offset += (mergeLength + 1);
+ }
+
+ lpszEnvironmentBlock[offset] = '\0';
+
+ free((void*)mergeStrings);
+
+ return lpszEnvironmentBlock;
+}
+
+DWORD GetEnvironmentVariableEBA(LPCSTR envBlock, LPCSTR lpName, LPSTR lpBuffer, DWORD nSize)
+{
+ size_t vLength = 0;
+ char* env = NULL;
+ char* foundEquals = NULL;
+ const char* penvb = envBlock;
+ size_t nLength = 0;
+ size_t fLength = 0;
+ size_t lpNameLength = 0;
+
+ if (!lpName || NULL == envBlock)
+ return 0;
+
+ lpNameLength = strlen(lpName);
+
+ if (lpNameLength < 1)
+ return 0;
+
+ while (*penvb && *(penvb + 1))
+ {
+ fLength = strlen(penvb);
+ foundEquals = strstr(penvb, "=");
+
+ if (!foundEquals)
+ {
+ /* if no = sign is found the envBlock is broken */
+ return 0;
+ }
+
+ nLength = (foundEquals - penvb);
+
+ if (nLength != lpNameLength)
+ {
+ penvb += (fLength + 1);
+ continue;
+ }
+
+ if (strncmp(penvb, lpName, nLength) == 0)
+ {
+ env = foundEquals + 1;
+ break;
+ }
+
+ penvb += (fLength + 1);
+ }
+
+ if (!env)
+ return 0;
+
+ vLength = strlen(env);
+ if (vLength >= UINT32_MAX)
+ return 0;
+
+ if ((vLength + 1 > nSize) || (!lpBuffer))
+ return (DWORD)vLength + 1;
+
+ CopyMemory(lpBuffer, env, vLength + 1);
+
+ return (DWORD)vLength;
+}
+
+BOOL SetEnvironmentVariableEBA(LPSTR* envBlock, LPCSTR lpName, LPCSTR lpValue)
+{
+ size_t length = 0;
+ char* envstr = NULL;
+ char* newEB = NULL;
+
+ if (!lpName)
+ return FALSE;
+
+ if (lpValue)
+ {
+ length = (strlen(lpName) + strlen(lpValue) + 2); /* +2 because of = and \0 */
+ envstr = (char*)malloc(length + 1); /* +1 because of closing \0 */
+
+ if (!envstr)
+ return FALSE;
+
+ sprintf_s(envstr, length, "%s=%s", lpName, lpValue);
+ }
+ else
+ {
+ length = strlen(lpName) + 2; /* +2 because of = and \0 */
+ envstr = (char*)malloc(length + 1); /* +1 because of closing \0 */
+
+ if (!envstr)
+ return FALSE;
+
+ sprintf_s(envstr, length, "%s=", lpName);
+ }
+
+ envstr[length] = '\0';
+
+ newEB = MergeEnvironmentStrings((LPCSTR)*envBlock, envstr);
+
+ free(envstr);
+ free(*envBlock);
+
+ *envBlock = newEB;
+
+ return TRUE;
+}
+
+char** EnvironmentBlockToEnvpA(LPCH lpszEnvironmentBlock)
+{
+ char* p = NULL;
+ SSIZE_T index = 0;
+ size_t count = 0;
+ size_t length = 0;
+ char** envp = NULL;
+
+ count = 0;
+ if (!lpszEnvironmentBlock)
+ return NULL;
+
+ p = (char*)lpszEnvironmentBlock;
+
+ while (p[0] && p[1])
+ {
+ length = strlen(p);
+ p += (length + 1);
+ count++;
+ }
+
+ index = 0;
+ p = (char*)lpszEnvironmentBlock;
+
+ envp = (char**)calloc(count + 1, sizeof(char*));
+ if (!envp)
+ return NULL;
+ envp[count] = NULL;
+
+ while (p[0] && p[1])
+ {
+ length = strlen(p);
+ envp[index] = _strdup(p);
+ if (!envp[index])
+ {
+ for (index -= 1; index >= 0; --index)
+ {
+ free(envp[index]);
+ }
+ free(envp);
+ return NULL;
+ }
+ p += (length + 1);
+ index++;
+ }
+
+ return envp;
+}
+
+#ifdef _WIN32
+
+// https://devblogs.microsoft.com/oldnewthing/20100203-00/?p=15083
+#define WINPR_MAX_ENVIRONMENT_LENGTH 2048
+
+DWORD GetEnvironmentVariableX(const char* lpName, char* lpBuffer, DWORD nSize)
+{
+ DWORD result = 0;
+ DWORD nSizeW = 0;
+ LPWSTR lpNameW = NULL;
+ LPWSTR lpBufferW = NULL;
+ LPSTR lpBufferA = lpBuffer;
+
+ lpNameW = ConvertUtf8ToWCharAlloc(lpName, NULL);
+ if (!lpNameW)
+ goto cleanup;
+
+ if (!lpBuffer)
+ {
+ char lpBufferMaxA[WINPR_MAX_ENVIRONMENT_LENGTH] = { 0 };
+ WCHAR lpBufferMaxW[WINPR_MAX_ENVIRONMENT_LENGTH] = { 0 };
+ LPSTR lpTmpBuffer = lpBufferMaxA;
+
+ nSizeW = ARRAYSIZE(lpBufferMaxW);
+
+ result = GetEnvironmentVariableW(lpNameW, lpBufferMaxW, nSizeW);
+
+ SSIZE_T rc =
+ ConvertWCharNToUtf8(lpBufferMaxW, nSizeW, lpTmpBuffer, ARRAYSIZE(lpBufferMaxA));
+ if ((rc < 0) || (rc >= UINT32_MAX))
+ goto cleanup;
+
+ result = (DWORD)rc + 1;
+ }
+ else
+ {
+ nSizeW = nSize;
+ lpBufferW = calloc(nSizeW + 1, sizeof(WCHAR));
+
+ if (!lpBufferW)
+ goto cleanup;
+
+ result = GetEnvironmentVariableW(lpNameW, lpBufferW, nSizeW);
+
+ if (result == 0)
+ goto cleanup;
+
+ SSIZE_T rc = ConvertWCharNToUtf8(lpBufferW, nSizeW, lpBufferA, nSize);
+ if ((rc < 0) || (rc > UINT32_MAX))
+ goto cleanup;
+
+ result = (DWORD)rc;
+ }
+
+cleanup:
+ free(lpBufferW);
+ free(lpNameW);
+
+ return result;
+}
+
+#else
+
+DWORD GetEnvironmentVariableX(const char* lpName, char* lpBuffer, DWORD nSize)
+{
+ return GetEnvironmentVariableA(lpName, lpBuffer, nSize);
+}
+
+#endif
diff --git a/winpr/libwinpr/environment/test/CMakeLists.txt b/winpr/libwinpr/environment/test/CMakeLists.txt
new file mode 100644
index 0000000..459d425
--- /dev/null
+++ b/winpr/libwinpr/environment/test/CMakeLists.txt
@@ -0,0 +1,28 @@
+
+set(MODULE_NAME "TestEnvironment")
+set(MODULE_PREFIX "TEST_ENVIRONMENT")
+
+set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
+
+set(${MODULE_PREFIX}_TESTS
+ TestEnvironmentGetEnvironmentStrings.c
+ TestEnvironmentSetEnvironmentVariable.c
+ TestEnvironmentMergeEnvironmentStrings.c
+ TestEnvironmentGetSetEB.c)
+
+create_test_sourcelist(${MODULE_PREFIX}_SRCS
+ ${${MODULE_PREFIX}_DRIVER}
+ ${${MODULE_PREFIX}_TESTS})
+
+add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
+
+target_link_libraries(${MODULE_NAME} winpr)
+
+set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
+
+foreach(test ${${MODULE_PREFIX}_TESTS})
+ get_filename_component(TestName ${test} NAME_WE)
+ add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
+endforeach()
+
+set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
diff --git a/winpr/libwinpr/environment/test/TestEnvironmentGetEnvironmentStrings.c b/winpr/libwinpr/environment/test/TestEnvironmentGetEnvironmentStrings.c
new file mode 100644
index 0000000..c596399
--- /dev/null
+++ b/winpr/libwinpr/environment/test/TestEnvironmentGetEnvironmentStrings.c
@@ -0,0 +1,43 @@
+
+#include <stdio.h>
+#include <winpr/crt.h>
+#include <winpr/tchar.h>
+#include <winpr/environment.h>
+
+int TestEnvironmentGetEnvironmentStrings(int argc, char* argv[])
+{
+ int r = -1;
+ TCHAR* p = NULL;
+ size_t length = 0;
+ LPTCH lpszEnvironmentBlock = NULL;
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ lpszEnvironmentBlock = GetEnvironmentStrings();
+
+ p = lpszEnvironmentBlock;
+
+ while (p[0] && p[1])
+ {
+ const int rc = _sntprintf(NULL, 0, _T("%s\n"), p);
+ if (rc < 1)
+ {
+ _tprintf(_T("test failed: return %d\n"), rc);
+ goto fail;
+ }
+ length = _tcslen(p);
+ if (length != (size_t)(rc - 1))
+ {
+ _tprintf(_T("test failed: length %") _T(PRIuz) _T(" != %d [%s]\n"), length, rc - 1, p);
+ goto fail;
+ }
+ p += (length + 1);
+ }
+
+ r = 0;
+fail:
+ FreeEnvironmentStrings(lpszEnvironmentBlock);
+
+ return r;
+}
diff --git a/winpr/libwinpr/environment/test/TestEnvironmentGetSetEB.c b/winpr/libwinpr/environment/test/TestEnvironmentGetSetEB.c
new file mode 100644
index 0000000..603b4c2
--- /dev/null
+++ b/winpr/libwinpr/environment/test/TestEnvironmentGetSetEB.c
@@ -0,0 +1,138 @@
+
+#include <stdio.h>
+#include <winpr/crt.h>
+#include <winpr/tchar.h>
+#include <winpr/environment.h>
+
+int TestEnvironmentGetSetEB(int argc, char* argv[])
+{
+ int rc = 0;
+#ifndef _WIN32
+ char test[1024];
+ TCHAR* p = NULL;
+ DWORD length = 0;
+ LPTCH lpszEnvironmentBlock = "SHELL=123\0test=1\0test1=2\0DISPLAY=WINPR_TEST_VALUE\0\0";
+ LPTCH lpszEnvironmentBlockNew = NULL;
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ rc = -1;
+ /* Get length of an variable */
+ length = GetEnvironmentVariableEBA(lpszEnvironmentBlock, "DISPLAY", NULL, 0);
+
+ if (0 == length)
+ return -1;
+
+ /* Get the variable itself */
+ p = (LPSTR)malloc(length);
+
+ if (!p)
+ goto fail;
+
+ if (GetEnvironmentVariableEBA(lpszEnvironmentBlock, "DISPLAY", p, length) != length - 1)
+ goto fail;
+
+ printf("GetEnvironmentVariableA(WINPR_TEST_VARIABLE) = %s\n", p);
+
+ if (strcmp(p, "WINPR_TEST_VALUE") != 0)
+ goto fail;
+
+ /* Get length of an non-existing variable */
+ length = GetEnvironmentVariableEBA(lpszEnvironmentBlock, "BLA", NULL, 0);
+
+ if (0 != length)
+ {
+ printf("Unset variable returned\n");
+ goto fail;
+ }
+
+ /* Get length of an similar called variables */
+ length = GetEnvironmentVariableEBA(lpszEnvironmentBlock, "XDISPLAY", NULL, 0);
+
+ if (0 != length)
+ {
+ printf("Similar named variable returned (XDISPLAY, length %d)\n", length);
+ goto fail;
+ }
+
+ length = GetEnvironmentVariableEBA(lpszEnvironmentBlock, "DISPLAYX", NULL, 0);
+
+ if (0 != length)
+ {
+ printf("Similar named variable returned (DISPLAYX, length %d)\n", length);
+ goto fail;
+ }
+
+ length = GetEnvironmentVariableEBA(lpszEnvironmentBlock, "DISPLA", NULL, 0);
+
+ if (0 != length)
+ {
+ printf("Similar named variable returned (DISPLA, length %d)\n", length);
+ goto fail;
+ }
+
+ length = GetEnvironmentVariableEBA(lpszEnvironmentBlock, "ISPLAY", NULL, 0);
+
+ if (0 != length)
+ {
+ printf("Similar named variable returned (ISPLAY, length %d)\n", length);
+ goto fail;
+ }
+
+ /* Set variable in empty environment block */
+ if (SetEnvironmentVariableEBA(&lpszEnvironmentBlockNew, "test", "5"))
+ {
+ if (GetEnvironmentVariableEBA(lpszEnvironmentBlockNew, "test", test, 1023))
+ {
+ if (strcmp(test, "5") != 0)
+ goto fail;
+ }
+ else
+ goto fail;
+ }
+
+ /* Clear variable */
+ if (SetEnvironmentVariableEBA(&lpszEnvironmentBlockNew, "test", NULL))
+ {
+ if (GetEnvironmentVariableEBA(lpszEnvironmentBlockNew, "test", test, 1023))
+ goto fail;
+ else
+ {
+ // not found .. this is expected
+ }
+ }
+
+ free(lpszEnvironmentBlockNew);
+ lpszEnvironmentBlockNew = (LPTCH)calloc(1024, sizeof(TCHAR));
+
+ if (!lpszEnvironmentBlockNew)
+ goto fail;
+
+ memcpy(lpszEnvironmentBlockNew, lpszEnvironmentBlock, length);
+
+ /* Set variable in empty environment block */
+ if (SetEnvironmentVariableEBA(&lpszEnvironmentBlockNew, "test", "5"))
+ {
+ if (0 != GetEnvironmentVariableEBA(lpszEnvironmentBlockNew, "testr", test, 1023))
+ {
+ printf("GetEnvironmentVariableEBA returned unset variable\n");
+ goto fail;
+ }
+
+ if (GetEnvironmentVariableEBA(lpszEnvironmentBlockNew, "test", test, 1023))
+ {
+ if (strcmp(test, "5") != 0)
+ goto fail;
+ }
+ else
+ goto fail;
+ }
+
+ rc = 0;
+fail:
+ free(p);
+ free(lpszEnvironmentBlockNew);
+#endif
+ return rc;
+}
diff --git a/winpr/libwinpr/environment/test/TestEnvironmentMergeEnvironmentStrings.c b/winpr/libwinpr/environment/test/TestEnvironmentMergeEnvironmentStrings.c
new file mode 100644
index 0000000..428418d
--- /dev/null
+++ b/winpr/libwinpr/environment/test/TestEnvironmentMergeEnvironmentStrings.c
@@ -0,0 +1,34 @@
+
+#include <stdio.h>
+#include <winpr/crt.h>
+#include <winpr/tchar.h>
+#include <winpr/environment.h>
+
+int TestEnvironmentMergeEnvironmentStrings(int argc, char* argv[])
+{
+#ifndef _WIN32
+ TCHAR* p = NULL;
+ size_t length = 0;
+ LPTCH lpszEnvironmentBlock = NULL;
+ LPTCH lpsz2Merge = "SHELL=123\0test=1\0test1=2\0DISPLAY=:77\0\0";
+ LPTCH lpszMergedEnvironmentBlock = NULL;
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ lpszEnvironmentBlock = GetEnvironmentStrings();
+ lpszMergedEnvironmentBlock = MergeEnvironmentStrings(lpszEnvironmentBlock, lpsz2Merge);
+ p = (TCHAR*)lpszMergedEnvironmentBlock;
+
+ while (p[0] && p[1])
+ {
+ printf("%s\n", p);
+ length = strlen(p);
+ p += (length + 1);
+ }
+
+ FreeEnvironmentStrings(lpszMergedEnvironmentBlock);
+ FreeEnvironmentStrings(lpszEnvironmentBlock);
+#endif
+ return 0;
+}
diff --git a/winpr/libwinpr/environment/test/TestEnvironmentSetEnvironmentVariable.c b/winpr/libwinpr/environment/test/TestEnvironmentSetEnvironmentVariable.c
new file mode 100644
index 0000000..04b7064
--- /dev/null
+++ b/winpr/libwinpr/environment/test/TestEnvironmentSetEnvironmentVariable.c
@@ -0,0 +1,72 @@
+
+#include <stdio.h>
+#include <winpr/crt.h>
+#include <winpr/tchar.h>
+#include <winpr/environment.h>
+#include <winpr/error.h>
+
+#define TEST_NAME "WINPR_TEST_VARIABLE"
+#define TEST_VALUE "WINPR_TEST_VALUE"
+int TestEnvironmentSetEnvironmentVariable(int argc, char* argv[])
+{
+ int rc = -1;
+ DWORD nSize = 0;
+ LPSTR lpBuffer = NULL;
+ DWORD error = 0;
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ SetEnvironmentVariableA(TEST_NAME, TEST_VALUE);
+ nSize = GetEnvironmentVariableA(TEST_NAME, NULL, 0);
+
+ /* check if value returned is len + 1 ) */
+ if (nSize != strnlen(TEST_VALUE, sizeof(TEST_VALUE)) + 1)
+ {
+ printf("GetEnvironmentVariableA not found error\n");
+ return -1;
+ }
+
+ lpBuffer = (LPSTR)malloc(nSize);
+
+ if (!lpBuffer)
+ return -1;
+
+ nSize = GetEnvironmentVariableA(TEST_NAME, lpBuffer, nSize);
+
+ if (nSize != strnlen(TEST_VALUE, sizeof(TEST_VALUE)))
+ {
+ printf("GetEnvironmentVariableA wrong size returned\n");
+ goto fail;
+ }
+
+ if (strcmp(lpBuffer, TEST_VALUE) != 0)
+ {
+ printf("GetEnvironmentVariableA returned value doesn't match\n");
+ goto fail;
+ }
+
+ nSize = GetEnvironmentVariableA("__xx__notset_", lpBuffer, nSize);
+ error = GetLastError();
+
+ if (0 != nSize || ERROR_ENVVAR_NOT_FOUND != error)
+ {
+ printf("GetEnvironmentVariableA not found error\n");
+ goto fail;
+ }
+
+ /* clear variable */
+ SetEnvironmentVariableA(TEST_NAME, NULL);
+ nSize = GetEnvironmentVariableA(TEST_VALUE, NULL, 0);
+
+ if (0 != nSize)
+ {
+ printf("SetEnvironmentVariableA failed to clear variable\n");
+ goto fail;
+ }
+
+ rc = 0;
+fail:
+ free(lpBuffer);
+ return rc;
+}