Пример #1
0
void DebugCpUnitTest()
{
	typedef struct {
		LPCWSTR sString;
		UINT nCP;
		wchar_t cEnd;
	} Test;
	Test Tests[] = {
		{L"Utf-8", CP_UTF8},
		{L"Utf-8;Acp", CP_UTF8, L';'},
		{L"ansi", CP_ACP},
		{L"ansicp;none", CP_ACP, L';'},
		{L"65001:1251", 65001, L':'},
		{NULL},
	};

	LPCWSTR pszEnd;
	UINT nCP;

	_ASSERTE(GetCpFromString(L"866") == 866);

	for (INT_PTR i = 0; Tests[i].sString; i++)
	{
		const Test& p = Tests[i];
		nCP = GetCpFromString(p.sString, &pszEnd);
		_ASSERTE(nCP == p.nCP);
		_ASSERTE((pszEnd == NULL && p.cEnd == 0) || (pszEnd && *pszEnd == p.cEnd));
	}
}
Пример #2
0
// Return true if "SetEnvironmentVariable" was processed
// if (bDoSet==false) - just skip all "set" commands
// Supported commands:
//  set abc=val
//  "set PATH=C:\Program Files;%PATH%"
//  chcp [utf8|ansi|oem|<cp_no>]
//  title "Console init title"
bool ProcessSetEnvCmd(LPCWSTR& asCmdLine, bool bDoSet, CmdArg* rpsTitle /*= NULL*/)
{
	LPCWSTR lsCmdLine = asCmdLine;
	bool bEnvChanged = false;
	CmdArg lsSet, lsAmp;

	// Example: "set PATH=C:\Program Files;%PATH%" & set abc=def & cmd
	while (NextArg(&lsCmdLine, lsSet) == 0)
	{
		bool bTokenOk = false;
		wchar_t* lsNameVal = NULL;

		// It may contains only "set" if was not quoted
		if (lstrcmpi(lsSet, L"set") == 0)
		{
			// Now we shell get in lsSet "abc=def" token
			if ((NextArg(&lsCmdLine, lsSet) == 0) && (wcschr(lsSet, L'=') > lsSet.ms_Arg))
			{
				lsNameVal = lsSet.ms_Arg;
			}
		}
		// Or full "set PATH=C:\Program Files;%PATH%" command (without quotes ATM)
		else if (lstrcmpni(lsSet, L"set ", 4) == 0)
		{
			LPCWSTR psz = SkipNonPrintable(lsSet.ms_Arg+4);
			if (wcschr(psz, L'=') > psz)
			{
				lsNameVal = (wchar_t*)psz;
			}
		}
		// Process "chcp <cp>" too
		else if (lstrcmpi(lsSet, L"chcp") == 0)
		{
			if (NextArg(&lsCmdLine, lsSet) == 0)
			{
				UINT nCP = GetCpFromString(lsSet);

				if (nCP > 0 && nCP <= 0xFFFF)
				{
					bTokenOk = true;
					_ASSERTE(lsNameVal == NULL);
					// Ask to be changed?
					if (bDoSet)
					{
						//Issue 60: BUGBUG: На некоторых системых (Win2k3, WinXP) SetConsoleCP (и иже с ними) просто зависают
						DWORD nTID;
						HANDLE hThread = CreateThread(NULL, 0, OurSetConsoleCPThread, (LPVOID)nCP, 0, &nTID);
						if (hThread)
						{
							DWORD nWait = WaitForSingleObject(hThread, 1000);
							if (nWait == WAIT_TIMEOUT)
							{
								TerminateThread(hThread,100);
							}
							CloseHandle(hThread);
						}
					}
				}
			}
		}
		// Change title without need of cmd.exe
		else if (lstrcmpi(lsSet, L"title") == 0)
		{
			if (NextArg(&lsCmdLine, lsSet) == 0)
			{
				bTokenOk = true;
				_ASSERTE(lsNameVal == NULL);
				// Ask to be changed?
				if (rpsTitle)
					rpsTitle->Set(lsSet);
			}
		}

		// Well, known command was detected. What is next?
		if (lsNameVal || bTokenOk)
		{
			lsAmp.GetPosFrom(lsSet);
			if (NextArg(&lsCmdLine, lsAmp) != 0)
			{
				// End of command? Use may call only "set" without following app? Run simple "cmd" in that case
				_ASSERTE(lsCmdLine!=NULL && *lsCmdLine==0);
				bTokenOk = true; // And process SetEnvironmentVariable
			}
			else
			{
				if (lstrcmp(lsAmp, L"&") == 0)
				{
					// Only simple conveyer is supported!
					bTokenOk = true; // And process SetEnvironmentVariable
				}
				// Update last pointer (debug and asserts purposes)
				lsSet.GetPosFrom(lsAmp);
			}
		}

		if (!bTokenOk)
		{
			break; // Stop processing command line
		}
		else if (lsNameVal)
		{
			// And split name/value
			_ASSERTE(lsNameVal!=NULL);

			wchar_t* pszEq = wcschr(lsNameVal, L'=');
			if (!pszEq)
			{
				_ASSERTE(pszEq!=NULL);
				break;
			}

			if (bDoSet)
			{
				*(pszEq++) = 0;
				// Expand value
				wchar_t* pszExpanded = ExpandEnvStr(pszEq);
				LPCWSTR pszSet = pszExpanded ? pszExpanded : pszEq;
				SetEnvironmentVariable(lsNameVal, (pszSet && *pszSet) ? pszSet : NULL);
				SafeFree(pszExpanded);
			}

			bEnvChanged = true;
		}

		// Remember processed position
		asCmdLine = lsCmdLine;

	} // end of "while (NextArg(&lsCmdLine, lsSet) == 0)"

	// Fin
	if (!asCmdLine || !*asCmdLine)
	{
		static wchar_t szSimple[] = L"cmd";
		asCmdLine = szSimple;
	}

	return bEnvChanged;
}
Пример #3
0
// May comes from Task or ConEmu's -run switch
// or from Setting\Environment page where one line is a single command (bAlone == true)
bool CProcessEnvCmd::AddCommands(LPCWSTR asCommands, LPCWSTR* ppszEnd/*= NULL*/, bool bAlone /*= false*/, INT_PTR anBefore /*= -1*/)
{
	bool bNew = false;
	LPCWSTR lsCmdLine = asCommands;
	CEStr lsSet, lsAmp, lsCmd;

	if (ppszEnd)
		*ppszEnd = asCommands;

	// Example: "set PATH=C:\Program Files;%PATH%" & set abc=def & cmd
	while (NextArg(&lsCmdLine, lsSet) == 0)
	{
		bool bTokenOk = false;
		wchar_t* lsNameVal = NULL;

		// It may contains only "set" or "alias" if was not quoted
		if ((lstrcmpi(lsSet, L"set") == 0) || (lstrcmpi(lsSet, L"alias") == 0))
		{
			lsCmd.Set(lsSet);

			_ASSERTE(*lsCmdLine != L' ');

			// Now we shell get in lsSet "abc=def" token
			// Or to simplify usage, the rest of line is supported too,
			// so user may type in our Settings\Environment:
			//   set V1=From Settings
			// instead of
			//   set "V1=From Settings"
			bool bProcessed = false;
			if ((*lsCmdLine != L'"') || bAlone)
			{
				LPCWSTR pszAmp = bAlone ? NULL : wcschr(lsCmdLine, L'&');
				if (!pszAmp) // No ampersand or bAlone? Use var value as the rest of line
					pszAmp = lsCmdLine + lstrlen(lsCmdLine);
				// Set tail pointer
				LPCWSTR pszValEnd = pszAmp;
				// Trim trailing spaces (only \x20)
				while ((pszValEnd > lsCmdLine) && (*(pszValEnd-1) == L' '))
					pszValEnd--;
				// Trim possible leading/trailing quotes
				if (bAlone && (*lsCmdLine == L'"'))
				{
					lsCmdLine++;
					if (((pszValEnd-1) > lsCmdLine) && (*(pszValEnd-1) == L'"'))
					{
						_ASSERTE(*pszValEnd == 0);
						pszValEnd--;
					}
				}
				// OK, return it
				lsSet.Empty(); // to avoid debug asserts
				lsSet.Set(lsCmdLine, pszValEnd - lsCmdLine);
				lsCmdLine = SkipNonPrintable(pszAmp); // Leave possible '&' at pointer
				bProcessed = true;
			}
			// OK, lets get token like "name=var value"
			if (!bProcessed)
			{
				bProcessed = (NextArg(&lsCmdLine, lsSet) == 0);
			}
			if (bProcessed && (wcschr(lsSet, L'=') > lsSet.ms_Val))
			{
				lsNameVal = lsSet.ms_Val;
			}
		}
		// Or full "set PATH=C:\Program Files;%PATH%" command (without quotes ATM)
		else if (lstrcmpni(lsSet, L"set ", 4) == 0)
		{
			lsCmd = L"set";
			LPCWSTR psz = SkipNonPrintable(lsSet.ms_Val+4);
			if (wcschr(psz, L'=') > psz)
			{
				lsNameVal = (wchar_t*)psz;
			}
		}
		// Support "alias token=value" too
		else if (lstrcmpni(lsSet, L"alias ", 6) == 0)
		{
			lsCmd = L"alias";
			LPCWSTR psz = SkipNonPrintable(lsSet.ms_Val+6);
			if (wcschr(psz, L'=') > psz)
			{
				lsNameVal = (wchar_t*)psz;
			}
		}
		// Process "chcp <cp>" too
		else if (lstrcmpi(lsSet, L"chcp") == 0)
		{
			lsCmd = L"chcp";
			if (NextArg(&lsCmdLine, lsSet) == 0)
			{
				UINT nCP = GetCpFromString(lsSet);
				if (nCP > 0 && nCP <= 0xFFFF)
				{
					bTokenOk = true;
					_ASSERTE(lsNameVal == NULL);
					if (mp_CmdChCp)
					{
						SafeFree(mp_CmdChCp->pszName);
						mp_CmdChCp->pszName = lstrdup(lsSet);
					}
					else
					{
						bNew |= (NULL != Add(lsCmd, lsSet, NULL, anBefore));
					}
				}
			}
		}
		// Change title without need of cmd.exe
		else if (lstrcmpi(lsSet, L"title") == 0)
		{
			lsCmd = L"title";
			if (NextArg(&lsCmdLine, lsSet) == 0)
			{
				bTokenOk = true;
				_ASSERTE(lsNameVal == NULL);
				if (mp_CmdTitle)
				{
					SafeFree(mp_CmdTitle->pszName);
					mp_CmdTitle->pszName = lstrdup(lsSet);
				}
				else
				{
					bNew |= (NULL != Add(lsCmd, lsSet, NULL, anBefore));
				}
			}
		}
		// Echo the "text" before console starts
		// Type the "text file" before console starts
		else if ((lstrcmpi(lsSet, L"echo") == 0) || (lstrcmpi(lsSet, L"type") == 0))
		{
			lsCmd.Set(lsSet);
			// echo [-r] [-n] [-x] [-b] "String to echo"
			// type [-b] [-CP] "Path to text file to echo"
			CEStr lsSwitches;
			while (*lsCmdLine == L'-')
			{
				if (NextArg(&lsCmdLine, lsSet) != 0)
					break;
				lstrmerge(&lsSwitches.ms_Val, lsSwitches.IsEmpty() ? NULL : L" ", lsSet.ms_Val);
			}
			// Rest arguments are expected to be processed text or file
			CEStr lsAdd;
			while (NextArg(&lsCmdLine, lsSet) == 0)
			{
				bTokenOk = true;
				lstrmerge(&lsAdd.ms_Val,
					lsAdd.IsEmpty() ? NULL : L" ",
					lsSet.mb_Quoted ? L"\"" : NULL,
					lsSet.ms_Val,
					lsSet.mb_Quoted ? L"\"" : NULL);
				lsCmdLine = SkipNonPrintable(lsCmdLine);
				if (!*lsCmdLine || (*lsCmdLine == L'&') || (*lsCmdLine == L'|'))
					break;

			}
			if (!lsAdd.IsEmpty())
			{
				bNew |= (NULL != Add(lsCmd, lsSwitches, lsAdd, anBefore));
			}
		}
		else
		{
			lsCmd.Empty();
		}

		// Well, known command was detected. What is next?
		if (lsNameVal || bTokenOk)
		{
			lsAmp.GetPosFrom(lsSet);
			if (NextArg(&lsCmdLine, lsAmp) != 0)
			{
				// End of command? Use may call only "set" without following app? Run simple "cmd" in that case
				_ASSERTE(lsCmdLine!=NULL && *lsCmdLine==0);
				bTokenOk = true; // And process SetEnvironmentVariable
			}
			else
			{
				if (lstrcmp(lsAmp, L"&") == 0)
				{
					// Only simple conveyer is supported!
					bTokenOk = true; // And process SetEnvironmentVariable
				}
				// Update last pointer (debug and asserts purposes)
				lsSet.GetPosFrom(lsAmp);
			}
		}

		if (!bTokenOk)
		{
			break; // Stop processing command line
		}
		else if (lsNameVal)
		{
			// And split name/value
			_ASSERTE(lsNameVal!=NULL);

			wchar_t* pszEq = wcschr(lsNameVal, L'=');
			if (!pszEq)
			{
				_ASSERTE(pszEq!=NULL);
				break;
			}

			*(pszEq++) = 0;

			bNew |= (NULL != Add(lsCmd, lsNameVal, pszEq ? pszEq : L"", anBefore));
		}

		// Remember processed position
		if (ppszEnd)
		{
			*ppszEnd = lsCmdLine;
		}
	} // end of "while (NextArg(&lsCmdLine, lsSet) == 0)"

	// Fin
	if (ppszEnd && (!*ppszEnd || !**ppszEnd))
	{
		static wchar_t szSimple[] = L"cmd";
		*ppszEnd = szSimple;
	}

	return bNew;
}