Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/elfmz/far2l.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorelfmz <fenix1905@tut.by>2021-12-31 12:15:36 +0300
committerelfmz <fenix1905@tut.by>2021-12-31 12:21:48 +0300
commit6b7b5f7fe480107373a6ef3cbd6ee41378c93642 (patch)
tree1af3f15ecc76c47749f74f38302cb33e0a3796e1 /far2l/src/cfg
parenta14dc1a81c797928d4f1b7d6a6b46ecc63f98308 (diff)
split /aux to /mix and /base
Diffstat (limited to 'far2l/src/cfg')
-rw-r--r--far2l/src/cfg/language.cpp601
-rw-r--r--far2l/src/cfg/language.hpp84
2 files changed, 685 insertions, 0 deletions
diff --git a/far2l/src/cfg/language.cpp b/far2l/src/cfg/language.cpp
new file mode 100644
index 00000000..8549b499
--- /dev/null
+++ b/far2l/src/cfg/language.cpp
@@ -0,0 +1,601 @@
+/*
+language.cpp
+
+Работа с lng файлами
+*/
+/*
+Copyright (c) 1996 Eugene Roshal
+Copyright (c) 2000 Far Group
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "headers.hpp"
+
+
+#include "language.hpp"
+#include "lang.hpp"
+#include "scantree.hpp"
+#include "vmenu.hpp"
+#include "manager.hpp"
+#include "message.hpp"
+#include "config.hpp"
+#include "strmix.hpp"
+#include "pathmix.hpp"
+#include "filestr.hpp"
+#include "interf.hpp"
+
+const wchar_t LangFileMask[] = L"*.lng";
+
+#ifndef pack
+#define _PACK_BITS 2
+#define _PACK (1 << _PACK_BITS)
+#define pck(x,N) ( ((x) + ((1<<(N))-1) ) & ~((1<<(N))-1) )
+#define pack(x) pck(x,_PACK_BITS)
+#endif
+
+Language Lang;
+Language OldLang;
+
+static FILE* TryOpenLangFile(const wchar_t *Path,const wchar_t *Mask,const wchar_t *Language, FARString &strFileName, UINT &nCodePage, BOOL StrongLang,FARString *pstrLangName)
+{
+ strFileName.Clear();
+ FILE *LangFile=nullptr;
+ FARString strEngFileName;
+ FARString strLangName;
+ FAR_FIND_DATA_EX FindData;
+ ScanTree ScTree(FALSE,FALSE);
+ ScTree.SetFindPath(Path,Mask);
+
+ while (ScTree.GetNextName(&FindData, strFileName))
+ {
+ if (!Language)
+ break;
+
+ if (!(LangFile=fopen(strFileName.GetMB().c_str(), "rb")))
+ {
+ fprintf(stderr, "OpenLangFile opfailed: %ls\n", strFileName.CPtr());
+
+ strFileName.Clear();
+ }
+ else
+ {
+ OldGetFileFormat(LangFile, nCodePage, nullptr, false);
+
+ if (GetLangParam(LangFile,L"Language",&strLangName,nullptr, nCodePage) && !StrCmpI(strLangName,Language))
+ break;
+
+ fclose(LangFile);
+ LangFile=nullptr;
+
+ if (StrongLang)
+ {
+ strFileName.Clear();
+ strEngFileName.Clear();
+ break;
+ }
+
+ if (!StrCmpI(strLangName,L"English"))
+ strEngFileName = std::move(strFileName);
+ }
+ }
+
+ if (!LangFile)
+ {
+ if (!strEngFileName.IsEmpty())
+ strFileName = std::move(strEngFileName);
+
+ if (!strFileName.IsEmpty())
+ {
+ LangFile=fopen(Wide2MB(strFileName).c_str(), FOPEN_READ);
+
+ if (pstrLangName)
+ *pstrLangName=std::move(strLangName);
+ }
+ }
+
+ return(LangFile);
+}
+
+FILE* OpenLangFile(FARString strPath,const wchar_t *Mask,const wchar_t *Language, FARString &strFileName, UINT &nCodePage, BOOL StrongLang,FARString *pstrLangName)
+{
+ FILE* out = TryOpenLangFile(strPath, Mask, Language, strFileName, nCodePage, StrongLang, pstrLangName);
+ if (!out) {
+ if (TranslateFarString<TranslateInstallPath_Lib2Share>(strPath)) {
+ out = TryOpenLangFile(strPath, Mask, Language, strFileName, nCodePage, StrongLang, pstrLangName);
+ }
+ }
+ return out;
+}
+
+int GetLangParam(FILE *SrcFile,const wchar_t *ParamName,FARString *strParam1, FARString *strParam2, UINT nCodePage)
+{
+ wchar_t ReadStr[1024];
+ FARString strFullParamName = L".";
+ strFullParamName += ParamName;
+ int Length=(int)strFullParamName.GetLength();
+ /* $ 29.11.2001 DJ
+ не поганим позицию в файле; дальше @Contents не читаем
+ */
+ BOOL Found = FALSE;
+ long OldPos = ftell(SrcFile);
+
+ while (ReadString(SrcFile, ReadStr, 1024, nCodePage))
+ {
+ if (!StrCmpNI(ReadStr,strFullParamName,Length))
+ {
+ wchar_t *Ptr=wcschr(ReadStr,L'=');
+
+ if (Ptr)
+ {
+ *strParam1 = Ptr+1;
+
+ if (strParam2)
+ strParam2->Clear();
+
+ size_t pos;
+
+ if (strParam1->Pos(pos,L','))
+ {
+ if (strParam2)
+ {
+ *strParam2 = *strParam1;
+ strParam2->LShift(pos+1);
+ RemoveTrailingSpaces(*strParam2);
+ }
+
+ strParam1->Truncate(pos);
+ }
+
+ RemoveTrailingSpaces(*strParam1);
+ Found = TRUE;
+ break;
+ }
+ }
+ else if (!StrCmpNI(ReadStr, L"@Contents", 9))
+ break;
+ }
+
+ fseek(SrcFile,OldPos,SEEK_SET);
+ return(Found);
+}
+
+int Select(int HelpLanguage,VMenu **MenuPtr)
+{
+ const wchar_t *Title,*Mask;
+ FARString *strDest;
+
+ if (HelpLanguage)
+ {
+ Title=MSG(MHelpLangTitle);
+ Mask=HelpFileMask;
+ strDest=&Opt.strHelpLanguage;
+ }
+ else
+ {
+ Title=MSG(MLangTitle);
+ Mask=LangFileMask;
+ strDest=&Opt.strLanguage;
+ }
+
+ MenuItemEx LangMenuItem;
+ LangMenuItem.Clear();
+ VMenu *LangMenu=new VMenu(Title,nullptr,0,ScrY-4);
+ *MenuPtr=LangMenu;
+ LangMenu->SetFlags(VMENU_WRAPMODE);
+ LangMenu->SetPosition(ScrX/2-8+5*HelpLanguage,ScrY/2-4+2*HelpLanguage,0,0);
+ FARString strFullName;
+ FAR_FIND_DATA_EX FindData;
+ ScanTree ScTree(FALSE,FALSE);
+ ScTree.SetFindPath(g_strFarPath, Mask);
+
+ while (ScTree.GetNextName(&FindData,strFullName))
+ {
+ FILE *LangFile=fopen(Wide2MB(strFullName).c_str(), FOPEN_READ);
+
+ if (!LangFile)
+ continue;
+
+ UINT nCodePage=CP_UTF8;
+ OldGetFileFormat(LangFile, nCodePage, nullptr, false);
+ FARString strLangName, strLangDescr;
+
+ if (GetLangParam(LangFile,L"Language",&strLangName,&strLangDescr,nCodePage))
+ {
+ FARString strEntryName;
+
+ if (!HelpLanguage || (!GetLangParam(LangFile,L"PluginContents",&strEntryName,nullptr,nCodePage) &&
+ !GetLangParam(LangFile,L"DocumentContents",&strEntryName,nullptr,nCodePage)))
+ {
+ LangMenuItem.strName.Format(L"%.40ls", !strLangDescr.IsEmpty() ? strLangDescr.CPtr():strLangName.CPtr());
+
+ /* $ 01.08.2001 SVS
+ Не допускаем дубликатов!
+ Если в каталог с ФАРом положить еще один HLF с одноименным
+ языком, то... фигня получается при выборе языка.
+ */
+ if (LangMenu->FindItem(0,LangMenuItem.strName,LIFIND_EXACTMATCH) == -1)
+ {
+ LangMenuItem.SetSelect(!StrCmpI(*strDest,strLangName));
+ LangMenu->SetUserData(strLangName.CPtr(),0,LangMenu->AddItem(&LangMenuItem));
+ }
+ }
+ }
+
+ fclose(LangFile);
+ }
+
+ LangMenu->AssignHighlights(FALSE);
+ LangMenu->Process();
+
+ if (LangMenu->Modal::GetExitCode()<0)
+ return FALSE;
+
+ wchar_t *lpwszDest = strDest->GetBuffer(LangMenu->GetUserDataSize()/sizeof(wchar_t)+1);
+ LangMenu->GetUserData(lpwszDest, LangMenu->GetUserDataSize());
+ strDest->ReleaseBuffer();
+ return(LangMenu->GetUserDataSize());
+}
+
+/* $ 01.09.2000 SVS
+ + Новый метод, для получения параметров для .Options
+ .Options <KeyName>=<Value>
+*/
+int GetOptionsParam(FILE *SrcFile,const wchar_t *KeyName,FARString &strValue, UINT nCodePage)
+{
+ wchar_t ReadStr[1024];
+ FARString strFullParamName;
+ int Length=StrLength(L".Options");
+ long CurFilePos=ftell(SrcFile);
+
+ while (ReadString(SrcFile, ReadStr, 1024, nCodePage) )
+ {
+ if (!StrCmpNI(ReadStr,L".Options",Length))
+ {
+ strFullParamName = RemoveExternalSpaces(ReadStr+Length);
+ size_t pos;
+
+ if (strFullParamName.RPos(pos,L'='))
+ {
+ strValue = strFullParamName;
+ strValue.LShift(pos+1);
+ RemoveExternalSpaces(strValue);
+ strFullParamName.Truncate(pos);
+ RemoveExternalSpaces(strFullParamName);
+
+ if (!StrCmpI(strFullParamName,KeyName))
+ {
+ fseek(SrcFile,CurFilePos,SEEK_SET);
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ fseek(SrcFile,CurFilePos,SEEK_SET);
+ return FALSE;
+}
+
+Language::Language():
+ LastError(LERROR_SUCCESS),
+ LanguageLoaded(false),
+ MsgAddr(nullptr),
+ MsgList(nullptr),
+ MsgAddrA(nullptr),
+ MsgListA(nullptr),
+ MsgSize(0),
+ MsgCount(0),
+ m_bUnicode(true)
+{
+}
+
+
+bool Language::Init(const wchar_t *Path, bool bUnicode, int CountNeed)
+{
+ //fprintf(stderr, "Language::Init(%ls, %u, %u)\n", Path, bUnicode, CountNeed);
+ if (MsgList || MsgListA)
+ return true;
+ ErrnoSaver gle;
+ LastError = LERROR_SUCCESS;
+ m_bUnicode = bUnicode;
+ UINT nCodePage = CP_UTF8;
+ //fprintf(stderr, "Opt.strLanguage=%ls\n", Opt.strLanguage.CPtr());
+ FARString strLangName=Opt.strLanguage;
+ FILE *LangFile=OpenLangFile(Path,LangFileMask,Opt.strLanguage,strMessageFile, nCodePage,FALSE, &strLangName);
+
+ if (this == &Lang && StrCmpI(Opt.strLanguage,strLangName))
+ Opt.strLanguage=strLangName;
+
+ if (!LangFile)
+ {
+ LastError = LERROR_FILE_NOT_FOUND;
+ return false;
+ }
+
+ wchar_t ReadStr[1024]={0};
+
+ while (ReadString(LangFile, ReadStr, ARRAYSIZE(ReadStr), nCodePage) )
+ {
+ FARString strDestStr;
+ RemoveExternalSpaces(ReadStr);
+
+ if (*ReadStr != L'\"')
+ continue;
+
+ int SrcLength=StrLength(ReadStr);
+
+ if (ReadStr[SrcLength-1]==L'\"')
+ ReadStr[SrcLength-1]=0;
+
+ ConvertString(ReadStr+1,strDestStr);
+ int DestLength=(int)pack(strDestStr.GetLength()+1);
+
+ if (m_bUnicode)
+ {
+ if (!(MsgList = (wchar_t*)realloc(MsgList, (MsgSize+DestLength)*sizeof(wchar_t))))
+ {
+ fclose(LangFile);
+ return false;
+ }
+
+ *(int*)&MsgList[MsgSize+DestLength-_PACK] = 0;
+ wcscpy(MsgList+MsgSize, strDestStr);
+ }
+ else
+ {
+ DestLength = pack(WINPORT(WideCharToMultiByte)(CP_UTF8, 0, strDestStr, -1, nullptr, 0, nullptr, nullptr));
+ if (!(MsgListA = (char*)realloc(MsgListA, (MsgSize+DestLength)*sizeof(char))))
+ {
+ fclose(LangFile);
+ return false;
+ }
+
+ *(int*)&MsgListA[MsgSize+DestLength-_PACK] = 0;
+ WINPORT(WideCharToMultiByte)(CP_UTF8, 0, strDestStr, -1, MsgListA+MsgSize, DestLength, nullptr, nullptr);
+ }
+
+ MsgSize+=DestLength;
+ MsgCount++;
+ }
+
+ // Проведем проверку на количество строк в LNG-файлах
+ if (CountNeed != -1 && CountNeed != MsgCount-1)
+ {
+ fclose(LangFile);
+ LastError = LERROR_BAD_FILE;
+ return false;
+ }
+
+ if (m_bUnicode)
+ {
+ wchar_t *CurAddr = MsgList;
+ MsgAddr = new(std::nothrow) wchar_t*[MsgCount];
+
+ if (!MsgAddr)
+ {
+ fclose(LangFile);
+ return false;
+ }
+
+ for (int I=0; I<MsgCount; I++)
+ {
+ MsgAddr[I]=CurAddr;
+ CurAddr+=pack(StrLength(CurAddr)+1);
+ }
+ }
+ else
+ {
+ char *CurAddrA = MsgListA;
+ MsgAddrA = new(std::nothrow) char*[MsgCount];
+
+ if (!MsgAddrA)
+ {
+ delete[] MsgAddr;
+ MsgAddr=nullptr;
+ fclose(LangFile);
+ return false;
+ }
+
+ for (int I=0; I<MsgCount; I++)
+ {
+ MsgAddrA[I]=CurAddrA;
+ CurAddrA+=pack(strlen(CurAddrA)+1);
+ }
+ }
+
+ fclose(LangFile);
+
+ if (this == &Lang)
+ OldLang.Free();
+
+ LanguageLoaded=true;
+ return true;
+}
+
+Language::~Language()
+{
+ Free();
+}
+
+void Language::Free()
+{
+ if (MsgList) free(MsgList);
+
+ if (MsgListA)free(MsgListA);
+
+ MsgList=nullptr;
+ MsgListA=nullptr;
+
+ if (MsgAddr) delete[] MsgAddr;
+
+ MsgAddr=nullptr;
+
+ if (MsgAddrA) delete[] MsgAddrA;
+
+ MsgAddrA=nullptr;
+ MsgCount=0;
+ MsgSize=0;
+ m_bUnicode = true;
+}
+
+void Language::Close()
+{
+ if (this == &Lang)
+ {
+ if (OldLang.MsgCount)
+ OldLang.Free();
+
+ OldLang.MsgList=MsgList;
+ OldLang.MsgAddr=MsgAddr;
+ OldLang.MsgListA=MsgListA;
+ OldLang.MsgAddrA=MsgAddrA;
+ OldLang.MsgCount=MsgCount;
+ OldLang.MsgSize=MsgSize;
+ OldLang.m_bUnicode=m_bUnicode;
+ }
+
+ MsgList=nullptr;
+ MsgAddr=nullptr;
+ MsgListA=nullptr;
+ MsgAddrA=nullptr;
+ MsgCount=0;
+ MsgSize=0;
+ m_bUnicode = true;
+ LanguageLoaded=false;
+}
+
+
+void Language::ConvertString(const wchar_t *Src,FARString &strDest)
+{
+ wchar_t *Dest = strDest.GetBuffer(wcslen(Src)*2);
+
+ while (*Src)
+ switch (*Src)
+ {
+ case L'\\':
+
+ switch (Src[1])
+ {
+ case L'\\':
+ *(Dest++)=L'\\';
+ Src+=2;
+ break;
+ case L'\"':
+ *(Dest++)=L'\"';
+ Src+=2;
+ break;
+ case L'n':
+ *(Dest++)=L'\n';
+ Src+=2;
+ break;
+ case L'r':
+ *(Dest++)=L'\r';
+ Src+=2;
+ break;
+ case L'b':
+ *(Dest++)=L'\b';
+ Src+=2;
+ break;
+ case L't':
+ *(Dest++)=L'\t';
+ Src+=2;
+ break;
+ default:
+ *(Dest++)=L'\\';
+ Src++;
+ break;
+ }
+
+ break;
+ case L'"':
+ *(Dest++)=L'"';
+ Src+=(Src[1]==L'"') ? 2:1;
+ break;
+ default:
+ *(Dest++)=*(Src++);
+ break;
+ }
+
+ *Dest=0;
+ strDest.ReleaseBuffer();
+}
+
+bool Language::CheckMsgId(int MsgId) const
+{
+ /* $ 19.03.2002 DJ
+ при отрицательном индексе - также покажем сообщение об ошибке
+ (все лучше, чем трапаться)
+ */
+ if (MsgId>=MsgCount || MsgId < 0)
+ {
+ if (this == &Lang && !LanguageLoaded && this != &OldLang && OldLang.CheckMsgId(MsgId))
+ return true;
+
+ /* $ 26.03.2002 DJ
+ если менеджер уже в дауне - сообщение не выводим
+ */
+ if (!FrameManager->ManagerIsDown())
+ {
+ /* $ 03.09.2000 IS
+ ! Нормальное сообщение об отсутствии строки в языковом файле
+ (раньше имя файла обрезалось справа и приходилось иногда гадать - в
+ каком же файле ошибка)
+ */
+ FARString strMsg1(L"Incorrect or damaged ");
+ strMsg1+=strMessageFile;
+ /* IS $ */
+ FormatString strMsgNotFound;
+ strMsgNotFound<<L"Message "<<MsgId<<L" not found";
+ if (Message(MSG_WARNING,2,L"Error",strMsg1,strMsgNotFound,L"Ok",L"Quit")==1)
+ exit(0);
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+const wchar_t* Language::GetMsg(int nID) const
+{
+ if (!m_bUnicode || !CheckMsgId(nID))
+ return L"";
+
+ if (this == &Lang && this != &OldLang && !LanguageLoaded && OldLang.MsgCount > 0)
+ return OldLang.MsgAddr[nID];
+
+ return MsgAddr[nID];
+}
+
+const char* Language::GetMsgA(int nID) const
+{
+ if (m_bUnicode || !CheckMsgId(nID))
+ return "";
+
+ if (this == &Lang && this != &OldLang && !LanguageLoaded && OldLang.MsgCount > 0)
+ return OldLang.MsgAddrA[nID];
+
+ return MsgAddrA[nID];
+}
+
diff --git a/far2l/src/cfg/language.hpp b/far2l/src/cfg/language.hpp
new file mode 100644
index 00000000..abf99994
--- /dev/null
+++ b/far2l/src/cfg/language.hpp
@@ -0,0 +1,84 @@
+#pragma once
+
+/*
+language.hpp
+
+Работа с LNG-файлами
+*/
+/*
+Copyright (c) 1996 Eugene Roshal
+Copyright (c) 2000 Far Group
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+enum LngErrors
+{
+ LERROR_SUCCESS,
+ LERROR_FILE_NOT_FOUND,
+ LERROR_BAD_FILE,
+};
+
+class Language
+{
+public:
+ Language();
+ ~Language();
+
+ bool Init(const wchar_t *Path, bool bUnicode, int CountNeed=-1);
+ void Close();
+
+ const wchar_t* GetMsg(int nID) const;
+ const char* GetMsgA(int nID) const;
+
+ bool IsLanguageLoaded() const {return LanguageLoaded;}
+ LngErrors GetLastError() const {return LastError;}
+
+private:
+ LngErrors LastError;
+ bool LanguageLoaded;
+ wchar_t **MsgAddr;
+ wchar_t *MsgList;
+ char **MsgAddrA; //фантастика, да
+ char *MsgListA;
+ long MsgSize;
+ int MsgCount;
+ FARString strMessageFile;
+ bool m_bUnicode;
+
+ void ConvertString(const wchar_t *Src,FARString &strDest);
+ bool CheckMsgId(int MsgId) const;
+ void Free();
+};
+
+extern Language Lang;
+
+#define MSG(ID) ::Lang.GetMsg(ID)
+
+class VMenu;
+
+FILE* OpenLangFile(FARString strPath,const wchar_t *Mask,const wchar_t *Language, FARString &strFileName, UINT &nCodePage, BOOL StrongLang=FALSE,FARString *pstrLangName=nullptr);
+int GetLangParam(FILE *SrcFile,const wchar_t *ParamName,FARString *strParam1, FARString *strParam2, UINT nCodePage);
+int GetOptionsParam(FILE *SrcFile,const wchar_t *KeyName,FARString &strValue, UINT nCodePage);
+int Select(int HelpLanguage,VMenu **MenuPtr);