int GetLangParam(api::File& LangFile,const string& ParamName,string *strParam1, string *strParam2, UINT nCodePage) { string strFullParamName = L"."; strFullParamName += ParamName; int Length=(int)strFullParamName.size(); /* $ 29.11.2001 DJ не поганим позицию в файле; дальше @Contents не читаем */ BOOL Found = FALSE; auto OldPos = LangFile.GetPointer(); string ReadStr; GetFileString GetStr(LangFile, nCodePage); while (GetStr.GetString(ReadStr)) { if (!StrCmpNI(ReadStr.data(), strFullParamName.data(), Length)) { size_t Pos = ReadStr.find(L'='); if (Pos != string::npos) { *strParam1 = ReadStr.substr(Pos + 1); if (strParam2) strParam2->clear(); size_t pos = strParam1->find(L','); if (pos != string::npos) { if (strParam2) { *strParam2 = *strParam1; strParam2->erase(0, pos+1); RemoveTrailingSpaces(*strParam2); } strParam1->resize(pos); } RemoveTrailingSpaces(*strParam1); Found = TRUE; break; } } else if (!StrCmpNI(ReadStr.data(), L"@Contents", 9)) break; } LangFile.SetPointer(OldPos, nullptr, FILE_BEGIN); return Found; }
int _cdecl SortDizIndex(const void *el1,const void *el2) { const wchar_t *Diz1=SearchDizData[*(int *)el1]->DizText+SearchDizData[*(int *)el1]->NameStart; const wchar_t *Diz2=SearchDizData[*(int *)el2]->DizText+SearchDizData[*(int *)el2]->NameStart; int Len1=SearchDizData[*(int *)el1]->NameLength; int Len2=SearchDizData[*(int *)el2]->NameLength; int CmpCode = StrCmpNI(Diz1,Diz2,Min(Len1,Len2)); if (!CmpCode) { if (Len1>Len2) return 1; if (Len1<Len2) return -1; //for equal names, deleted is bigger bool Del1=SearchDizData[*(int *)el1]->Deleted; bool Del2=SearchDizData[*(int *)el2]->Deleted; if (Del1 && !Del2) return 1; if (Del2 && !Del1) return -1; } return CmpCode; }
intptr_t WINAPI SortDizSearch(const void *key,const void *elem,void*) { const string* strKey = reinterpret_cast<const string*>(key); const wchar_t *SearchName = strKey->CPtr(); const wchar_t *DizName=SearchDizData[*(int *)elem]->DizText+SearchDizData[*(int *)elem]->NameStart; int DizNameLength=SearchDizData[*(int *)elem]->NameLength; int NameLength=static_cast<int>(strKey->GetLength()); int CmpCode=StrCmpNI(SearchName,DizName, Min(DizNameLength,NameLength)); if (!CmpCode) { if (NameLength>DizNameLength) return 1; if (NameLength+1<DizNameLength) return -1; //filename == filename. if (NameLength+1==DizNameLength && !(DizName[NameLength]==L'.' && wcschr(DizName,L'.')==&DizName[NameLength])) return -1; //for equal names, deleted is bigger so deleted items are never matched if (SearchDizData[*(int *)elem]->Deleted) return -1; } return CmpCode; }
bool History::GetSimilar(string &strStr, int LastCmdPartLength, bool bAppend) { int Length=(int)strStr.GetLength(); if (LastCmdPartLength!=-1 && LastCmdPartLength<Length) Length=LastCmdPartLength; if (LastCmdPartLength==-1) { ResetPosition(); } for (HistoryRecord *HistoryItem=HistoryList.Prev(CurrentItem); HistoryItem != CurrentItem; HistoryItem=HistoryList.Prev(HistoryItem)) { if (!HistoryItem) continue; if (!StrCmpNI(strStr,HistoryItem->strName,Length) && StrCmp(strStr,HistoryItem->strName)) { if (bAppend) strStr += &HistoryItem->strName[Length]; else strStr = HistoryItem->strName; CurrentItem = HistoryItem; return true; } } return false; }
/* $ 01.09.2000 SVS + Новый метод, для получения параметров для .Options .Options <KeyName>=<Value> */ int GetOptionsParam(api::File& SrcFile,const wchar_t *KeyName,string &strValue, UINT nCodePage) { int Length=StrLength(L".Options"); auto CurFilePos = SrcFile.GetPointer(); string ReadStr; GetFileString GetStr(SrcFile, nCodePage); while (GetStr.GetString(ReadStr)) { if (!StrCmpNI(ReadStr.data(), L".Options", Length)) { string strFullParamName = ReadStr.substr(Length); RemoveExternalSpaces(strFullParamName); size_t pos = strFullParamName.rfind(L'='); if (pos != string::npos) { strValue = strFullParamName; strValue.erase(0, pos+1); RemoveExternalSpaces(strValue); strFullParamName.resize(pos); RemoveExternalSpaces(strFullParamName); if (!StrCmpI(strFullParamName.data(),KeyName)) { SrcFile.SetPointer(CurFilePos, nullptr, FILE_BEGIN); return TRUE; } } } } SrcFile.SetPointer(CurFilePos, nullptr, FILE_BEGIN); return FALSE; }
HWND FindHandle(DWORD dwThreadId, string wdwClass, long x, long y) { int size,cnt=0; string str; char buffer[256]={0}; HWND handle; EnumThreadWindows(dwThreadId,EnumThreadWndProc,(LPARAM) &handle); do { if (GetParent(handle)!=NULL && GetParent(handle)!=handle && GetParent(handle)!=GetDesktopWindow() ) handle = GetParent(handle); else break; } while (true); POINT Point; Point.x = x; Point.y = y; handle = ChildWindowFromPoint(handle,Point); if (handle!=NULL) { GetClassName(handle,buffer,256); if (StrCmpNI(buffer,wdwClass.c_str(),wdwClass.length())==0) { return handle; } } return 0; }
bool History::GetAllSimilar(VMenu2 &HistoryMenu,const string& Str) { int Length=static_cast<int>(Str.size()); DWORD index=0; string strHName,strHGuid,strHFile,strHData; history_record_type HType; bool HLock; unsigned __int64 id; unsigned __int64 Time; while (HistoryCfgRef()->Enum(index++,m_TypeHistory,m_HistoryName,&id,strHName,&HType,&HLock,&Time,strHGuid,strHFile,strHData,true)) { if (!StrCmpNI(Str.data(),strHName.data(),Length)) { MenuItemEx NewItem(strHName); if(HLock) { NewItem.Flags|=LIF_CHECKED; } HistoryMenu.SetUserData(&id,sizeof(id),HistoryMenu.AddItem(NewItem)); } } if(HistoryMenu.GetItemCount() == 1 && HistoryMenu.GetItemPtr(0)->strName.size() == static_cast<size_t>(Length)) { HistoryMenu.DeleteItems(); return false; } return true; }
void ProcessCommandLine() { TCHAR **argv; int i, j; int argc = SetArgv((TCHAR *)GetCommandLine(), &argv); if (argc > 1) { for (i = 1; i < argc; i++) { if (!StrCmpNI(argv[i], _T("/XSetCompressor "), lstrlen(_T("/XSetCompressor ")))) { TCHAR *p = argv[i] + lstrlen(_T("/XSetCompressor ")); if(!StrCmpNI(p,_T("/FINAL "), lstrlen(_T("/FINAL ")))) { p += lstrlen(_T("/FINAL ")); } while (*p == _T(' ')) p++; for (j = (int) COMPRESSOR_SCRIPT + 1; j < (int) COMPRESSOR_BEST; j++) { if (!lstrcmpi(p, compressor_names[j])) { SetCompressor((NCOMPRESSOR) j); } } } else if (!lstrcmpi(argv[i], _T("/ChooseCompressor"))) { g_sdata.userSelectCompressor = TRUE; } else if (argv[i][0] == _T('-') || argv[i][0] == _T('/')) { AddScriptCmdArgs(argv[i]); } else { SetScript(argv[i], false); PushMRUFile(g_sdata.script); break; } } } MemSafeFree(argv); }
LONG_PTR WINAPI HashVerifyFindItem( PHASHVERIFYCONTEXT phvctx, LPNMLVFINDITEM pfi ) { PHASHVERIFYITEM pItem; INT cchCompare, iStart = pfi->iStart; LONG_PTR i; if (pfi->lvfi.flags & (LVFI_PARAM | LVFI_NEARESTXY)) goto not_found; // Unsupported search types if (!(pfi->lvfi.flags & (LVFI_PARTIAL | LVFI_STRING))) goto not_found; // No valid search type specified // According to the documentation, LVFI_STRING without a corresponding // LVFI_PARTIAL should match the FULL string, but when the user sends // keyboard input (which uses a partial match), the notification does not // have the LVFI_PARTIAL flag, so we should just always assume LVFI_PARTIAL // INT cchCompare = (pfi->lvfi.flags & LVFI_PARTIAL) ? 0 : 1; // cchCompare += SSLen(pfi->lvfi.psz); // The above code should have been correct, but it is not... cchCompare = (INT)SSLen(pfi->lvfi.psz); // Fix out-of-range indices; by casting to unsigned, we also catch negatives if ((UINT)iStart > phvctx->cTotal) iStart = phvctx->cTotal; for (i = iStart; i < (INT)phvctx->cTotal; ++i) { pItem = phvctx->index[i]; if (StrCmpNI(pItem->pszDisplayName, pfi->lvfi.psz, cchCompare) == 0) return(i); } if (pfi->lvfi.flags & LVFI_WRAP) { for (i = 0; i < iStart; ++i) { pItem = phvctx->index[i]; if (StrCmpNI(pItem->pszDisplayName, pfi->lvfi.psz, cchCompare) == 0) return(i); } } not_found: return(-1); }
HRESULT UpdatePublisherPolicyTimeStampFile(IAssemblyName *pName) { HRESULT hr = S_OK; DWORD dwSize; HANDLE hFile = INVALID_HANDLE_VALUE; WCHAR wzTimeStampFile[MAX_PATH + 1]; WCHAR wzAsmName[MAX_PATH]; ASSERT(pName); // If the name of the assembly begins with "policy." then update // the publisher policy timestamp file. wzAsmName[0] = L'\0'; dwSize = MAX_PATH; hr = pName->GetProperty(ASM_NAME_NAME, wzAsmName, &dwSize); if (FAILED(hr)) { goto Exit; } if (StrCmpNI(wzAsmName, POLICY_ASSEMBLY_PREFIX, lstrlenW(POLICY_ASSEMBLY_PREFIX))) { // No work needs to be done goto Exit; } // Touch the file dwSize = MAX_PATH; hr = GetCachePath(ASM_CACHE_GAC, wzTimeStampFile, &dwSize); if (lstrlenW(wzTimeStampFile) + lstrlenW(FILENAME_PUBLISHER_PCY_TIMESTAMP) + 1 >= MAX_PATH) { hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW); goto Exit; } PathRemoveBackslash(wzTimeStampFile); lstrcatW(wzTimeStampFile, FILENAME_PUBLISHER_PCY_TIMESTAMP); hFile = CreateFileW(wzTimeStampFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (hFile == INVALID_HANDLE_VALUE) { hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; } Exit: if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); } return hr; }
// Заменить в строке Str Count вхождений подстроки FindStr на подстроку ReplStr // Если Count < 0 - заменять "до полной победы" // Return - количество замен int ReplaceStrings(string &strStr,const wchar_t *FindStr,const wchar_t *ReplStr,int Count,BOOL IgnoreCase) { const int LenFindStr=StrLength(FindStr); if ( !LenFindStr || !Count ) return 0; const int LenReplStr=StrLength(ReplStr); size_t L=strStr.GetLength(); const int Delta = LenReplStr-LenFindStr; const int AllocDelta = Delta > 0 ? Delta*10 : 0; size_t I=0; int J=0; while (I+LenFindStr <= L) { int Res=IgnoreCase?StrCmpNI(&strStr[I], FindStr, LenFindStr):StrCmpN(&strStr[I], FindStr, LenFindStr); if (!Res) { wchar_t *Str; if (L+Delta+1 > strStr.GetSize()) Str = strStr.GetBuffer(L+AllocDelta); else Str = strStr.GetBuffer(); if (Delta > 0) wmemmove(Str+I+Delta,Str+I,L-I+1); else if (Delta < 0) wmemmove(Str+I,Str+I-Delta,L-I+Delta+1); wmemcpy(Str+I,ReplStr,LenReplStr); I += LenReplStr; L+=Delta; strStr.ReleaseBuffer(L); if (++J == Count && Count > 0) break; } else { I++; } } return J; }
/* Character string comparison */ static int KlezTypeCheckSub( const char* name, int mask ) { VIRUSKEYTBL* tbl = viruskeytbl; while( tbl->keyname ) { if( tbl->type & mask ) { if( !tbl->length ) { if( StrCmpI( name, tbl->keyname ) == 0 ) return 1; } else { if( StrCmpNI( name, tbl->keyname, tbl->length ) == 0 ) return 1; } } tbl++; } return 0; }
bool History::GetAllSimilar(VMenu &HistoryMenu,const wchar_t *Str) { int Length=StrLength(Str); for (HistoryRecord *HistoryItem=HistoryList.Last();HistoryItem;HistoryItem=HistoryList.Prev(HistoryItem)) { //Maximus5: в Far3.0 здесь другое условие: "if (!StrCmpNI(Str,HistoryItem->strName,Length))" if (!StrCmpNI(Str,HistoryItem->strName,Length) && StrCmp(Str,HistoryItem->strName)) { MenuItemEx NewItem={}; NewItem.strName = HistoryItem->strName; if(HistoryItem->Lock) { NewItem.Flags|=LIF_CHECKED; } HistoryMenu.SetUserData(HistoryItem,sizeof(HistoryItem),HistoryMenu.AddItem(&NewItem)); } } return false; }
bool History::GetSimilar(string &strStr, int LastCmdPartLength, bool bAppend) { int Length=(int)strStr.size(); if (LastCmdPartLength!=-1 && LastCmdPartLength<Length) Length=LastCmdPartLength; if (LastCmdPartLength==-1) { ResetPosition(); } int i=0; string strName; unsigned __int64 HistoryItem=HistoryCfgRef()->CyclicGetPrev(m_TypeHistory, m_HistoryName, m_CurrentItem, strName); while (HistoryItem != m_CurrentItem) { if (!HistoryItem) { if (++i > 1) //infinite loop break; HistoryItem = HistoryCfgRef()->CyclicGetPrev(m_TypeHistory, m_HistoryName, HistoryItem, strName); continue; } if (!StrCmpNI(strStr.data(),strName.data(),Length) && strStr != strName) { if (bAppend) strStr += strName.data() + Length; else strStr = strName; m_CurrentItem = HistoryItem; return true; } HistoryItem = HistoryCfgRef()->CyclicGetPrev(m_TypeHistory, m_HistoryName, HistoryItem, strName); } return false; }
static DWORD funcLook(const wchar_t *s) { static bool InitedInternalFuncs=false; if (!InitedInternalFuncs) { KeyMacro::RegisterMacroIntFunction(); InitedInternalFuncs=true; } size_t CountMacroFunction=KeyMacro::GetCountMacroFunction(); for (size_t I=0; I < CountMacroFunction; ++I) { const TMacroFunction *mFunc=KeyMacro::GetMacroFunction(I); if (!StrCmpNI(s, mFunc->Name, (int)Max(StrLength(mFunc->Name),StrLength(s)))) { return (DWORD)mFunc->Code; } } return (DWORD)MCODE_F_NOFUNC; }
void EnumFiles(VMenu2& Menu, const string& Str) { if(!Str.empty()) { string strStr(Str); size_t Pos = 0; if(std::count(ALL_CONST_RANGE(strStr), L'"') & 1) // odd quotes count { Pos = strStr.rfind(L'"'); } else { for(Pos=strStr.size()-1; Pos!=static_cast<size_t>(-1); Pos--) { if(strStr[Pos]==L'"') { Pos--; while(strStr[Pos]!=L'"' && Pos!=static_cast<size_t>(-1)) { Pos--; } } else if(strStr[Pos]==L' ') { Pos++; break; } } } if(Pos==static_cast<size_t>(-1)) { Pos=0; } bool StartQuote=false; if(Pos < strStr.size() && strStr[Pos]==L'"') { Pos++; StartQuote=true; } string strStart(strStr.data(),Pos); Unquote(strStr.erase(0, Pos)); if(!strStr.empty()) { string strExp = os::env::expand_strings(strStr); os::fs::enum_file Find(strExp+L"*"); bool Separator=false; std::for_each(CONST_RANGE(Find, i) { const wchar_t* FileName=PointToName(strStr); bool NameMatch=!StrCmpNI(FileName, i.strFileName.data(), StrLength(FileName)), AltNameMatch = NameMatch? false : !StrCmpNI(FileName, i.strAlternateFileName.data(), StrLength(FileName)); if(NameMatch || AltNameMatch) { strStr.resize(FileName-strStr.data()); string strAdd (strStr + (NameMatch ? i.strFileName : i.strAlternateFileName)); if (!StartQuote) QuoteSpace(strAdd); string strTmp(strStart+strAdd); if(StartQuote) strTmp += L'"'; if(!Separator) { if(Menu.GetItemCount()) { MenuItemEx Item; Item.strName = MSG(MCompletionFilesTitle); Item.Flags=LIF_SEPARATOR; Menu.AddItem(Item); } else { Menu.SetTitle(MSG(MCompletionFilesTitle)); } Separator=true; } Menu.AddItem(strTmp); } });
// обработка единичного меню int UserMenu::ProcessSingleMenu(DList<UserMenuItem> *Menu, int MenuPos, DList<UserMenuItem> *MenuRoot, const string& MenuFileName, const wchar_t *Title) { for (;;) { int NumLine=0, ExitCode, FuncPos[24]; UserMenuItem *CurrentMenuItem = nullptr; // очистка F-хоткеев for (size_t I=0 ; I < ARRAYSIZE(FuncPos) ; I++) FuncPos[I]=-1; string strName,strShortName; CtrlObject->Cp()->ActivePanel->GetCurName(strName,strShortName); /* $ 24.07.2000 VVM + При показе главного меню в заголовок добавляет тип - FAR/Registry */ string strMenuTitle; if (Title && *Title) { strMenuTitle = Title; } else { switch (MenuMode) { case MM_LOCAL: strMenuTitle = MSG(MLocalMenuTitle); break; case MM_GLOBAL: strMenuTitle = MSG(MMainMenuTitle); strMenuTitle += L" ("; strMenuTitle += MSG(MMainMenuGlobal); strMenuTitle += L")"; break; default: strMenuTitle = MSG(MMainMenuTitle); strMenuTitle += L" ("; strMenuTitle += MSG(MMainMenuUser); strMenuTitle += L")"; } } { VMenu UserMenu(strMenuTitle,nullptr,0,ScrY-4); UserMenu.SetFlags(VMENU_WRAPMODE); UserMenu.SetHelp(L"UserMenu"); UserMenu.SetPosition(-1,-1,0,0); UserMenu.SetBottomTitle(MSG(MMainMenuBottomTitle)); MenuNeedRefresh=true; while (!UserMenu.Done()) { if (MenuNeedRefresh) { UserMenu.Hide(); // спрячем // "изнасилуем" (перезаполним :-) NumLine=FillUserMenu(UserMenu,Menu,MenuPos,FuncPos,strName,strShortName); // заставим манагер менюхи корректно отрисовать ширину и // высоту, а заодно и скорректировать вертикальные позиции UserMenu.SetPosition(-1,-1,-1,-1); UserMenu.Show(); MenuNeedRefresh=false; } int Key=UserMenu.ReadInput(); MenuPos=UserMenu.GetSelectPos(); void* userdata = UserMenu.GetUserData(nullptr, 0, MenuPos); CurrentMenuItem = userdata? *static_cast<UserMenuItem**>(userdata):nullptr; if ((unsigned int)Key>=KEY_F1 && (unsigned int)Key<=KEY_F24) { int FuncItemPos; if ((FuncItemPos=FuncPos[Key-KEY_F1])!=-1) { UserMenu.Modal::SetExitCode(FuncItemPos); continue; } } else if (Key == L' ') // исключаем пробел из "хоткеев"! continue; switch (Key) { /* $ 24.08.2001 VVM + Стрелки вправо/влево открывают/закрывают подменю соответственно */ case KEY_RIGHT: case KEY_NUMPAD6: case KEY_MSWHEEL_RIGHT: if (CurrentMenuItem && CurrentMenuItem->Submenu) UserMenu.SetExitCode(MenuPos); break; case KEY_LEFT: case KEY_NUMPAD4: case KEY_MSWHEEL_LEFT: if (Title && *Title) UserMenu.SetExitCode(-1); break; case KEY_NUMDEL: case KEY_DEL: if (CurrentMenuItem) DeleteMenuRecord(Menu,CurrentMenuItem); break; case KEY_INS: case KEY_F4: case KEY_SHIFTF4: case KEY_NUMPAD0: { bool bNew = Key == KEY_INS || Key == KEY_NUMPAD0; if (!bNew && !CurrentMenuItem) break; EditMenu(Menu,CurrentMenuItem,bNew); break; } case KEY_CTRLUP: case KEY_RCTRLUP: case KEY_CTRLDOWN: case KEY_RCTRLDOWN: { int Pos=UserMenu.GetSelectPos(); if (Pos!=UserMenu.GetItemCount()-1 && CurrentMenuItem) { if (!((Key==KEY_CTRLUP || Key==KEY_RCTRLUP) && !Pos) && !((Key==KEY_CTRLDOWN || Key==KEY_RCTRLDOWN) && Pos==UserMenu.GetItemCount()-2)) { MenuModified = MenuNeedRefresh = true; if (Key==KEY_CTRLUP || Key==KEY_RCTRLUP) { Menu->MoveBefore(Menu->Prev(CurrentMenuItem),CurrentMenuItem); MenuPos--; } else { Menu->MoveAfter(Menu->Next(CurrentMenuItem),CurrentMenuItem); MenuPos++; } } } } break; case KEY_ALTF4: // редактировать все меню case KEY_RALTF4: { File MenuFile; (*FrameManager)[0]->Unlock(); { ConsoleTitle *OldTitle=new ConsoleTitle; SaveMenu(MenuFileName); FileEditor ShellEditor(MenuFileName,CP_UNICODE,FFILEEDIT_DISABLEHISTORY,-1,-1,nullptr); delete OldTitle; ShellEditor.SetDynamicallyBorn(false); FrameManager->EnterModalEV(); FrameManager->ExecuteModal(); FrameManager->ExitModalEV(); if (!ShellEditor.IsFileChanged() || (!MenuFile.Open(MenuFileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING))) { return 0; } } MenuRoot->Clear(); GetFileString GetStr(MenuFile); MenuFileToList(MenuRoot, MenuFile, GetStr); MenuFile.Close(); MenuModified=true; UserMenu.Hide(); return 0; // Закрыть меню } /* $ 28.06.2000 tran выход из пользовательского меню по ShiftF10 из любого уровня вложенности просто задаем ExitCode -1, и возвращаем FALSE - по FALSE оно и выйдет откуда угодно */ case KEY_SHIFTF10: //UserMenu.SetExitCode(-1); return EC_CLOSE_MENU; case KEY_SHIFTF2: // Показать главное меню return(EC_MAIN_MENU); case KEY_BS: // Показать меню из родительского каталога только в MM_LOCAL режиме if (MenuMode == MM_LOCAL) return EC_PARENT_MENU; default: UserMenu.ProcessInput(); if (MenuPos!=UserMenu.GetSelectPos()) { MenuPos=UserMenu.GetSelectPos(); userdata = UserMenu.GetUserData(nullptr, 0, MenuPos); CurrentMenuItem = userdata? *static_cast<UserMenuItem**>(userdata):nullptr; } if (Key == KEY_F1) MenuNeedRefresh=true; break; } // switch(Key) } // while (!UserMenu.Done()) ExitCode=UserMenu.Modal::GetExitCode(); if (ExitCode<0 || ExitCode>=NumLine || !CurrentMenuItem) return EC_CLOSE_LEVEL; // вверх на один уровень void* userdata = UserMenu.GetUserData(nullptr, 0, ExitCode); CurrentMenuItem = userdata? *static_cast<UserMenuItem**>(userdata):nullptr; if (!CurrentMenuItem) return EC_CLOSE_LEVEL; // вверх на один уровень } if (CurrentMenuItem->Submenu) { /* $ 20.08.2001 VVM + При вложенных меню показывает заголовки предыдущих */ string strSubMenuLabel = CurrentMenuItem->strLabel; SubstFileName(strSubMenuLabel,strName,strShortName,nullptr,nullptr,nullptr,nullptr,TRUE); apiExpandEnvironmentStrings(strSubMenuLabel, strSubMenuLabel); size_t pos; if (strSubMenuLabel.Pos(pos,L'&')) strSubMenuLabel.LShift(1,pos); string strSubMenuTitle; if (Title && *Title) { strSubMenuTitle = Title; strSubMenuTitle += L" -> "; strSubMenuTitle += strSubMenuLabel; } else { strSubMenuTitle = strSubMenuLabel; } /* $ 14.07.2000 VVM ! Если закрыли подменю, то остаться. Инече передать управление выше */ MenuPos = ProcessSingleMenu(CurrentMenuItem->Menu, 0, MenuRoot, MenuFileName, strSubMenuTitle); if (MenuPos!=EC_CLOSE_LEVEL) return MenuPos; MenuPos = ExitCode; continue; } /* $ 01.05.2001 IS Отключим до лучших времен */ //int LeftVisible,RightVisible,PanelsHidden=0; string strCmdLineDir; CtrlObject->CmdLine->GetCurDir(strCmdLineDir); string strOldCmdLine; CtrlObject->CmdLine->GetString(strOldCmdLine); int OldCmdLineCurPos = CtrlObject->CmdLine->GetCurPos(); int OldCmdLineLeftPos = CtrlObject->CmdLine->GetLeftPos(); intptr_t OldCmdLineSelStart, OldCmdLineSelEnd; CtrlObject->CmdLine->GetSelection(OldCmdLineSelStart,OldCmdLineSelEnd); CtrlObject->CmdLine->LockUpdatePanel(TRUE); // Цикл исполнения команд меню (CommandX) for (string *str=CurrentMenuItem->Commands.First(); str; str=CurrentMenuItem->Commands.Next(str)) { string strCommand = *str; string strListName, strAnotherListName; string strShortListName, strAnotherShortListName; if (!((!StrCmpNI(strCommand,L"REM",3) && IsSpaceOrEos(strCommand.At(3))) || !StrCmpNI(strCommand,L"::",2))) { /* Осталось корректно обработать ситуацию, например: if exist !#!\!^!.! far:edit < diff -c -p !#!\!^!.! !\!.! Т.е. сначала "вычислить" кусок "if exist !#!\!^!.!", ну а если выполнится, то делать дальше. Или еще пример, if exist ..\a.bat D:\FAR\170\DIFF.MY\mkdiff.bat !?&Номер патча?! ЭТО выполняется всегда, т.к. парсинг всей строки идет, а надо проверить фазу "if exist ..\a.bat", а уж потом делать выводы... */ //if(ExtractIfExistCommand(Command)) { /* $ 01.05.2001 IS Отключим до лучших времен */ /* if (!PanelsHidden) { LeftVisible=CtrlObject->Cp()->LeftPanel->IsVisible(); RightVisible=CtrlObject->Cp()->RightPanel->IsVisible(); CtrlObject->Cp()->LeftPanel->Hide(); CtrlObject->Cp()->RightPanel->Hide(); CtrlObject->Cp()->LeftPanel->SetUpdateMode(FALSE); CtrlObject->Cp()->RightPanel->SetUpdateMode(FALSE); PanelsHidden=TRUE; } */ //; int PreserveLFN=SubstFileName(strCommand, strName, strShortName, &strListName, &strAnotherListName, &strShortListName, &strAnotherShortListName, FALSE, strCmdLineDir); bool ListFileUsed=!strListName.IsEmpty()||!strAnotherListName.IsEmpty()||!strShortListName.IsEmpty()||!strAnotherShortListName.IsEmpty(); if (ExtractIfExistCommand(strCommand)) { PreserveLongName PreserveName(strShortName,PreserveLFN); RemoveExternalSpaces(strCommand); if (!strCommand.IsEmpty()) { bool isSilent=false; if (strCommand.At(0) == L'@') { strCommand.LShift(1); isSilent=true; } ProcessOSAliases(strCommand); // TODO: Ахтунг. В режиме isSilent имеем проблемы с командами, которые выводят что-то на экран // Здесь необходимо переделка, например, перед исполнением подсунуть временный экранный буфер, а потом его содержимое подсунуть в ScreenBuf... if (!isSilent) { CtrlObject->CmdLine->ExecString(strCommand,FALSE, 0, 0, ListFileUsed); } else { SaveScreen SaveScr; CtrlObject->Cp()->LeftPanel->CloseFile(); CtrlObject->Cp()->RightPanel->CloseFile(); Execute(strCommand,TRUE, 0, 0, 0, ListFileUsed, true); } } } } } // strCommand != "REM" if (!strListName.IsEmpty()) apiDeleteFile(strListName); if (!strAnotherListName.IsEmpty()) apiDeleteFile(strAnotherListName); if (!strShortListName.IsEmpty()) apiDeleteFile(strShortListName); if (!strAnotherShortListName.IsEmpty()) apiDeleteFile(strAnotherShortListName); } // while (1) CtrlObject->CmdLine->LockUpdatePanel(FALSE); if (!strOldCmdLine.IsEmpty()) // восстановим сохраненную командную строку { CtrlObject->CmdLine->SetString(strOldCmdLine, FrameManager->IsPanelsActive()); CtrlObject->CmdLine->SetCurPos(OldCmdLineCurPos, OldCmdLineLeftPos); CtrlObject->CmdLine->Select(OldCmdLineSelStart, OldCmdLineSelEnd); } /* $ 01.05.2001 IS Отключим до лучших времен */ /* if (PanelsHidden) { CtrlObject->Cp()->LeftPanel->SetUpdateMode(TRUE); CtrlObject->Cp()->RightPanel->SetUpdateMode(TRUE); CtrlObject->Cp()->LeftPanel->Update(UPDATE_KEEP_SELECTION); CtrlObject->Cp()->RightPanel->Update(UPDATE_KEEP_SELECTION); if (RightVisible) CtrlObject->Cp()->RightPanel->Show(); if (LeftVisible) CtrlObject->Cp()->LeftPanel->Show(); } */ /* $ 14.07.2000 VVM ! Закрыть меню */ /* $ 25.04.2001 DJ - сообщаем, что была выполнена команда (нужно перерисовать панели) */ return EC_COMMAND_SELECTED; } }
static int TryInstallDevice( const char *pInfFilePath, const char *pDevId, const char *pDevInstID, PCNC_DEV_CALLBACK pDevCallBack, void *pDevCallBackParam, bool updateDriver, BOOL *pRebootRequired) { GUID classGUID; char className[32]; if (!SetupDiGetINFClass(pInfFilePath, &classGUID, className, sizeof(className)/sizeof(className[0]), 0)) { ShowLastError(MB_OK|MB_ICONSTOP, "SetupDiGetINFClass(%s)", pInfFilePath); return IDCANCEL; } //Trace("className=%s\n", className); HDEVINFO hDevInfo; hDevInfo = SetupDiCreateDeviceInfoList(&classGUID, 0); if (hDevInfo == INVALID_HANDLE_VALUE) { ShowLastError(MB_OK|MB_ICONSTOP, "SetupDiCreateDeviceInfoList()"); return IDCANCEL; } int res = IDCONTINUE; SP_DEVINFO_DATA devInfoData; devInfoData.cbSize = sizeof(devInfoData); if (!pDevInstID) { if (StrCmpNI(pDevId, "root\\", 5) == 0) { /* * root\<enumerator-specific-device-ID> */ if (!SetupDiCreateDeviceInfo(hDevInfo, pDevId + 5, &classGUID, NULL, 0, DICD_GENERATE_ID, &devInfoData)) res = IDCANCEL; } else { SetLastError(ERROR_INVALID_DEVINST_NAME); res = IDCANCEL; } } else if (StrChr(pDevInstID, '\\')) { /* * <enumerator>\<enumerator-specific-device-ID>\<instance-specific-ID> */ if (!SetupDiCreateDeviceInfo(hDevInfo, pDevInstID, &classGUID, NULL, 0, 0, &devInfoData)) res = IDCANCEL; if (res != IDCONTINUE && GetLastError() == ERROR_DEVINST_ALREADY_EXISTS) { char *pTmpDevInstID = NULL; if (SetStr(&pTmpDevInstID, pDevInstID)) { char *pSave; char *p; p = STRTOK_R(pTmpDevInstID, "\\", &pSave); if (p && !lstrcmp(p, REGSTR_KEY_ROOTENUM)) { p = STRTOK_R(NULL, "\\", &pSave); if (SetupDiCreateDeviceInfo(hDevInfo, p, &classGUID, NULL, 0, DICD_GENERATE_ID, &devInfoData)) res = IDCONTINUE; } SetStr(&pTmpDevInstID, NULL); } else { SetLastError(ERROR_DEVINST_ALREADY_EXISTS); } } } else { /* * <enumerator-specific-device-ID> */ if (!SetupDiCreateDeviceInfo(hDevInfo, pDevInstID, &classGUID, NULL, 0, DICD_GENERATE_ID, &devInfoData)) res = IDCANCEL; } if (res != IDCONTINUE) { ShowLastError(MB_OK|MB_ICONSTOP, "SetupDiCreateDeviceInfo()"); goto exit1; } char hardwareId[MAX_DEVICE_ID_LEN + 1 + 1]; SNPRINTF(hardwareId, sizeof(hardwareId)/sizeof(hardwareId[0]) - 1, "%s", pDevId); int hardwareIdLen; hardwareIdLen = lstrlen(hardwareId) + 1 + 1; hardwareId[hardwareIdLen - 1] = 0; if (!SetupDiSetDeviceRegistryProperty(hDevInfo, &devInfoData, SPDRP_HARDWAREID, (LPBYTE)hardwareId, hardwareIdLen * sizeof(hardwareId[0]))) { res = IDCANCEL; ShowLastError(MB_OK|MB_ICONSTOP, "SetupDiSetDeviceRegistryProperty()"); goto exit1; } if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, hDevInfo, &devInfoData)) { res = IDCANCEL; ShowLastError(MB_OK|MB_ICONSTOP, "SetupDiCallClassInstaller()"); goto exit1; } if (pDevCallBack) { DevProperties devProperties; if (!devProperties.DevId(pDevId)) { res = IDCANCEL; goto exit2; } if (!pDevCallBack(hDevInfo, &devInfoData, &devProperties, NULL, pDevCallBackParam)) { res = IDCANCEL; goto exit2; } } if (updateDriver) res = UpdateDriver(pInfFilePath, pDevId, 0, TRUE, pRebootRequired); exit2: if (res != IDCONTINUE) { if (!SetupDiCallClassInstaller(DIF_REMOVE, hDevInfo, &devInfoData)) ShowLastError(MB_OK|MB_ICONWARNING, "SetupDiCallClassInstaller()"); } exit1: SetupDiDestroyDeviceInfoList(hDevInfo); return res; }
VOID WINAPI HashCalcSetSavePrefix( PHASHCALCCONTEXT phcctx, PTSTR pszSave ) { // We have to be careful here about case sensitivity since we are now // working with a user-provided path instead of a system-provided path... // We want to build new paths without resorting to using "..", as that is // ugly, fragile (often more so than absolute paths), and not to mention, // complicated to calculate. This means that relative paths will be used // only for paths within the same line of ancestry. BOOL bMultiSel; PTSTR pszOrig; PTSTR pszTail; // First, grab one of the original paths to work with SLReset(phcctx->hListRaw); pszOrig = SLGetDataAndStep(phcctx->hListRaw); bMultiSel = SLCheck(phcctx->hListRaw); // Unfortunately, we also have to contend with the possibility that one of // these paths may be in short name format (e.g., if the user navigates to // %TEMP% on a NT 5.x system) { // The scratch buffer's sz members are large enough for us PTSTR pszOrigLong = (PTSTR)phcctx->scratch.szW; PTSTR pszSaveLong = (PTSTR)phcctx->scratch.szA; // Copy original path to scratch and terminate pszTail = SSChainNCpy(pszOrigLong, pszOrig, phcctx->cchPrefix); pszTail[0] = 0; // Copy output path to scratch and terminate pszTail = SSChainNCpy(pszSaveLong, pszSave, phcctx->ofn.nFileOffset); pszTail[0] = 0; // Normalize both paths to LFN GetLongPathName(pszOrigLong, pszOrigLong, MAX_PATH_BUFFER); GetLongPathName(pszSaveLong, pszSaveLong, MAX_PATH_BUFFER); // We will only handle the case where they are the same, to prevent our // re-prefixing from messing up the base behavior; it is not worth the // trouble to account for LFN for all cases--just let it fall through // to an absolute path. if (StrCmpNI(pszOrigLong, pszSaveLong, MAX_PATH_BUFFER) == 0) { phcctx->cchAdjusted = phcctx->cchPrefix; return; } } if (pszTail = StrRChr(pszSave, NULL, TEXT('\\'))) { phcctx->cchAdjusted = (UINT)(pszTail - pszSave) + 1; if (phcctx->cchAdjusted <= phcctx->cchPrefix) { if (StrCmpNI(pszOrig, pszSave, phcctx->cchAdjusted) == 0) { // If the ouput prefix is the same as or a parent of the input // prefix... if (!(IsDoubleSlashPath(pszSave) && phcctx->cchAdjusted < 3)) return; } } else if (!bMultiSel) { // We will make an exception for the case where the user selects // a single directory from the Shell and then saves the output in // that directory... BOOL bEqual; *pszTail = 0; bEqual = StrCmpNI(pszOrig, pszSave, phcctx->cchAdjusted) == 0; *pszTail = TEXT('\\'); if (bEqual) return; } } // If we have reached this point, we need to use an absolute path if ( pszSave[1] == TEXT(':') && phcctx->cchPrefix > 2 && StrCmpNI(pszOrig, pszSave, 2) == 0 ) { // Omit drive letter phcctx->cchAdjusted = 2; } else { // Full absolute path phcctx->cchAdjusted = 0; } }
inline bool StrEqualNI(const wchar_t *s1, const wchar_t *s2, size_t n) {return 0 == StrCmpNI(s1, s2, n);}
// Refer to Figures.pptx/CNumber::Read() state chart for details. HRESULT CNumberRange::Read(const wchar_t * pstr, uint_least16_t uiLength) { HRESULT hr = S_OK; int32_t i0 = 0, i1 = 0; do { // check invalid arguments if (uiLength == 0) { uiLength = (uint_least16_t)lstrlen(pstr); } if (pstr == nullptr) { hr = E_POINTER; break; } // start parsing. const wchar_t* const pstrEnd = pstr + uiLength; int iState = sm_stateInitial; int iSign = 1; // sign of numbers, [-1 | +1] while (iState != sm_stateExit) { switch (iState) { case sm_stateInitial: // waiting for [U | 0-9] and skipping white-spaces if (ChrCmpI(*pstr, L'U') == 0) { iState = sm_stateNegativeUnlimited; break; } else if (*pstr == L'+') { iSign = 1; iState = sm_stateFirstNumber; pstr++; break; } else if (*pstr == L'-') { iSign = -1; iState = sm_stateFirstNumber; pstr++; break; } else if (IsDigit(pstr)) // is digit { iSign = 1; iState = sm_stateFirstNumber; break; } else if (IsCharSpace(*pstr)) { pstr++; break; } else // invalid case { hr = E_FAIL; iState = sm_stateExit; swprintf_s(CTrace::WrPtr(), CTrace::AvailableLength(), L"State=Initial, *pstr=%wc", *pstr); CTrace::Update2(); break; } case sm_stateNegativeUnlimited: if (StrCmpNI(pstr, sm_strUnlimited, sm_iLengthOfStrUnLimited) == 0) { pstr += sm_iLengthOfStrUnLimited; i0 = sm_iNoBoundary; iState = sm_stateFirstDelim; break; } else { // invalid case hr = E_FAIL; iState = sm_stateExit; swprintf_s(CTrace::WrPtr(), CTrace::AvailableLength(), L"State=NagativeUnlimited, *pstr=%wc", *pstr); CTrace::Update2(); break; } case sm_stateFirstNumber: if (IsDigit(pstr)) { i0 = i0 * 10 + static_cast<int32_t>(*pstr - L'0'); pstr++; break; } else if (IsCharSpace(*pstr)) { pstr++; i0 *= iSign; iState = sm_stateFirstDelim; break; } else if (*pstr == sm_chBar) { pstr++; i0 *= iSign; iState = sm_stateFirstDelim2; break; } else if (pstrEnd == pstr) { // end of parsing with only a single number i0 *= iSign; i1 = i0; iState = sm_stateExit; break; } else { // invalid case iState = sm_stateExit; hr = E_FAIL; swprintf_s(CTrace::WrPtr(), CTrace::AvailableLength(), L"State=FirstNumber, *pstr=%wc", *pstr); CTrace::Update2(); break; } case sm_stateFirstDelim: if (pstrEnd == pstr) { // end of parsing with only a single number i1 = i0; iState = sm_stateExit; break; } else if (IsCharSpace(*pstr)) { pstr++; break; } else if (sm_chBar == *pstr) { pstr++; iState = sm_stateFirstDelim2; break; } else { // invalid case iState = sm_stateExit; hr = E_FAIL; swprintf_s(CTrace::WrPtr(), CTrace::AvailableLength(), L"State=FirstDelim, *pstr=%wc", *pstr); CTrace::Update2(); break; } case sm_stateFirstDelim2: if (IsCharSpace(*pstr)) { pstr++; break; } else if (*pstr == L'+') { iSign = 1; pstr++; iState = sm_stateSecondNumber; break; } else if (*pstr == L'-') { iSign = -1; pstr++; iState = sm_stateSecondNumber; break; } else if (IsDigit(pstr)) { iSign = 1; iState = sm_stateSecondNumber; break; } else if (ChrCmpI(*pstr, L'U') == 0) { iState = sm_statePositiveUnlimited; break; } else { // invalid case hr = E_FAIL; iState = sm_stateExit; swprintf_s(CTrace::WrPtr(), CTrace::AvailableLength(), L"State=FirstDelim2, *pstr=%wc", *pstr); CTrace::Update2(); break; } case sm_statePositiveUnlimited: if (StrCmpNI(pstr, sm_strUnlimited, sm_iLengthOfStrUnLimited) == 0) { i1 = sm_iNoBoundary; iState = sm_stateSecondDelim; pstr += sm_iLengthOfStrUnLimited; break; } else { // invalid case hr = E_FAIL; iState = sm_stateExit; swprintf_s(CTrace::WrPtr(), CTrace::AvailableLength(), L"State=PositiveUnlimited, *pstr=%wc", *pstr); CTrace::Update2(); break; } case sm_stateSecondNumber: if (IsDigit(pstr)) { i1 = (i1 * 10) + static_cast<int>(*pstr - L'0'); pstr++; break; } else if (IsCharSpace(*pstr)) { i1 *= iSign; iState = sm_stateSecondDelim; pstr++; break; } else if (pstr == pstrEnd) { i1 *= iSign; iState = sm_stateExit; break; } else { hr = E_FAIL; iState = sm_stateExit; swprintf_s(CTrace::WrPtr(), CTrace::AvailableLength(), L"State=SecondNumber, *pstr=%wc", *pstr); CTrace::Update2(); break; } case sm_stateSecondDelim: if (IsCharSpace(*pstr)) { pstr++; break; } else if (pstr == pstrEnd) { iState = sm_stateExit; break; } else { hr = E_FAIL; iState = sm_stateExit; swprintf_s(CTrace::WrPtr(), CTrace::AvailableLength(), L"State=SecondDelim, *pstr=%wc", *pstr); CTrace::Update2(); break; } default: // unknown invalid condition iState = sm_stateExit; hr = E_FAIL; break; } } } while (false); if (i0 == i1 && i0 == sm_iNoBoundary) { hr = E_FAIL; } if (SUCCEEDED(hr)) { first = i0; second = (i1 == sm_iNoBoundary) ? i1 : i1 + 1; } else { *this = CNumberRange(); } return hr; }
int _tmain(int argc, TCHAR *argv[]) { HANDLE hFile = INVALID_HANDLE_VALUE; WCHAR *pCmd = NULL; TCHAR chName[CHAPTER_NAME_MAX] = {0}; int pos = 0, rv = 1; _tsetlocale(LC_ALL, TEXT("")); if (argc < 3) { _tprintf(TEXT("Usage: %s <ファイル名> <チャプター位置(msec)> [チャプター名]\n"), argv[0]); goto EXIT; } if (lstrcmpi(PathFindExtension(argv[1]), TEXT(".chapter"))) { _tprintf(TEXT("Error: 拡張子は.chapterである必要があります\n")); goto EXIT; } if ((pos = StrToInt(argv[2])) < 0) { _tprintf(TEXT("Error: チャプター位置は負の整数を指定できません\n")); goto EXIT; } if (argc >= 4) { if (lstrlen(argv[3]) >= CHAPTER_NAME_MAX) { _tprintf(TEXT("Error: チャプター名は%d文字までです\n"), CHAPTER_NAME_MAX - 1); goto EXIT; } if (StrChr(argv[3], TEXT('-'))) { _tprintf(TEXT("Error: チャプター名に-を含めることはできません\n")); goto EXIT; } lstrcpy(chName, argv[3]); } // [チャプターコマンド仕様] // ・ファイルの文字コードはBOM付きUTF-8であること // ・Caseはできるだけ保存するが区別しない // ・"c-"で始めて"c"で終わる // ・チャプターごとに"{正整数}{接頭英文字}{文字列}-"を追加する // ・{接頭英文字}が"c" "d" "e"以外のとき、そのチャプターを無視する // ・"c"なら{正整数}の単位はmsec // ・"d"なら{正整数}の単位は100msec // ・"e"なら{正整数}はCHAPTER_POS_MAX(動画の末尾) // ・仕様を満たさないコマンドは(できるだけ)全体を無視する // ・例1: "c-c" (仕様を満たす最小コマンド) // ・例2: "c-1234cName1-3456c-2345c2ndName-0e-c" if (PathFileExists(argv[1])) { // ファイルが存在すれば追記 // 不整合を防ぐためにSHARE_READ、SHARE_WRITEは指定しない hFile = CreateFile(argv[1], GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { _tprintf(TEXT("Error: ファイルをオープンできません\n")); goto EXIT; } pCmd = NewReadUtfFileToEnd(hFile, CHAPTER_NAME_MAX + 32); // 先頭2文字は"c-"、末尾2文字は"-c"でなければ異常とみなす if (!pCmd || StrCmpNI(pCmd, L"c-", 2) || StrCmpI(pCmd + lstrlen(pCmd) - 2, L"-c")) { _tprintf(TEXT("Error: 書き込むファイルの中身が異常です\n")); goto EXIT; } // 末尾にチャプターを追記 wsprintf(pCmd + lstrlen(pCmd) - 1, L"%dc%s-c", pos, chName); if (!WriteUtfFileToEnd(hFile, pCmd)) { _tprintf(TEXT("Error: 書き込みエラー\n")); goto EXIT; } } else { // ファイルが存在しなければ作成 hFile = CreateFile(argv[1], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { _tprintf(TEXT("Error: ファイルをオープンできません\n")); goto EXIT; } WCHAR cmd[CHAPTER_NAME_MAX + 32]; wsprintf(cmd, L"c-%dc%s-c", pos, chName); if (!WriteUtfFileToEnd(hFile, cmd)) { _tprintf(TEXT("Error: 書き込みエラー\n")); goto EXIT; } } _tprintf(TEXT("%s に書き込みました: チャプター位置=%dmsec,チャプター名=%s\n"), argv[1], pos, chName); rv = 0; EXIT: if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); delete [] pCmd; return rv; }
int NumStrCmp(const wchar_t *s1, size_t n1, const wchar_t *s2, size_t n2, bool IgnoreCase) { size_t l1 = 0; size_t l2 = 0; while (l1 < n1 && l2 < n2 && *s1 && *s2) { if (iswdigit(*s1) && iswdigit(*s2)) { // skip leading zeroes while (l1 < n1 && *s1 == L'0') { s1++; l1++; } while (l2 < n2 && *s2 == L'0') { s2++; l2++; } // if end of string reached if (l1 == n1 || !*s1 || l2 == n2 || !*s2) break; // compare numbers int res = 0; while (l1 < n1 && l2 < n2 && iswdigit(*s1) && iswdigit(*s2)) { if (!res && *s1 != *s2) res = *s1 < *s2 ? -1 : 1; s1++; s2++; l1++; l2++; } if ((l1 == n1 || !iswdigit(*s1)) && (l2 == n2 || !iswdigit(*s2))) { if (res) return res; } else if (l1 == n1 || !iswdigit(*s1)) return -1; else if (l2 == n2 || !iswdigit(*s2)) return 1; } else { int res = IgnoreCase ? StrCmpNI(s1, s2, 1) : StrCmpN(s1, s2, 1); if (res) return res; s1++; s2++; l1++; l2++; } } if ((l1 == n1 || !*s1) && (l2 == n2 || !*s2)) { if (l1 < l2) return -1; else if (l1 == l2) return 0; else return 1; } else if (l1 == n1 || !*s1) return -1; else if (l2 == n2 || !*s2) return 1; assert(false); return 0; }