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)); } }
// 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; }
// 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; }