summaryrefslogtreecommitdiffstats
path: root/private/mvdm/dos/command/cmdenv.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/mvdm/dos/command/cmdenv.c')
-rw-r--r--private/mvdm/dos/command/cmdenv.c696
1 files changed, 696 insertions, 0 deletions
diff --git a/private/mvdm/dos/command/cmdenv.c b/private/mvdm/dos/command/cmdenv.c
new file mode 100644
index 000000000..6bbf509e2
--- /dev/null
+++ b/private/mvdm/dos/command/cmdenv.c
@@ -0,0 +1,696 @@
+
+/* cmdenv.c - Environment supporting functions for command.lib
+ *
+ *
+ * Modification History:
+ *
+ * williamh 13-May-1993 Created
+ */
+
+#include "cmd.h"
+
+#include <cmdsvc.h>
+#include <demexp.h>
+#include <softpc.h>
+#include <mvdm.h>
+#include <ctype.h>
+#include <memory.h>
+#include <oemuni.h>
+
+#define VDM_ENV_INC_SIZE 512
+
+CHAR windir[] = "windir";
+extern BOOL fSeparateWow;
+
+// Transform the given DOS environment to 32bits environment.
+// WARNING!! The environment block we passed to 32bits must be in sort order.
+// Therefore, we call RtlSetEnvironmentVariable to do the work
+// The result string must be in ANSI character set.
+BOOL cmdXformEnvironment(PCHAR pEnv16, PANSI_STRING Env_A)
+{
+ UNICODE_STRING Name_U, Value_U, Temp_U;
+ STRING String;
+ PWCHAR pwch, NewEnv, CurEnv, CurEnvCopy, pTmp;
+ NTSTATUS Status;
+ BOOL fFoundComSpec;
+ USHORT NewEnvLen;
+
+ if (pEnv16 == NULL)
+ return FALSE;
+
+ // flag true if we alread found comspec envirnment
+ // !!!! Do we allow two or more comspec in environment????????
+ fFoundComSpec = FALSE;
+
+ CurEnv = GetEnvironmentStringsW();
+ pwch = CurEnv;
+ // figure how long the environment strings is
+ while (*pwch != UNICODE_NULL || *(pwch + 1) != UNICODE_NULL)
+ pwch++;
+
+ // plus 2 to include the last two NULL chars
+ CurEnvCopy = malloc((pwch - CurEnv + 2) * sizeof(WCHAR));
+ if (!CurEnvCopy)
+ return FALSE;
+
+ // make a copy of current process environment so we can walk through
+ // it. The environment can be changed by any threads in the process
+ // thus is not safe to walk through without a local copy
+ RtlMoveMemory(CurEnvCopy, CurEnv, (pwch - CurEnv + 2) * sizeof(WCHAR));
+
+ // create a new environment block. We don't want to change
+ // any currnt process environment variables, instead, we are
+ // preparing a new one for the new process.
+ Status = RtlCreateEnvironment(FALSE, (PVOID *)&NewEnv);
+ if (!NT_SUCCESS(Status)) {
+ free(CurEnvCopy);
+ return FALSE;
+ }
+ NewEnvLen = 0;
+ // now pick up environment we want from the current environment
+ // and set it to the new environment block
+ // the variables we want:
+ // (1). comspec
+ // (2). current directories settings
+
+ pwch = CurEnvCopy;
+
+ while (*pwch != UNICODE_NULL) {
+ if (*pwch == L'=') {
+ // variable names started with L'=' are current directroy settings
+ pTmp = wcschr(pwch + 1, L'=');
+ if (pTmp) {
+ Name_U.Buffer = pwch;
+ Name_U.Length = (pTmp - pwch) * sizeof(WCHAR);
+ RtlInitUnicodeString(&Value_U, pTmp + 1);
+ Status = RtlSetEnvironmentVariable(&NewEnv, &Name_U, &Value_U);
+ if (!NT_SUCCESS(Status)) {
+ RtlDestroyEnvironment(NewEnv);
+ free(CurEnvCopy);
+ return FALSE;
+ }
+ // <name> + <'='> + <value> + <'\0'>
+ NewEnvLen += Name_U.Length + Value_U.Length + 2 * sizeof(WCHAR);
+ }
+ }
+ else if (!fFoundComSpec) {
+ fFoundComSpec = !_wcsnicmp(pwch, L"COMSPEC=", 8);
+ if (fFoundComSpec) {
+ Name_U.Buffer = pwch;
+ Name_U.Length = 7 * sizeof(WCHAR);
+ RtlInitUnicodeString(&Value_U, pwch + 8);
+ Status = RtlSetEnvironmentVariable(&NewEnv,
+ &Name_U,
+ &Value_U
+ );
+ if (!NT_SUCCESS(Status)) {
+ RtlDestroyEnvironment(NewEnv);
+ free(CurEnvCopy);
+ return FALSE;
+ }
+ NewEnvLen += Name_U.Length + Value_U.Length + 2 * sizeof(WCHAR);
+ }
+ }
+ pwch += wcslen(pwch) + 1;
+ }
+ // we are done with current process environment.
+ free(CurEnvCopy);
+
+ // now deal with 16bits settings passed from dos.
+ // characters in 16bits environment are in OEM character set
+
+ // 16bit comspec environment variable
+ fFoundComSpec = FALSE;
+ while (*pEnv16 != '\0') {
+ RtlInitString(&String, pEnv16);
+ // discard 16bits comspec
+ if (!fFoundComSpec) {
+ fFoundComSpec = !_strnicmp(pEnv16, comspec, 8);
+ if (fFoundComSpec) {
+ // ignore 16bits comspec environment
+ pEnv16 += String.Length + 1;
+ continue;
+ }
+ }
+ Status = RtlOemStringToUnicodeString(&Temp_U, &String, TRUE);
+ if (!NT_SUCCESS(Status)) {
+ RtlDestroyEnvironment(NewEnv);
+ return FALSE;
+ }
+ pwch = wcschr(Temp_U.Buffer, L'=');
+ if (pwch) {
+ Name_U.Buffer = Temp_U.Buffer;
+ Name_U.Length = (pwch - Temp_U.Buffer) * sizeof(WCHAR);
+ RtlInitUnicodeString(&Value_U, pwch + 1);
+ Status = RtlSetEnvironmentVariable( &NewEnv, &Name_U, &Value_U);
+ RtlFreeUnicodeString(&Temp_U);
+ if (!NT_SUCCESS(Status)) {
+ RtlDestroyEnvironment(NewEnv);
+ return FALSE;
+ }
+ NewEnvLen += Name_U.Length + Value_U.Length + 2 * sizeof(WCHAR);
+ }
+ pEnv16 += String.Length + 1;
+ }
+ // count the last terminated null char
+ Temp_U.Length = NewEnvLen + sizeof(WCHAR);
+ Temp_U.Buffer = NewEnv;
+ Status = RtlUnicodeStringToAnsiString(Env_A, &Temp_U, TRUE);
+ RtlDestroyEnvironment(NewEnv); /* don't need it anymore */
+ return(NT_SUCCESS(Status));
+}
+
+
+
+
+/* get ntvdm initial environment. This initial environment is necessary
+ * for the first instance of command.com before it processing autoexec.bat
+ * this function strips off an environment headed with "=" and
+ * replace the comspec with 16bits comspec and upper case all environment vars.
+ *
+ * Entry: Client (ES:0) = buffer to receive the environment
+ * Client (BX) = size in paragraphs of the given buffer
+ *
+ * Exit: (BX) = 0 if nothing to copy
+ * (BX) <= the given size, function okay
+ * (BX) > given size, (BX) has the required size
+ */
+
+VOID cmdGetInitEnvironment(VOID)
+{
+ CHAR *lpszzEnvBuffer, *lpszEnv;
+ WORD cchEnvBuffer;
+ CHAR *lpszzEnvStrings, * lpszz;
+ WORD cchString;
+ WORD cchRemain;
+ WORD cchIncrement = MAX_PATH;
+ BOOL fFoundComSpec = FALSE;
+ BOOL fFoundWindir = FALSE;
+ BOOL fVarIsWindir = FALSE;
+
+ // if not during the initialization return nothing
+ if (!IsFirstCall) {
+ setBX(0);
+ return;
+ }
+ if (cchInitEnvironment == 0) {
+ //
+ // If the PROMPT variable is not set, add it as $P$G. This is to
+ // keep the command.com shell consistent with SCS cmd.exe(which
+ // always does this) when we don't have a top level cmd shell.
+ //
+ {
+ CHAR *pPromptStr = "PROMPT";
+ char ach[2];
+
+ if (!GetEnvironmentVariable(pPromptStr,ach,1)) {
+ SetEnvironmentVariable(pPromptStr, "$P$G");
+ }
+ }
+
+ cchRemain = 0;
+ fFoundComSpec = FALSE;
+ lpszEnv =
+ lpszzEnvStrings = GetEnvironmentStrings();
+ while (*lpszEnv) {
+ cchString = strlen(lpszEnv) + 1;
+ cchVDMEnv32 += cchString;
+ lpszEnv += cchString;
+ }
+ lpszz = lpszzEnvStrings;
+
+ if (lpszzVDMEnv32 != NULL)
+ free(lpszzVDMEnv32);
+ lpszzVDMEnv32 = malloc(++cchVDMEnv32);
+ if (lpszzVDMEnv32 == NULL) {
+ RcMessageBox(EG_MALLOC_FAILURE, NULL, NULL,
+ RMB_ICON_BANG | RMB_ABORT);
+ TerminateVDM();
+ }
+
+ RtlMoveMemory(lpszzVDMEnv32, lpszzEnvStrings, cchVDMEnv32);
+
+ while (*lpszz != '\0') {
+ cchString = strlen(lpszz) + 1;
+ if (*lpszz != '=') {
+
+ if (!fFoundComSpec && !_strnicmp(lpszz, comspec, 8)){
+ fFoundComSpec = TRUE;
+ lpszz += cchString;
+ continue;
+ }
+
+ if (!fFoundWindir && !_strnicmp(lpszz, windir, 6)) {
+ fFoundWindir = TRUE;
+ if (fSeparateWow) {
+ // starting a separate WOW box - flag this one so its
+ // name won't be converted to uppercase later.
+ fVarIsWindir = TRUE;
+ } else {
+ // starting a DOS app, so remove "windir" to make sure
+ // they don't think they are running under Windows.
+ lpszz += cchString;
+ continue;
+ }
+ }
+
+ if (cchRemain < cchString) {
+ if (cchIncrement < cchString)
+ cchIncrement = cchString;
+ lpszzEnvBuffer =
+ (CHAR *)realloc(lpszzInitEnvironment,
+ cchInitEnvironment + cchRemain + cchIncrement
+ );
+ if (lpszzEnvBuffer == NULL) {
+ if (lpszzInitEnvironment != NULL) {
+ free(lpszzInitEnvironment);
+ lpszzInitEnvironment = NULL;
+ }
+ cchInitEnvironment = 0;
+ break;
+ }
+ lpszzInitEnvironment = lpszzEnvBuffer;
+ lpszzEnvBuffer += cchInitEnvironment;
+ cchRemain += cchIncrement;
+ }
+ // the environment strings from base is in ANSI and dos needs OEM
+ AnsiToOemBuff(lpszz, lpszzEnvBuffer, cchString);
+ // convert the name to upper case -- ONLY THE NAME, NOT VALUE.
+ if (!fVarIsWindir && (lpszEnv = strchr(lpszzEnvBuffer, '=')) != NULL){
+ *lpszEnv = '\0';
+ _strupr(lpszzEnvBuffer);
+ *lpszEnv = '=';
+ } else {
+ fVarIsWindir = FALSE;
+ }
+ cchRemain -= cchString;
+ cchInitEnvironment += cchString ;
+ lpszzEnvBuffer += cchString;
+ }
+ lpszz += cchString;
+ }
+ FreeEnvironmentStrings(lpszzEnvStrings);
+
+ lpszzEnvBuffer = (CHAR *) realloc(lpszzInitEnvironment,
+ cchInitEnvironment + 1
+ );
+ if (lpszzInitEnvironment != NULL ) {
+ lpszzInitEnvironment = lpszzEnvBuffer;
+ lpszzInitEnvironment[cchInitEnvironment++] = '\0';
+ }
+ else {
+ if (lpszzInitEnvironment != NULL) {
+ free(lpszzInitEnvironment);
+ lpszzInitEnvironment = NULL;
+ }
+ cchInitEnvironment = 0;
+ }
+ }
+ lpszzEnvBuffer = (CHAR *) GetVDMAddr(getES(), 0);
+ cchEnvBuffer = (WORD)getBX() << 4;
+ if (cchEnvBuffer < cchInitEnvironment + cbComSpec) {
+ setBX((USHORT)((cchInitEnvironment + cbComSpec + 15) >> 4));
+ return;
+ }
+ else {
+ strncpy(lpszzEnvBuffer, lpszComSpec, cbComSpec);
+ lpszzEnvBuffer += cbComSpec;
+ }
+ if (lpszzInitEnvironment != NULL) {
+ setBX((USHORT)((cchInitEnvironment + cbComSpec + 15) >> 4));
+ memcpy(lpszzEnvBuffer, lpszzInitEnvironment, cchInitEnvironment);
+ free(lpszzInitEnvironment);
+ lpszzInitEnvironment = NULL;
+ cchInitEnvironment = 0;
+
+ }
+ else
+ setBX(0);
+
+ return;
+}
+
+
+
+/** create a DOS environment for DOS.
+ This is to get 32bits environment(comes with the dos executanle)
+ and merge it with the environment settings in autoexec.nt so that
+ COMMAND.COM gets the expected environment. We already created a
+ double-null terminated string during autoexec.nt parsing. The string
+ has mutltiple substring:
+ "EnvName_1 NULL EnvValue_1 NULL[EnvName_n NULL EnvValue_n NULL] NULL"
+ When name conflicts happened(a environment name was found in both
+ 16 bits and 32 bits), we do the merging based on the rules:
+ get 16bits value, expands any environment variables in the string
+ by using the current environment.
+
+WARINING !!! The changes made by applications through directly manipulation
+ in command.com environment segment will be lost.
+
+**/
+BOOL cmdCreateVDMEnvironment(
+PVDMENVBLK pVDMEnvBlk
+)
+{
+PCHAR p1, p2;
+BOOL fFoundComSpec;
+BOOL fFoundWindir;
+BOOL fVarIsWindir;
+DWORD Length;
+PCHAR lpszzVDMEnv, lpszzEnv;
+CHAR achBuffer[MAX_PATH + 1];
+
+ pVDMEnvBlk->lpszzEnv = malloc(cchVDMEnv32 + cbComSpec + 1);
+ if ((lpszzVDMEnv = pVDMEnvBlk->lpszzEnv) == NULL)
+ return FALSE;
+
+ pVDMEnvBlk->cchRemain = cchVDMEnv32 + cbComSpec + 1;
+ pVDMEnvBlk->cchEnv = 0;
+
+ // grab the 16bits comspec first
+ if (cbComSpec && lpszComSpec && *lpszComSpec) {
+ RtlCopyMemory(lpszzVDMEnv, lpszComSpec, cbComSpec);
+ pVDMEnvBlk->cchEnv += cbComSpec;
+ pVDMEnvBlk->cchRemain -= cbComSpec;
+ lpszzVDMEnv += cbComSpec;
+ }
+ if (lpszzVDMEnv32) {
+
+ // go through the given 32bits environmnet and take what we want:
+ // everything except:
+ // (1). variable name begin with '='
+ // (2). compsec
+ // (3). string without a '=' -- malformatted environment variable
+ // (4). windir, so DOS apps don't think they're running under Windows
+ // Note that strings pointed by lpszzVDMEnv32 are in ANSI character set
+
+
+ fFoundComSpec = FALSE;
+ fFoundWindir = FALSE;
+ fVarIsWindir = FALSE;
+ lpszzEnv = lpszzVDMEnv32;
+
+ while (*lpszzEnv) {
+ Length = strlen(lpszzEnv) + 1;
+ if (*lpszzEnv != '=' &&
+ (p1 = strchr(lpszzEnv, '=')) != NULL &&
+ (fFoundComSpec || !(fFoundComSpec = _strnicmp(lpszzEnv,
+ comspec,
+ 8
+ ) == 0)) ){
+ if (!fFoundWindir) {
+ fFoundWindir = (_strnicmp(lpszzEnv,
+ windir,
+ 6) == 0);
+ fVarIsWindir = fFoundWindir;
+ }
+ if (!fVarIsWindir || fSeparateWow) {
+ if (Length >= pVDMEnvBlk->cchRemain) {
+ lpszzVDMEnv = realloc(pVDMEnvBlk->lpszzEnv,
+ pVDMEnvBlk->cchEnv +
+ pVDMEnvBlk->cchRemain +
+ VDM_ENV_INC_SIZE
+ );
+ if (lpszzVDMEnv == NULL){
+ free(pVDMEnvBlk->lpszzEnv);
+ return FALSE;
+ }
+ pVDMEnvBlk->cchRemain += VDM_ENV_INC_SIZE;
+ pVDMEnvBlk->lpszzEnv = lpszzVDMEnv;
+ lpszzVDMEnv += pVDMEnvBlk->cchEnv;
+ }
+ AnsiToOemBuff(lpszzEnv, lpszzVDMEnv, Length);
+ if (!fVarIsWindir) {
+ *(lpszzVDMEnv + (DWORD)(p1 - lpszzEnv)) = '\0';
+ _strupr(lpszzVDMEnv);
+ *(lpszzVDMEnv + (DWORD)(p1 - lpszzEnv)) = '=';
+ } else {
+ fVarIsWindir = FALSE;
+ }
+ pVDMEnvBlk->cchEnv += Length;
+ pVDMEnvBlk->cchRemain -= Length;
+ lpszzVDMEnv += Length;
+ }
+ else
+ fVarIsWindir = FALSE;
+ }
+ lpszzEnv += Length;
+ }
+ }
+ *lpszzVDMEnv = '\0';
+ pVDMEnvBlk->cchEnv++;
+ pVDMEnvBlk->cchRemain--;
+
+ if (lpszzcmdEnv16 != NULL) {
+ lpszzEnv = lpszzcmdEnv16;
+
+ while (*lpszzEnv) {
+ p1 = lpszzEnv + strlen(lpszzEnv) + 1;
+ p2 = NULL;
+ if (*p1) {
+ p2 = achBuffer;
+ // expand the strings pointed by p1
+ Length = cmdExpandEnvironmentStrings(pVDMEnvBlk,
+ p1,
+ p2,
+ MAX_PATH + 1
+ );
+ if (Length && Length > MAX_PATH) {
+ p2 = (PCHAR) malloc(Length);
+ if (p2 == NULL) {
+ free(pVDMEnvBlk->lpszzEnv);
+ return FALSE;
+ }
+ cmdExpandEnvironmentStrings(pVDMEnvBlk,
+ p1,
+ p2,
+ Length
+ );
+ }
+ }
+ if (!cmdSetEnvironmentVariable(pVDMEnvBlk,
+ lpszzEnv,
+ p2
+ )){
+ if (p2 && p2 != achBuffer)
+ free(p2);
+ free(pVDMEnvBlk->lpszzEnv);
+ return FALSE;
+ }
+ lpszzEnv = p1 + strlen(p1) + 1;
+ }
+ }
+ lpszzVDMEnv = realloc(pVDMEnvBlk->lpszzEnv, pVDMEnvBlk->cchEnv);
+ if (lpszzVDMEnv != NULL) {
+ pVDMEnvBlk->lpszzEnv = lpszzVDMEnv;
+ pVDMEnvBlk->cchRemain = 0;
+ }
+ return TRUE;
+}
+
+
+BOOL cmdSetEnvironmentVariable(
+PVDMENVBLK pVDMEnvBlk,
+PCHAR lpszName,
+PCHAR lpszValue
+)
+{
+ PCHAR p, p1, pEnd;
+ DWORD ExtraLength, Length, cchValue, cchOldValue;
+
+ pVDMEnvBlk = (pVDMEnvBlk) ? pVDMEnvBlk : &cmdVDMEnvBlk;
+
+ if (pVDMEnvBlk == NULL || lpszName == NULL)
+ return FALSE;
+ if (!(p = pVDMEnvBlk->lpszzEnv))
+ return FALSE;
+ pEnd = p + pVDMEnvBlk->cchEnv - 1;
+
+ cchValue = (lpszValue) ? strlen(lpszValue) : 0;
+
+ Length = strlen(lpszName);
+ while (*p && ((p1 = strchr(p, '=')) == NULL ||
+ (DWORD)(p1 - p) != Length ||
+ _strnicmp(p, lpszName, Length)))
+ p += strlen(p) + 1;
+
+ if (*p) {
+ // name was found in the base environment, replace it
+ p1++;
+ cchOldValue = strlen(p1);
+ if (cchValue <= cchOldValue) {
+ if (!cchValue) {
+ RtlMoveMemory(p,
+ p1 + cchOldValue + 1,
+ (DWORD)(pEnd - p) - cchOldValue
+ );
+ pVDMEnvBlk->cchRemain += Length + cchOldValue + 2;
+ pVDMEnvBlk->cchEnv -= Length + cchOldValue + 2;
+ }
+ else {
+ RtlCopyMemory(p1,
+ lpszValue,
+ cchValue
+ );
+ if (cchValue != cchOldValue) {
+ RtlMoveMemory(p1 + cchValue,
+ p1 + cchOldValue,
+ (DWORD)(pEnd - p1) - cchOldValue + 1
+ );
+ pVDMEnvBlk->cchEnv -= cchOldValue - cchValue;
+ pVDMEnvBlk->cchRemain += cchOldValue - cchValue;
+ }
+ }
+ return TRUE;
+ }
+ else {
+ // need more space for the new value
+ // we delete it from here and fall through
+ RtlMoveMemory(p,
+ p1 + cchOldValue + 1,
+ (DWORD)(pEnd - p1) - cchOldValue
+ );
+ pVDMEnvBlk->cchRemain += Length + 1 + cchOldValue + 1;
+ pVDMEnvBlk->cchEnv -= Length + 1 + cchOldValue + 1;
+ }
+ }
+ if (cchValue) {
+ ExtraLength = Length + 1 + cchValue + 1;
+ if (pVDMEnvBlk->cchRemain < ExtraLength) {
+ p = realloc(pVDMEnvBlk->lpszzEnv,
+ pVDMEnvBlk->cchEnv + pVDMEnvBlk->cchRemain + ExtraLength
+ );
+ if (p == NULL)
+ return FALSE;
+ pVDMEnvBlk->lpszzEnv = p;
+ pVDMEnvBlk->cchRemain += ExtraLength;
+ }
+ p = pVDMEnvBlk->lpszzEnv + pVDMEnvBlk->cchEnv - 1;
+ RtlCopyMemory(p, lpszName, Length + 1);
+ _strupr(p);
+ p += Length;
+ *p++ = '=';
+ RtlCopyMemory(p, lpszValue, cchValue + 1);
+ *(p + cchValue + 1) = '\0';
+ pVDMEnvBlk->cchEnv += ExtraLength;
+ pVDMEnvBlk->cchRemain -= ExtraLength;
+ return TRUE;
+ }
+ return FALSE;
+
+}
+
+
+DWORD cmdExpandEnvironmentStrings(
+PVDMENVBLK pVDMEnvBlk,
+PCHAR lpszSrc,
+PCHAR lpszDst,
+DWORD cchDst
+)
+{
+
+
+ DWORD RequiredLength, RemainLength, Length;
+ PCHAR p1;
+
+ RequiredLength = 0;
+ RemainLength = (lpszDst) ? cchDst : 0;
+ pVDMEnvBlk = (pVDMEnvBlk) ? pVDMEnvBlk : &cmdVDMEnvBlk;
+ if (pVDMEnvBlk == NULL || lpszSrc == NULL)
+ return 0;
+
+ while(*lpszSrc) {
+ if (*lpszSrc == '%') {
+ p1 = strchr(lpszSrc + 1, '%');
+ if (p1 != NULL) {
+ if (p1 == lpszSrc + 1) { // a "%%"
+ lpszSrc += 2;
+ continue;
+ }
+ *p1 = '\0';
+ Length = cmdGetEnvironmentVariable(pVDMEnvBlk,
+ lpszSrc + 1,
+ lpszDst,
+ RemainLength
+ );
+ *p1 = '%';
+ lpszSrc = p1 + 1;
+ if (Length) {
+ if (Length < RemainLength) {
+ RemainLength -= Length;
+ lpszDst += Length;
+ }
+ else {
+ RemainLength = 0;
+ Length --;
+ }
+ RequiredLength += Length;
+ }
+ continue;
+ }
+ else {
+ RequiredLength++;
+ if (RemainLength) {
+ *lpszDst++ = *lpszSrc;
+ RemainLength--;
+ }
+ lpszSrc++;
+ continue;
+ }
+ }
+ else {
+ RequiredLength++;
+ if (RemainLength) {
+ *lpszDst++ = *lpszSrc;
+ RemainLength--;
+ }
+ lpszSrc++;
+ }
+ } // while(*lpszSrc)
+ RequiredLength++;
+ if (RemainLength)
+ *lpszDst = '\0';
+ return RequiredLength;
+}
+
+
+DWORD cmdGetEnvironmentVariable(
+PVDMENVBLK pVDMEnvBlk,
+PCHAR lpszName,
+PCHAR lpszValue,
+DWORD cchValue
+)
+{
+
+ DWORD RequiredLength, Length;
+ PCHAR p, p1;
+
+ pVDMEnvBlk = (pVDMEnvBlk) ? pVDMEnvBlk : &cmdVDMEnvBlk;
+ if (pVDMEnvBlk == NULL || lpszName == NULL)
+ return 0;
+
+ RequiredLength = 0;
+ Length = strlen(lpszName);
+
+ // if the name is "windir", get its value from ntvdm process's environment
+ // for DOS because we took it out of the environment block the application
+ // will see.
+ if (Length == 6 && !fSeparateWow && !_strnicmp(lpszName, windir, 6)) {
+ return(GetEnvironmentVariableOem(lpszName, lpszValue, cchValue));
+ }
+
+ if (p = pVDMEnvBlk->lpszzEnv) {
+ while (*p && ((p1 = strchr(p, '=')) == NULL ||
+ (DWORD)(p1 - p) != Length ||
+ _strnicmp(lpszName, p, Length)))
+ p += strlen(p) + 1;
+ if (*p) {
+ RequiredLength = strlen(p1 + 1);
+ if (cchValue > RequiredLength && lpszValue)
+ RtlCopyMemory(lpszValue, p1 + 1, RequiredLength + 1);
+ else
+ RequiredLength++;
+ }
+ }
+ return RequiredLength;
+}