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/base
parenta14dc1a81c797928d4f1b7d6a6b46ecc63f98308 (diff)
split /aux to /mix and /base
Diffstat (limited to 'far2l/src/base')
-rw-r--r--far2l/src/base/CriticalSections.hpp69
-rw-r--r--far2l/src/base/DList.cpp121
-rw-r--r--far2l/src/base/DList.hpp125
-rw-r--r--far2l/src/base/FARString.cpp550
-rw-r--r--far2l/src/base/FARString.hpp241
-rw-r--r--far2l/src/base/array.hpp473
-rw-r--r--far2l/src/base/bitflags.hpp62
-rw-r--r--far2l/src/base/farqueue.cpp157
-rw-r--r--far2l/src/base/farqueue.hpp66
-rw-r--r--far2l/src/base/farrtl.cpp69
-rw-r--r--far2l/src/base/farrtl.hpp18
-rw-r--r--far2l/src/base/noncopyable.hpp52
12 files changed, 2003 insertions, 0 deletions
diff --git a/far2l/src/base/CriticalSections.hpp b/far2l/src/base/CriticalSections.hpp
new file mode 100644
index 00000000..db2bfcaf
--- /dev/null
+++ b/far2l/src/base/CriticalSections.hpp
@@ -0,0 +1,69 @@
+#pragma once
+
+/*
+CriticalSections.hpp
+
+Критические секции
+*/
+/*
+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 "noncopyable.hpp"
+#include <mutex>
+#include <memory>
+
+class CriticalSection
+{
+ private:
+ std::shared_ptr<std::recursive_mutex> _mutex;
+
+public:
+ CriticalSection() : _mutex(std::make_shared<std::recursive_mutex>())
+ {
+ }
+
+ public:
+#if 1
+ void Enter() { _mutex->lock(); }
+ void Leave() { _mutex->unlock(); }
+#else
+ void Enter() { if (!_mutex->try_lock()) { fprintf(stderr, "CriticalSection:%p - locking by %p\n", this, pthread_self()); _mutex->lock(); } fprintf(stderr, "CriticalSection:%p - locked by %p\n", this, pthread_self()); }
+ void Leave() { fprintf(stderr, "CriticalSection:%p - unlocked by %p\n", this, pthread_self()); _mutex->unlock(); }
+#endif
+};
+
+class CriticalSectionLock:public NonCopyable
+{
+ private:
+ CriticalSection &_object;
+
+ public:
+ CriticalSectionLock(CriticalSection &object): _object(object) { _object.Enter(); }
+ ~CriticalSectionLock() { _object.Leave(); }
+};
+
diff --git a/far2l/src/base/DList.cpp b/far2l/src/base/DList.cpp
new file mode 100644
index 00000000..f037523b
--- /dev/null
+++ b/far2l/src/base/DList.cpp
@@ -0,0 +1,121 @@
+/*
+DList.cpp
+
+двусвязный список
+*/
+/*
+Copyright (c) 2009 lort
+Copyright (c) 2009 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 "DList.hpp"
+
+CDList::CDList():
+ count(0)
+{
+ root.next=&root;
+ root.prev=&root;
+}
+
+void CDList::Clear()
+{
+ Node *f=root.next;
+
+ while (f!=&root)
+ {
+ Node *f1=f;
+ f=f->next;
+ DeleteNode(f1);
+ }
+
+ count=0;
+ root.next=&root;
+ root.prev=&root;
+}
+void CDList::CSwap(CDList &l)
+{
+ Node *pr=root.prev;
+ root.next->prev=&l.root;
+ pr->next=&l.root;
+ pr=l.root.prev;
+ l.root.next->prev=&root;
+ pr->next=&root;
+ size_t tcount=count;
+ Node troot=root;
+ count=l.count;
+ root=l.root;
+ l.count=tcount;
+ l.root=troot;
+}
+void *CDList::CInsertBefore(void *b, void *item)
+{
+ Node *Before=b ? (Node*)((BYTE*)b-sizeof(Node)) : &root;
+ Node *node=AllocNode(item);
+ node->prev=Before->prev;
+ node->next=Before;
+ Before->prev->next=node;
+ Before->prev=node;
+ ++count;
+ return ((BYTE*)node)+sizeof(Node);
+}
+void *CDList::CInsertAfter(void *a, void *item)
+{
+ Node *After=a ? (Node*)((BYTE*)a-sizeof(Node)) : &root;
+ return CInsertBefore((BYTE*)After->next+sizeof(Node), item);
+}
+void CDList::CMoveBefore(void *b, void *item)
+{
+ if (!item) return;
+ if (item == b) return;
+ Node *Before=b ? (Node*)((BYTE*)b-sizeof(Node)) : &root;
+ Node *node=(Node*)((BYTE*)item-sizeof(Node));
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+ node->prev=Before->prev;
+ node->next=Before;
+ Before->prev->next=node;
+ Before->prev=node;
+}
+void CDList::CMoveAfter(void *a, void *item)
+{
+ if (item == a) return;
+ Node *After=a ? (Node*)((BYTE*)a-sizeof(Node)) : &root;
+ CMoveBefore((BYTE*)After->next+sizeof(Node), item);
+}
+void *CDList::CDelete(void *item)
+{
+ Node *node=(Node*)((BYTE*)item-sizeof(Node));
+ Node *pr=node->prev;
+ Node *nx=node->next;
+ pr->next=nx;
+ nx->prev=pr;
+ --count;
+ DeleteNode(node);
+ return pr==&root ? nullptr : ((BYTE*)pr)+sizeof(Node);
+}
diff --git a/far2l/src/base/DList.hpp b/far2l/src/base/DList.hpp
new file mode 100644
index 00000000..9e65ff87
--- /dev/null
+++ b/far2l/src/base/DList.hpp
@@ -0,0 +1,125 @@
+#pragma once
+
+/*
+DList.hpp
+Шаблон работы с двусвязным списком.
+Type должен иметь конструктор по умолчанию, если используются методы
+Push, Unshift, InsertBefore или InsertAfter с item должен так же
+существовать оператор копирования:
+ const Type& operator=(const Type &)
+*/
+/*
+Copyright (c) 2009 lort
+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 <WinCompat.h>
+
+class CDList
+{
+ size_t count;
+ protected:
+ struct Node
+ {
+ Node *next;
+ Node *prev;
+ };
+ CDList();
+ void *CInsertBefore(void *b, void *item);
+ void *CInsertAfter(void *a, void *item);
+ void CMoveBefore(void *b, void *item);
+ void CMoveAfter(void *a, void *item);
+ void *CDelete(void *item);
+ void CSwap(CDList &l);
+ Node root;
+
+ virtual Node *AllocNode(void *key)=0;
+ virtual void DeleteNode(Node *node)=0;
+
+ public:
+ void Clear();
+ size_t Count()const {return count;};
+ bool Empty()const {return !count;};
+};
+
+template <typename Type>
+class DList : public CDList
+{
+ struct TNode : Node
+ {
+ Type type;
+ TNode(Type *t) {if (t) type=*t;}
+ };
+ Node *AllocNode(void *key) {return new TNode((Type*)key);}
+ void DeleteNode(Node *node) {delete(TNode*)node;}
+
+ Type *Node2Type(Node *node) {return node!=&root ? (Type*)((BYTE*)node+sizeof(Node)) : nullptr;}
+ Node *Type2Node(const Type *item) {return item ? (Node*)((BYTE*)item-sizeof(Node)) : &root;}
+
+ public:
+ ~DList() {Clear();};
+
+ //создать новый элемент и поместить его в конец списка
+ //возвращает указатель на созданный элемент
+ Type *Push(const Type *item=nullptr) {return (Type*)CInsertBefore(nullptr, (void*)item);}
+
+ //создать новый элемент и поместить его в начало списка
+ //возвращает указатель на созданный элемент
+ Type *Unshift(const Type *item=nullptr) {return (Type*)CInsertAfter(nullptr, (void*)item);}
+
+ //создать новый элемент и поместить его в списке перед before
+ //если before==nullptr элемент помещается в конец списка
+ //возвращает указатель на созданный элемент
+ Type *InsertBefore(const Type *before, const Type *item=nullptr) {return (Type*)CInsertBefore((void*)before, (void*)item);}
+
+ //создать новый элемент и поместить его в списке после after
+ //если after==nullptr элемент помещается в начало списка
+ //возвращает указатель на созданный элемент
+ Type *InsertAfter(const Type *after, const Type *item=nullptr) {return (Type*)CInsertAfter((void*)after, (void*)item);}
+
+ void MoveBefore(const Type *before, const Type *item) {CMoveBefore((void*)before, (void*)item);}
+ void MoveAfter(const Type *after, const Type *item) {CMoveAfter((void*)after, (void*)item);}
+
+ //удалить элемент item из списка, возвращается указатель на предыдущий элемент,
+ //если удалялся первый элемент возвращается nullptr
+ Type *Delete(Type *item) {return (Type*)CDelete(item);}
+
+ //возвращает первый элемент списка или nullptr если список пустой
+ Type *First() {return Node2Type(root.next);}
+
+ //возвращает последний элемент списка или nullptr если список пустой
+ Type *Last() {return Node2Type(root.prev);}
+
+ //возвращает элемент следующий за item или nullptr если item последний элемент.
+ //Next(nullptr) возвращает первый элемент
+ Type *Next(const Type *item) {return Node2Type(Type2Node(item)->next);}
+
+ //возвращает элемент идущий в списке перед item или nullptr если item первый элемент.
+ //Prev(nullptr) возвращает последний элемент
+ Type *Prev(const Type *item) {return Node2Type(Type2Node(item)->prev);}
+
+ //меняет местами содержимое списков
+ void Swap(DList<Type> &l) {CSwap(l);}
+};
diff --git a/far2l/src/base/FARString.cpp b/far2l/src/base/FARString.cpp
new file mode 100644
index 00000000..b1a55411
--- /dev/null
+++ b/far2l/src/base/FARString.cpp
@@ -0,0 +1,550 @@
+/*
+FARString.hpp
+
+Unicode строки
+*/
+/*
+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 <StackHeapArray.hpp>
+#include <stdarg.h>
+#include <assert.h>
+#include <limits>
+
+/// change to 1 to enable stats & leaks detection (slow!)
+#if 0
+#include <mutex>
+#include <set>
+
+struct DbgStr
+{
+ std::mutex Mtx;
+ unsigned long long Addrefs = 0;
+ std::set<void *> Instances;
+};
+
+static DbgStr &DBGSTR()
+{
+ static DbgStr s_out;
+ return s_out;
+}
+
+void __attribute__((noinline)) dbgStrCreated(void *c, unsigned int Capacity)
+{
+ std::lock_guard<std::mutex> lock(DBGSTR().Mtx);
+ if (!DBGSTR().Instances.insert(c).second) abort();
+// fprintf(stderr, "dbgStrCreated: Instances=%lu Addrefs=%llu [%u]\n",
+// (unsigned long)DBGSTR().Instances.size(), DBGSTR().Addrefs, Capacity);
+}
+
+void __attribute__((noinline)) dbgStrDestroyed(void *c, unsigned int Capacity)
+{
+ std::lock_guard<std::mutex> lock(DBGSTR().Mtx);
+ if (!DBGSTR().Instances.erase(c)) abort();
+// fprintf(stderr, "dbgStrDestroyed: Instances=%lu Addrefs=%llu [%u]\n",
+// (unsigned long)DBGSTR().Instances.size(), DBGSTR().Addrefs, Capacity);
+}
+
+void __attribute__((noinline)) dbgStrAddref(const wchar_t *Data)
+{
+ std::lock_guard<std::mutex> lock(DBGSTR().Mtx);
+ ++DBGSTR().Addrefs;
+// fprintf(stderr, "dbgStrAddref: Instances=%lu Addrefs=%llu '%ls'\n",
+// (unsigned long)DBGSTR().Instances.size(), DBGSTR().Addrefs, Data);
+}
+
+static std::set<void *> s_PrevStrings;
+
+void FARString::ScanForLeaks()
+{
+ std::lock_guard<std::mutex> lock(DBGSTR().Mtx);
+ const auto &strs = DBGSTR().Instances;
+ fprintf(stderr, "========= %s: Count=%lu Addrefs=%llu\n",
+ __FUNCTION__, (unsigned long)strs.size(), DBGSTR().Addrefs);
+
+// fprintf(stderr, "dbgStrAddref: Instances=%lu Addrefs=%llu '%ls'\n",
+// (unsigned long)DBGSTR().Instances.size(), DBGSTR().Addrefs, Data);
+
+ if (!s_PrevStrings.empty())
+ {
+ for (const auto &p : strs) if (s_PrevStrings.find(p) == s_PrevStrings.end())
+ {
+ FARString::Content *c = (FARString::Content *)p;
+ fprintf(stderr, " + refs=%u cap=%u len=%u data='%ls'\n",
+ c->GetRefs(), (unsigned int)c->GetCapacity(), (unsigned int)c->GetLength(), c->GetData());
+ }
+ }
+
+ s_PrevStrings = strs;
+}
+
+#else
+# define dbgStrCreated(c, Capacity)
+# define dbgStrDestroyed(c, Capacity)
+# define dbgStrAddref(Data)
+void FARString::ScanForLeaks() { }
+#endif
+
+FARString::Content FARString::Content::sEmptyData{}; // all fields zero inited by loader
+
+FARString::Content *FARString::Content::Create(size_t nCapacity)
+{
+ if (UNLIKELY(!nCapacity))
+ return EmptySingleton();
+
+ Content *out = (Content *)malloc(sizeof(Content) + sizeof(wchar_t) * nCapacity);
+ //Так как ни где выше в коде мы не готовы на случай что памяти не хватит
+ //то уж лучше и здесь не проверять, а сразу падать
+ out->m_nRefCount = 1;
+ out->m_nCapacity = (unsigned int)std::min(nCapacity, (size_t)std::numeric_limits<unsigned int>::max());
+ out->m_nLength = 0;
+ out->m_Data[0] = 0;
+
+ dbgStrCreated(out, out->m_nCapacity);
+ return out;
+}
+
+FARString::Content *FARString::Content::Create(size_t nCapacity, const wchar_t *SrcData, size_t SrcLen)
+{
+ Content *out = Content::Create(nCapacity);
+ out->m_nLength = (unsigned int)std::min(std::min(nCapacity, SrcLen), (size_t)std::numeric_limits<unsigned int>::max());
+ wmemcpy(out->m_Data, SrcData, out->m_nLength);
+ out->m_Data[out->m_nLength] = 0;
+ return out;
+}
+
+void __attribute__((noinline)) FARString::Content::Destroy(Content *c)
+{
+ dbgStrDestroyed(c, c->m_nCapacity);
+
+ if (LIKELY(c != EmptySingleton()))
+ free(c);
+ else
+ abort();
+}
+
+void FARString::Content::AddRef()
+{
+ if (LIKELY(m_nCapacity)) // only empty singletone has zero capacity
+ {
+ dbgStrAddref(m_Data);
+ __atomic_add_fetch(&m_nRefCount, 1, __ATOMIC_RELAXED);
+ }
+}
+
+void FARString::Content::DecRef()
+{
+ // __atomic_load_n(relaxed) usually doesn't use any HW interlocking
+ // thus its a fast path for empty or single-owner strings
+ unsigned int n = __atomic_load_n(&m_nRefCount, __ATOMIC_RELAXED);
+ if (LIKELY(n == 0))
+ { // (only) empty singletone has always-zero m_nRefCount
+ return;
+ }
+
+ if (LIKELY(n != 1))
+ {
+ if (LIKELY(__atomic_sub_fetch(&m_nRefCount, 1, __ATOMIC_RELEASE) != 0))
+ return;
+ }
+
+ Destroy(this);
+}
+
+void FARString::Content::SetLength(size_t nLength)
+{
+ m_nLength = std::min(nLength, (size_t)m_nCapacity);
+ m_Data[m_nLength] = 0;
+}
+
+//////////////////////////
+
+void FARString::PrepareForModify(size_t nCapacity)
+{
+ if (m_pContent->GetRefs() != 1 || nCapacity > m_pContent->GetCapacity())
+ {
+ size_t NewCapacity = nCapacity;
+ if (m_pContent->GetCapacity() > 0 && NewCapacity > m_pContent->GetCapacity())
+ NewCapacity+= std::max(NewCapacity - m_pContent->GetCapacity(), (size_t)16);
+
+ Content *pNewData =
+ Content::Create(NewCapacity, m_pContent->GetData(), m_pContent->GetLength());
+ pNewData->SetLength(m_pContent->GetLength());
+ m_pContent->DecRef();
+ m_pContent = pNewData;
+ }
+}
+
+void FARString::PrepareForModify()
+{
+ // invoke PrepareForModify with current length but not capacity intentially
+ // so in case of single owner this will not alter things but in case of
+ // not single owner then new copy will be alloced with capacity == length
+ PrepareForModify(m_pContent->GetLength());
+}
+
+size_t FARString::GetCharString(char *lpszStr, size_t nSize, UINT CodePage) const
+{
+ if (!lpszStr || !nSize)
+ return 0;
+
+ int SrcLen;
+ for (SrcLen = (int)m_pContent->GetLength(); SrcLen; --SrcLen)
+ {
+ int DstLen = WINPORT(WideCharToMultiByte)(CodePage, 0,
+ m_pContent->GetData(), SrcLen, nullptr, 0, nullptr, nullptr);
+ if (DstLen < (int)nSize)
+ {
+ DstLen = WINPORT(WideCharToMultiByte)(CodePage, 0,
+ m_pContent->GetData(), SrcLen, lpszStr, (int)nSize, nullptr, nullptr);
+ if (DstLen >= 0 && DstLen < (int)nSize)
+ {
+ lpszStr[DstLen] = 0;
+ return DstLen + 1;
+ }
+ }
+ }
+
+ *lpszStr = 0;
+ return 1;
+}
+
+FARString& FARString::Replace(size_t Pos, size_t Len, const wchar_t* Data, size_t DataLen)
+{
+ // Pos & Len must be valid
+ assert(Pos <= m_pContent->GetLength());
+ assert(Len <= m_pContent->GetLength());
+ assert(Pos + Len <= m_pContent->GetLength());
+
+ // Data and *this must not intersect (but Data can be located entirely within *this)
+ const bool DataStartsInside = (Data >= CPtr() && Data < CEnd());
+ const bool DataEndsInside = (Data + DataLen > CPtr() && Data + DataLen <= CEnd());
+ assert(DataStartsInside == DataEndsInside);
+
+ if (!Len && !DataLen)
+ return *this;
+
+ const size_t NewLength = m_pContent->GetLength() + DataLen - Len;
+ if (!DataStartsInside && m_pContent->GetRefs() == 1 && NewLength <= m_pContent->GetCapacity())
+ {
+ wmemmove(m_pContent->GetData() + Pos + DataLen,
+ m_pContent->GetData() + Pos + Len, m_pContent->GetLength() - Pos - Len);
+ wmemcpy(m_pContent->GetData() + Pos, Data, DataLen);
+ }
+ else
+ {
+ Content *NewData = Content::Create(NewLength);
+ wmemcpy(NewData->GetData(), m_pContent->GetData(), Pos);
+ wmemcpy(NewData->GetData() + Pos, Data, DataLen);
+ wmemcpy(NewData->GetData() + Pos + DataLen, m_pContent->GetData() + Pos + Len, m_pContent->GetLength() - Pos - Len);
+ m_pContent->DecRef();
+ m_pContent = NewData;
+ }
+
+ m_pContent->SetLength(NewLength);
+
+ return *this;
+}
+
+FARString& FARString::Append(const char *lpszAdd, UINT CodePage)
+{
+ if (lpszAdd && *lpszAdd)
+ {
+ int nAddSize = WINPORT(MultiByteToWideChar)(CodePage,0,lpszAdd,-1,nullptr,0);
+ if (nAddSize > 0) {
+ size_t nNewLength = m_pContent->GetLength() + nAddSize - 1; // minus NUL char that implicitely there
+ PrepareForModify(nNewLength);
+ WINPORT(MultiByteToWideChar)(CodePage, 0, lpszAdd, -1, m_pContent->GetData() + m_pContent->GetLength(), nAddSize);
+ m_pContent->SetLength(nNewLength);
+ }
+ }
+
+ return *this;
+}
+
+FARString& FARString::Copy(const FARString &Str)
+{
+ auto prev_pContent = m_pContent;
+ m_pContent = Str.m_pContent;
+ m_pContent->AddRef();
+ prev_pContent->DecRef();
+
+ return *this;
+}
+
+FARString& FARString::Copy(const char *lpszData, UINT CodePage)
+{
+ m_pContent->DecRef();
+
+ if (!lpszData || !*lpszData)
+ {
+ Init();
+ }
+ else
+ {
+ int nSize = WINPORT(MultiByteToWideChar)(CodePage,0,lpszData,-1,nullptr,0);
+ if (nSize > 0) {
+ m_pContent = Content::Create(nSize - 1);
+ WINPORT(MultiByteToWideChar)(CodePage, 0, lpszData, -1, m_pContent->GetData(), nSize);
+ m_pContent->SetLength(nSize - 1);
+
+ } else
+ Init();
+ }
+
+ return *this;
+}
+
+FARString FARString::SubStr(size_t Pos, size_t Len)
+{
+ if (Pos >= GetLength())
+ return FARString();
+ if (Len == static_cast<size_t>(-1) || Len > GetLength() || Pos + Len > GetLength())
+ Len = GetLength() - Pos;
+ return FARString(m_pContent->GetData() + Pos, Len);
+}
+
+bool FARString::Equal(size_t Pos, size_t Len, const wchar_t* Data, size_t DataLen) const
+{
+ if (Pos >= m_pContent->GetLength())
+ Len = 0;
+ else if (Len >= m_pContent->GetLength() || Pos + Len >= m_pContent->GetLength())
+ Len = m_pContent->GetLength() - Pos;
+
+ if (Len != DataLen)
+ return false;
+
+ return !wmemcmp(m_pContent->GetData() + Pos, Data, Len);
+}
+
+bool FARString::operator<(const FARString& Str) const
+{
+ return wmemcmp(CPtr(), Str.CPtr(), std::min(GetLength(), Str.GetLength()) + 1 ) < 0;
+}
+
+FARString operator+(const FARString &strSrc1, const FARString &strSrc2)
+{
+ FARString out = strSrc1.Clone();
+ out.Append(strSrc2);
+ return out;
+}
+
+FARString operator+(const FARString &strSrc1, const char *lpszSrc2)
+{
+ FARString out = strSrc1.Clone();
+ out.Append(lpszSrc2);
+ return out;
+}
+
+FARString operator+(const FARString &strSrc1, const wchar_t *lpwszSrc2)
+{
+ FARString out = strSrc1.Clone();
+ out.Append(lpwszSrc2);
+ return out;
+}
+
+wchar_t *FARString::GetBuffer(size_t nLength)
+{
+ if (nLength == (size_t)-1)
+ nLength = m_pContent->GetLength();
+
+ PrepareForModify(nLength);
+ return m_pContent->GetData();
+}
+
+void FARString::ReleaseBuffer(size_t nLength)
+{
+ if (nLength == (size_t)-1)
+ nLength = wcsnlen(m_pContent->GetData(), m_pContent->GetCapacity());
+ else if (nLength > m_pContent->GetCapacity())
+ nLength = m_pContent->GetCapacity();
+
+ PrepareForModify(nLength);
+ m_pContent->SetLength(nLength);
+}
+
+size_t FARString::Truncate(size_t nLength)
+{
+ if (nLength < m_pContent->GetLength())
+ {
+ if (!nLength)
+ {
+ m_pContent->DecRef();
+ Init();
+ }
+ else
+ {
+ PrepareForModify(nLength);
+ m_pContent->SetLength(nLength);
+ }
+ }
+
+ return m_pContent->GetLength();
+}
+
+FARString& FARString::Clear()
+{
+ Truncate(0);
+
+ return *this;
+}
+
+
+static void FARStringFmt(FARString &str, bool append, const wchar_t *format, va_list argptr)
+{
+ const size_t StartSize = 0x200; // 512 bytes ought to be enough for mosts
+ const size_t MaxSize = 0x1000000; // 16 megs ought to be enough for anybody
+ size_t Size;
+
+ for (Size = StartSize; Size <= MaxSize; Size<<= 1)
+ {
+ StackHeapArray<wchar_t, StartSize> buf(Size);
+ if (UNLIKELY(!buf.Get()))
+ break;
+
+ va_list argptr_copy;
+ va_copy(argptr_copy, argptr);
+ int retValue = vswprintf(buf.Get(), Size, format, argptr_copy);
+ va_end(argptr_copy);
+
+ if (retValue >= 0 && size_t(retValue) < Size)
+ {
+ if (append)
+ str.Append(buf.Get(), retValue);
+ else
+ str.Copy(buf.Get(), retValue);
+ return;
+ }
+ }
+
+ fprintf(stderr, "%s: failed; Size=%lu format='%ls'\n", __FUNCTION__, (unsigned long)Size, format);
+}
+
+FARString& FARString::Format(const wchar_t * format, ...)
+{
+ va_list argptr;
+ va_start(argptr, format);
+ FARStringFmt(*this, false, format, argptr);
+ va_end(argptr);
+ return *this;
+}
+
+FARString& FARString::AppendFormat(const wchar_t * format, ...)
+{
+ va_list argptr;
+ va_start(argptr, format);
+ FARStringFmt(*this, true, format, argptr);
+ va_end(argptr);
+ return *this;
+}
+
+FARString& FARString::Lower(size_t nStartPos, size_t nLength)
+{
+ PrepareForModify();
+ WINPORT(CharLowerBuff)(m_pContent->GetData() + nStartPos,
+ DWORD((nLength == (size_t)-1) ? m_pContent->GetLength() - nStartPos : nLength));
+ return *this;
+}
+
+FARString& FARString::Upper(size_t nStartPos, size_t nLength)
+{
+ PrepareForModify();
+ WINPORT(CharUpperBuff)(m_pContent->GetData() + nStartPos,
+ DWORD((nLength == (size_t)-1) ? m_pContent->GetLength() - nStartPos : nLength));
+ return *this;
+}
+
+bool FARString::Pos(size_t &nPos, wchar_t Ch, size_t nStartPos) const
+{
+ const wchar_t *lpwszData = m_pContent->GetData();
+ const wchar_t *lpFound = wcschr(lpwszData + nStartPos, Ch);
+
+ if (lpFound)
+ {
+ nPos = lpFound - lpwszData;
+ return true;
+ }
+
+ return false;
+}
+
+bool FARString::Pos(size_t &nPos, const wchar_t *lpwszFind, size_t nStartPos) const
+{
+ const wchar_t *lpwszData = m_pContent->GetData();
+ const wchar_t *lpFound = wcsstr(lpwszData + nStartPos, lpwszFind);
+
+ if (lpFound)
+ {
+ nPos = lpFound - lpwszData;
+ return true;
+ }
+
+ return false;
+}
+
+bool FARString::PosI(size_t &nPos, const wchar_t *lpwszFind, size_t nStartPos) const
+{
+ const wchar_t *lpwszData = m_pContent->GetData();
+ const wchar_t *lpFound = StrStrI(lpwszData + nStartPos, lpwszFind);
+
+ if (lpFound)
+ {
+ nPos = lpFound - lpwszData;
+ return true;
+ }
+
+ return false;
+}
+
+bool FARString::RPos(size_t &nPos, wchar_t Ch, size_t nStartPos) const
+{
+ const wchar_t *lpwszData = m_pContent->GetData();
+ const wchar_t *lpwszStrStart = lpwszData + nStartPos;
+ const wchar_t *lpwszStrScan = lpwszData + m_pContent->GetLength();
+
+ for (;;--lpwszStrScan)
+ {
+ if (*lpwszStrScan == Ch)
+ {
+ nPos = lpwszStrScan - lpwszData;
+ return true;
+ }
+
+ if (lpwszStrScan == lpwszStrStart)
+ return false;
+ }
+}
+
+std::string FARString::GetMB() const
+{
+ std::string out;
+ Wide2MB(CPtr(), GetLength(), out);
+ return out;
+}
diff --git a/far2l/src/base/FARString.hpp b/far2l/src/base/FARString.hpp
new file mode 100644
index 00000000..9585db03
--- /dev/null
+++ b/far2l/src/base/FARString.hpp
@@ -0,0 +1,241 @@
+#pragma once
+
+/*
+FARString.hpp
+
+Unicode строка
+*/
+/*
+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 <sys/types.h>
+#include <string.h>
+#include <WinCompat.h>
+#include "locale.hpp"
+#include "headers.hpp" // for NullToEmpty
+
+/***********************************************************************************************************
+ * This is a FARString - homegrew reference-counted string widely used in this project.
+ * This puts some restrictions on how this string may be used:
+ * - Don't write into const pointer returned by CPtr(), doing that may affect data used by irrelevant code.
+ * Use GetBuffer/ReleaseBuffer or simple plain assignment instead.
+ * - Don't modify single FARString instance from different threads without serialization.
+ * Create per-thread copies of FARString and modifying them from that threads is perfectly fine however.
+ * - Avoid excessive copying. While its doesn't copy string content, it performs still slow HW-interlocked
+ * reference counter manipulations, so better use passing-by-reference and std::move where possible.
+ */
+
+class FARString
+{
+ /* <Content> represents actual content of string that may be shared across different FARStrings
+ * and it must be trivial cuz there is sEmptyData singletone shared across all empty strings and
+ * thus it may be accessed during early static objects initialization; using Meyer's singletone
+ * implementaion for it would cause compiler to include local static strapping code that has some
+ * runtime overhead. Using trivial class makes possible just to create global static variable that
+ * will be resided in BSS and thus will have all fields zero-initialized by linker and ready to use
+ * just upon app loading without using initializing c-tor. This is also main reason why cannot use
+ * virtual methods, std::atomic<> instead of __atomic_* etc */
+
+ class Content
+ {
+ static Content sEmptyData; //для оптимизации создания пустых FARString
+
+ volatile unsigned int m_nRefCount;
+ unsigned int m_nCapacity; // not including final NULL char
+ unsigned int m_nLength; // not including final NULL char
+ wchar_t m_Data[1];
+
+ static void Destroy(Content *c);
+
+ public:
+ static inline Content *EmptySingleton() { return &sEmptyData; }
+
+ static Content *Create(size_t nCapacity);
+ static Content *Create(size_t nCapacity, const wchar_t *SrcData, size_t SrcLen);
+
+ void AddRef();
+ void DecRef();
+ unsigned int GetRefs() const { return __atomic_load_n(&m_nRefCount, __ATOMIC_RELAXED); }
+
+ void SetLength(size_t nLength);
+ inline wchar_t *GetData() { return m_Data; }
+ inline size_t GetCapacity() const { return m_nCapacity; }
+ inline size_t GetLength() const { return m_nLength; }
+
+ } *m_pContent;
+
+ inline void Init()
+ {
+ m_pContent = Content::EmptySingleton();
+ }
+
+ inline void Init(const wchar_t *SrcData, size_t SrcLen)
+ {
+ m_pContent = LIKELY(SrcLen)
+ ? Content::Create(SrcLen, SrcData, SrcLen)
+ : Content::EmptySingleton();
+ }
+
+ inline void Init(const wchar_t *SrcData)
+ {
+ if (LIKELY(SrcData))
+ Init(SrcData, wcslen(SrcData));
+ else
+ Init();
+ }
+
+ void PrepareForModify(size_t nCapacity);
+ void PrepareForModify();
+
+public:
+ static void ScanForLeaks();
+
+ inline FARString() { Init(); }
+
+ inline FARString(FARString &&strOriginal) : m_pContent(strOriginal.m_pContent) { strOriginal.Init(); }
+ inline FARString(const FARString &strCopy) : m_pContent(strCopy.m_pContent) { m_pContent->AddRef(); }
+ inline FARString(const wchar_t *lpwszData) { Init(lpwszData); }
+ inline FARString(const wchar_t *lpwszData, size_t nLength) { Init(lpwszData, nLength); }
+ inline FARString(const std::wstring &strData) { Init(strData.c_str(), strData.size()); }
+
+ inline FARString(const char *lpszData, UINT CodePage=CP_UTF8) { Init(); Copy(lpszData, CodePage); }
+ inline FARString(const std::string &strData, UINT CodePage=CP_UTF8) { Init(); Copy(strData.c_str(), CodePage); }
+
+ inline ~FARString() { /*if (m_pContent) он не должен быть nullptr*/ m_pContent->DecRef(); }
+
+ // Returns copy of *this string but that copy uses OWN, not shared with *this, content.
+ inline FARString Clone() const { return FARString(CPtr(), GetLength()); }
+
+ wchar_t *GetBuffer(size_t nLength = (size_t)-1);
+ void ReleaseBuffer(size_t nLength = (size_t)-1);
+
+ inline size_t GetLength() const { return m_pContent->GetLength(); }
+ size_t Truncate(size_t nLength);
+
+ inline wchar_t At(size_t nIndex) const { return m_pContent->GetData()[nIndex]; }
+
+ inline bool IsEmpty() const { return !(m_pContent->GetLength() && *m_pContent->GetData()); }
+
+ size_t GetCharString(char *lpszStr, size_t nSize, UINT CodePage=CP_UTF8) const;
+ std::string GetMB() const;
+ inline std::wstring GetWide() const { return std::wstring(CPtr(), GetLength()); }
+
+ FARString& Format(const wchar_t * format, ...);
+ FARString& AppendFormat(const wchar_t * format, ...);
+
+ FARString& Replace(size_t Pos, size_t Len, const wchar_t* Data, size_t DataLen);
+ FARString& Replace(size_t Pos, size_t Len, const FARString& Str) { return Replace(Pos, Len, Str.CPtr(), Str.GetLength()); }
+ FARString& Replace(size_t Pos, size_t Len, const wchar_t* Str) { return Replace(Pos, Len, Str, StrLength(NullToEmpty(Str))); }
+ FARString& Replace(size_t Pos, size_t Len, wchar_t Ch) { return Replace(Pos, Len, &Ch, 1); }
+
+ FARString& Append(const wchar_t* Str, size_t StrLen) { return Replace(GetLength(), 0, Str, StrLen); }
+ FARString& Append(const FARString& Str) { return Append(Str.CPtr(), Str.GetLength()); }
+ FARString& Append(const wchar_t* Str) { return Append(Str, StrLength(NullToEmpty(Str))); }
+ FARString& Append(wchar_t Ch) { return Append(&Ch, 1); }
+ FARString& Append(const char *lpszAdd, UINT CodePage=CP_UTF8);
+
+ FARString& Insert(size_t Pos, const wchar_t* Str, size_t StrLen) { return Replace(Pos, 0, Str, StrLen); }
+ FARString& Insert(size_t Pos, const FARString& Str) { return Insert(Pos, Str.CPtr(), Str.GetLength()); }
+ FARString& Insert(size_t Pos, const wchar_t* Str) { return Insert(Pos, Str, StrLength(NullToEmpty(Str))); }
+ FARString& Insert(size_t Pos, wchar_t Ch) { return Insert(Pos, &Ch, 1); }
+
+ FARString& Copy(const wchar_t *Str, size_t StrLen) { return Replace(0, GetLength(), Str, StrLen); }
+ FARString& Copy(const wchar_t *Str) { return Copy(Str, StrLength(NullToEmpty(Str))); }
+ FARString& Copy(wchar_t Ch) { return Copy(&Ch, 1); }
+ FARString& Copy(const FARString &Str);
+ FARString& Copy(const char *lpszData, UINT CodePage=CP_UTF8);
+
+ FARString& Remove(size_t Pos, size_t Len = 1) { return Replace(Pos, Len, nullptr, 0); }
+ FARString& LShift(size_t nShiftCount, size_t nStartPos=0) { return Remove(nStartPos, nShiftCount); }
+
+ FARString& Clear();
+
+ inline const wchar_t *CPtr() const { return m_pContent->GetData(); }
+ inline const wchar_t *CEnd() const { return m_pContent->GetData() + m_pContent->GetLength(); }
+ inline operator const wchar_t *() const { return m_pContent->GetData(); }
+
+ FARString SubStr(size_t Pos, size_t Len = -1);
+
+ inline FARString& operator=(FARString &&strOriginal) { std::swap(m_pContent, strOriginal.m_pContent); return *this; }
+ inline FARString& operator=(const FARString &strCopy) { return Copy(strCopy); }
+ inline FARString& operator=(const char *lpszData) { return Copy(lpszData); }
+ inline FARString& operator=(const wchar_t *lpwszData) { return Copy(lpwszData); }
+ inline FARString& operator=(wchar_t chData) { return Copy(chData); }
+ inline FARString& operator=(const std::string &strSrc) { return Copy(strSrc.c_str(), CP_UTF8); }
+ inline FARString& operator=(const std::wstring &strSrc) { return Copy(strSrc.c_str()); }
+
+ inline FARString& operator+=(const FARString &strAdd) { return Append(strAdd); }
+ inline FARString& operator+=(const char *lpszAdd) { return Append(lpszAdd); }
+ inline FARString& operator+=(const wchar_t *lpwszAdd) { return Append(lpwszAdd); }
+ inline FARString& operator+=(wchar_t chAdd) { return Append(chAdd); }
+
+ bool Equal(size_t Pos, size_t Len, const wchar_t* Data, size_t DataLen) const;
+ inline bool Equal(size_t Pos, const wchar_t* Str, size_t StrLen) const { return Equal(Pos, StrLen, Str, StrLen); }
+ inline bool Equal(size_t Pos, const wchar_t* Str) const { return Equal(Pos, StrLength(Str), Str, StrLength(Str)); }
+ inline bool Equal(size_t Pos, const FARString& Str) const { return Equal(Pos, Str.GetLength(), Str.CPtr(), Str.GetLength()); }
+ inline bool Equal(size_t Pos, wchar_t Ch) const { return Equal(Pos, 1, &Ch, 1); }
+ inline bool operator==(const FARString& Str) const { return Equal(0, GetLength(), Str.CPtr(), Str.GetLength()); }
+ inline bool operator==(const wchar_t* Str) const { return Equal(0, GetLength(), Str, StrLength(Str)); }
+ inline bool operator==(wchar_t Ch) const { return Equal(0, GetLength(), &Ch, 1); }
+
+ inline bool operator!=(const FARString& Str) const { return !Equal(0, GetLength(), Str.CPtr(), Str.GetLength()); }
+ inline bool operator!=(const wchar_t* Str) const { return !Equal(0, GetLength(), Str, StrLength(Str)); }
+ inline bool operator!=(wchar_t Ch) const { return !Equal(0, GetLength(), &Ch, 1); }
+
+ bool operator<(const FARString& Str) const;
+
+ FARString& Lower(size_t nStartPos=0, size_t nLength=(size_t)-1);
+ FARString& Upper(size_t nStartPos=0, size_t nLength=(size_t)-1);
+
+ bool Pos(size_t &nPos, wchar_t Ch, size_t nStartPos=0) const;
+ bool Pos(size_t &nPos, const wchar_t *lpwszFind, size_t nStartPos=0) const;
+ bool PosI(size_t &nPos, const wchar_t *lpwszFind, size_t nStartPos=0) const;
+ bool RPos(size_t &nPos, wchar_t Ch, size_t nStartPos=0) const;
+
+ bool Contains(wchar_t Ch, size_t nStartPos=0) const { return !wcschr(m_pContent->GetData()+nStartPos,Ch) ? false : true; }
+ bool Contains(const wchar_t *lpwszFind, size_t nStartPos=0) const { return !wcsstr(m_pContent->GetData()+nStartPos,lpwszFind) ? false : true; }
+
+ inline bool Begins(wchar_t Ch) const
+ { return m_pContent->GetLength() > 0 && *m_pContent->GetData() == Ch; }
+
+ inline bool Begins(const FARString &strFind) const
+ { return m_pContent->GetLength() >= strFind.m_pContent->GetLength() && wmemcmp(m_pContent->GetData(), strFind.m_pContent->GetData(), strFind.m_pContent->GetLength()) == 0; }
+
+ inline bool Begins(const wchar_t *lpwszFind) const
+ { return m_pContent->GetLength() > 0 && wcsncmp(m_pContent->GetData(), lpwszFind, wcslen(lpwszFind)) == 0; }
+
+ template <typename CharT>
+ bool ContainsAnyOf(const CharT *needles)
+ {
+ return FindAnyOfChars(CPtr(), CPtr() + GetLength(), needles) != nullptr;
+ }
+};
+
+FARString operator+(const FARString &strSrc1, const FARString &strSrc2);
+FARString operator+(const FARString &strSrc1, const char *lpszSrc2);
+FARString operator+(const FARString &strSrc1, const wchar_t *lpwszSrc2);
diff --git a/far2l/src/base/array.hpp b/far2l/src/base/array.hpp
new file mode 100644
index 00000000..c2317318
--- /dev/null
+++ b/far2l/src/base/array.hpp
@@ -0,0 +1,473 @@
+#pragma once
+
+/*
+array.hpp
+
+Шаблон работы с массивом
+
+ TArray<Object> Array;
+ // Object должен иметь конструктор по умолчанию и следующие операторы
+ // bool operator==(const Object &) const
+ // bool operator<(const Object &) const
+ // const Object& operator=(const Object &)
+
+ TPointerArray<Object> Array;
+ Object должен иметь конструктор по умолчанию.
+ Класс для тупой но прозрачной работы с массивом понтеров на класс Object
+*/
+/*
+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 <new> // for std::nothrow
+#include <WinCompat.h>
+#include "farrtl.hpp"
+
+#ifdef __GNUC__
+typedef int __cdecl(*TARRAYCMPFUNC)(const void *el1,const void *el2);
+#else
+typedef int (*TARRAYCMPFUNC)(const void *el1,const void *el2);
+#endif
+
+template <class Object>
+class TArray
+{
+ private:
+ size_t internalCount, Count, Delta;
+ Object **items;
+
+ private:
+ static int __cdecl CmpItems(const Object **el1, const Object **el2);
+ bool deleteItem(size_t index);
+
+ public:
+ TArray(size_t Delta=8);
+ TArray<Object>(const TArray<Object> &rhs);
+ ~TArray() { Free(); }
+
+ public:
+ TArray& operator=(const TArray<Object> &rhs);
+
+ public:
+ void Free();
+ void setDelta(size_t newDelta);
+ bool setSize(size_t newSize);
+
+ Object *setItem(size_t index, const Object &newItem);
+ Object *getItem(size_t index);
+ const Object *getConstItem(size_t index) const;
+ int getIndex(const Object &item, int start=-1);
+
+ // сортировка массива. Offset - сколько первых пунктов пропустить
+ void Sort(TARRAYCMPFUNC user_cmp_func=nullptr,size_t Offset=0);
+
+ // упаковать массив - вместо нескольких одинаковых элементов,
+ /*
+ идущих подряд, оставить только один. Возвращает, false,
+ если изменений массива не производилось.
+ Вызов Pack() после Sort(nullptr) приведет к устранению
+ дубликатов
+ */
+ bool Pack();
+
+ public: // inline
+ size_t getSize() const { return Count; }
+ Object *addItem(const Object &newItem) { return setItem(Count,newItem); }
+};
+
+template <class Object>
+TArray<Object>::TArray(size_t delta):
+ internalCount(0), Count(0), items(nullptr)
+{
+ setDelta(delta);
+}
+
+template <class Object>
+void TArray<Object>::Free()
+{
+ if (items)
+ {
+ for (unsigned i=0; i<Count; ++i)
+ delete items[i];
+
+ free(items);
+ items=nullptr;
+ }
+
+ Count=internalCount=0;
+}
+
+template <class Object>
+Object *TArray<Object>::setItem(size_t index, const Object &newItem)
+{
+ bool set=true;
+
+ if (index<Count)
+ deleteItem(index);
+ else
+ set=setSize(index+(index==Count));
+
+ if (set)
+ {
+ items[index]=new(std::nothrow) Object;
+
+ if (items[index])
+ *items[index]=newItem;
+
+ return items[index];
+ }
+
+ return nullptr;
+}
+
+template <class Object>
+Object *TArray<Object>::getItem(size_t index)
+{
+ return (index<Count)?items[index]:nullptr;
+}
+
+template <class Object>
+const Object *TArray<Object>::getConstItem(size_t index) const
+{
+ return (index<Count)?items[index]:nullptr;
+}
+
+template <class Object>
+void TArray<Object>::Sort(TARRAYCMPFUNC user_cmp_func,size_t Offset)
+{
+ if (Count)
+ {
+ if (!user_cmp_func)
+ user_cmp_func=reinterpret_cast<TARRAYCMPFUNC>(CmpItems);
+
+ far_qsort(reinterpret_cast<char*>(items+Offset),Count-Offset,sizeof(Object*),user_cmp_func);
+ }
+}
+
+template <class Object>
+bool TArray<Object>::Pack()
+{
+ bool was_changed=false;
+
+ for (size_t index=1; index<Count; ++index)
+ {
+ if (*items[index-1]==*items[index])
+ {
+ deleteItem(index);
+ was_changed=true;
+ --Count;
+
+ if (index<Count)
+ {
+ memmove(&items[index], &items[index+1], sizeof(Object*)*(Count-index));
+ --index;
+ }
+ }
+ }
+
+ return was_changed;
+}
+
+template <class Object>
+bool TArray<Object>::deleteItem(size_t index)
+{
+ if (index<Count)
+ {
+ delete items[index];
+ items[index]=nullptr;
+ return true;
+ }
+
+ return false;
+}
+
+template <class Object>
+bool TArray<Object>::setSize(size_t newSize)
+{
+ bool rc=false;
+
+ if (newSize < Count) // уменьшение размера
+ {
+ for (size_t i=newSize; i<Count; ++i)
+ {
+ delete items[i];
+ items[i]=nullptr;
+ }
+
+ Count=newSize;
+ rc=true;
+ }
+ else if (newSize < internalCount) // увеличение, но в рамках имеющегося
+ {
+ for (size_t i=Count; i<newSize; ++i)
+ items[i]=nullptr;
+
+ Count=newSize;
+ rc=true;
+ }
+ else // увеличение размера
+ {
+ size_t Remainder=newSize%Delta;
+ size_t newCount=Remainder?(newSize+Delta)-Remainder:
+ newSize?newSize:Delta;
+ Object **newItems=static_cast<Object**>(malloc(newCount*sizeof(Object*)));
+
+ if (newItems)
+ {
+ if (items)
+ {
+ memcpy(newItems,items,Count*sizeof(Object*));
+ free(items);
+ }
+
+ items=newItems;
+ internalCount=newCount;
+
+ for (size_t i=Count; i<newSize; ++i)
+ items[i]=nullptr;
+
+ Count=newSize;
+ rc=true;
+ }
+ }
+
+ return rc;
+}
+
+template <class Object>
+int __cdecl TArray<Object>::CmpItems(const Object **el1, const Object **el2)
+{
+ if (el1==el2)
+ return 0;
+ else if (**el1==**el2)
+ return 0;
+ else if (**el1<**el2)
+ return -1;
+ else
+ return 1;
+}
+
+template <class Object>
+TArray<Object>::TArray(const TArray<Object> &rhs):
+ items(nullptr), Count(0), internalCount(0)
+{
+ *this=rhs;
+}
+
+template <class Object>
+TArray<Object>& TArray<Object>::operator=(const TArray<Object> &rhs)
+{
+ if (this == &rhs)
+ return *this;
+
+ setDelta(rhs.Delta);
+
+ if (setSize(rhs.Count))
+ {
+ for (unsigned i=0; i<Count; ++i)
+ {
+ if (rhs.items[i])
+ {
+ if (!items[i])
+ items[i]=new Object;
+
+ if (items[i])
+ *items[i]=*rhs.items[i];
+ else
+ {
+ Free();
+ break;
+ }
+ }
+ else
+ {
+ delete items[i];
+ items[i]=nullptr;
+ }
+ }
+ }
+
+ return *this;
+}
+
+template <class Object>
+void TArray<Object>::setDelta(size_t newDelta)
+{
+ if (newDelta<4)
+ newDelta=4;
+
+ Delta=newDelta;
+}
+
+template <class Object>
+int TArray<Object>::getIndex(const Object &item, int start)
+{
+ int rc=-1;
+
+ if (start==-1)
+ start=0;
+
+ for (size_t i=start; i<Count; ++i)
+ {
+ if (items[i] && item==*items[i])
+ {
+ rc=i;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+template <class Object>
+class TPointerArray
+{
+ private:
+ size_t internalCount, Count, Delta;
+ Object **items;
+
+ private:
+ bool setSize(size_t newSize)
+ {
+ bool rc=false;
+
+ if (newSize < Count) // уменьшение размера
+ {
+ Count=newSize;
+ rc=true;
+ }
+ else if (newSize < internalCount) // увеличение, но в рамках имеющегося
+ {
+ for (size_t i=Count; i<newSize; i++)
+ items[i]=nullptr;
+
+ Count=newSize;
+ rc=true;
+ }
+ else // увеличение размера
+ {
+ size_t Remainder=newSize%Delta;
+ size_t newCount=Remainder?(newSize+Delta)-Remainder:(newSize?newSize:Delta);
+ Object **newItems=static_cast<Object**>(realloc(items,newCount*sizeof(Object*)));
+
+ if (newItems)
+ {
+ items=newItems;
+ internalCount=newCount;
+
+ for (size_t i=Count; i<newSize; i++)
+ items[i]=nullptr;
+
+ Count=newSize;
+ rc=true;
+ }
+ }
+
+ return rc;
+ }
+
+ public:
+ TPointerArray(size_t delta=1) { items=nullptr; Count=internalCount=0; setDelta(delta); }
+ ~TPointerArray() { Free(); }
+
+ void Free()
+ {
+ if (items)
+ {
+ for (size_t i=0; i<Count; ++i)
+ delete items[i];
+
+ free(items);
+ items=nullptr;
+ }
+
+ Count=internalCount=0;
+ }
+
+ void setDelta(size_t newDelta) { if (newDelta<1) newDelta=1; Delta=newDelta; }
+
+ Object *getItem(size_t index) { return (index<Count)?items[index]:nullptr; }
+
+ const Object *getConstItem(size_t index) const { return (index<Count)?items[index]:nullptr; }
+
+ Object *lastItem() { return Count?items[Count-1]:nullptr; }
+
+ Object *addItem() { return insertItem(Count); }
+
+ Object *insertItem(size_t index)
+ {
+ if (index>Count)
+ return nullptr;
+
+ Object *newItem = new(std::nothrow) Object;
+
+ if (newItem && setSize(Count+1))
+ {
+ for (size_t i=Count-1; i>index; i--)
+ items[i]=items[i-1];
+
+ items[index]= newItem;
+ return items[index];
+ }
+
+ if (newItem)
+ delete newItem;
+
+ return nullptr;
+ }
+
+ bool deleteItem(size_t index)
+ {
+ if (index<Count)
+ {
+ delete items[index];
+
+ for (size_t i=index+1; i<Count; i++)
+ items[i-1]=items[i];
+
+ setSize(Count-1);
+ return true;
+ }
+
+ return false;
+ }
+
+ bool swapItems(size_t index1, size_t index2)
+ {
+ if (index1<Count && index2<Count)
+ {
+ Object *temp = items[index1];
+ items[index1] = items[index2];
+ items[index2] = temp;
+ return true;
+ }
+
+ return false;
+ }
+
+ size_t getCount() const { return Count; }
+};
diff --git a/far2l/src/base/bitflags.hpp b/far2l/src/base/bitflags.hpp
new file mode 100644
index 00000000..1a99b757
--- /dev/null
+++ b/far2l/src/base/bitflags.hpp
@@ -0,0 +1,62 @@
+#pragma once
+
+/*
+bitflags.hpp
+
+Флаги
+*/
+/*
+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 <WinCompat.h>
+
+class BitFlags
+{
+ public:
+ DWORD Flags;
+
+ public:
+ BitFlags() {Flags=0;}
+ BitFlags(DWORD Fl) {Flags=Fl;}
+
+ ~BitFlags() {}
+
+ public:
+ // установить набор флагов
+ DWORD Set(DWORD NewFlags) { Flags|=NewFlags; return Flags;}
+ // сбросить набор флагов
+ DWORD Clear(DWORD NewFlags) { Flags&=~NewFlags; return Flags; }
+ // проверить набор флагов
+ BOOL Check(DWORD NewFlags) const { return Flags&NewFlags?TRUE:FALSE; }
+ // изменить состояние набора флагов в заивисмости от Status
+ DWORD Change(DWORD NewFlags,BOOL Status) { if (Status) Flags|=NewFlags; else Flags&=~NewFlags; return Flags;}
+ // инвертировать состояние флагов
+ DWORD Swap(DWORD SwapedFlags) { if (Flags&SwapedFlags) Flags&=~SwapedFlags; else Flags|=SwapedFlags; return Flags;}
+ //сбросить все флаги
+ void ClearAll() {Flags=0;}
+};
diff --git a/far2l/src/base/farqueue.cpp b/far2l/src/base/farqueue.cpp
new file mode 100644
index 00000000..32b28e9c
--- /dev/null
+++ b/far2l/src/base/farqueue.cpp
@@ -0,0 +1,157 @@
+/*
+farqueue.cpp
+
+Шаблон работы с очередью
+Использование:
+ FarQueue<int> *q;
+ q=new FarQueue<int>(10);
+
+ for( int j = 0; j < 5; j++ )
+ {
+ for( int i = 0; i < 5; i++ )
+ q->Put( i );
+
+ while( !q->isEmpty( ) )
+ cout << q->Get( ) << endl;
+ }
+*/
+/*
+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 "farqueue.hpp"
+
+template <class Object>
+FarQueue<Object>::FarQueue(int SizeQueue):
+ Array(nullptr)
+{
+ Init(SizeQueue);
+}
+
+template <class Object>
+FarQueue<Object>::~FarQueue()
+{
+ if (Array)
+ delete[] Array;
+}
+
+
+template <class Object>
+BOOL FarQueue<Object>::isEmpty() const
+{
+ return !CurrentSize;
+}
+
+template <class Object>
+BOOL FarQueue<Object>::isFull() const
+{
+ return CurrentSize == Size;
+}
+
+template <class Object>
+int FarQueue<Object>::Init(int SizeQueue)
+{
+ if (Array)
+ delete[] Array;
+
+ Array=new(std::nothrow) Object[Size=SizeQueue];
+
+ if (!Array)
+ Size=0;
+
+ CurrentSize=0;
+ Front=0;
+ Back=-1;
+ return Size ;
+}
+
+template <class Object>
+Object FarQueue<Object>::Peek() const
+{
+ if (isEmpty())
+ return 0;
+
+ return Array[Front];
+}
+
+template <class Object>
+Object FarQueue<Object>::Get()
+{
+ if (isEmpty())
+ return 0;
+
+ CurrentSize--;
+ Object FrontItem = Array[Front];
+ increment(Front);
+ return FrontItem;
+}
+
+template <class Object>
+int FarQueue<Object>::Put(const Object& x)
+{
+ if (isFull())
+ return FALSE;
+
+ increment(Back);
+ Array[Back] = x;
+ CurrentSize++;
+ return TRUE;
+}
+
+template <class Object>
+void FarQueue<Object>::increment(int& x)
+{
+ if (++x == Size)
+ x=0;
+}
+
+//#ifdef _MSC_VER
+template class FarQueue<DWORD>;
+//#endif
+
+#if 0
+#include <iostream.h>
+void main()
+{
+ FarQueue<int> *q;
+ q=new FarQueue<int>(1);
+
+ for (int j = 0; j < 5; j++)
+ {
+ for (int i = 0; i < 5; i++)
+ q->Put(i);
+
+ while (!q->isEmpty())
+ cout << q->Get() << endl;
+ }
+
+ delete q;
+}
+#endif
diff --git a/far2l/src/base/farqueue.hpp b/far2l/src/base/farqueue.hpp
new file mode 100644
index 00000000..6fb77ab6
--- /dev/null
+++ b/far2l/src/base/farqueue.hpp
@@ -0,0 +1,66 @@
+#pragma once
+
+/*
+farqueue.hpp
+
+Шаблон работы с очередью
+*/
+/*
+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 <WinCompat.h>
+
+template <class Object>
+class FarQueue
+{
+ private:
+ Object *Array;
+ int Size;
+ int CurrentSize;
+ int Front;
+ int Back;
+
+ private:
+ void increment(int& x);
+
+ public:
+ FarQueue(int SizeQueue=64);
+ ~FarQueue();
+
+ public:
+ int Init(int SizeQueue);
+
+ BOOL isEmpty() const;
+ BOOL isFull() const;
+
+ Object Peek() const;
+
+
+ Object Get();
+ int Put(const Object& x);
+};
diff --git a/far2l/src/base/farrtl.cpp b/far2l/src/base/farrtl.cpp
new file mode 100644
index 00000000..29a4845c
--- /dev/null
+++ b/far2l/src/base/farrtl.cpp
@@ -0,0 +1,69 @@
+/*
+farrtl.cpp
+
+Переопределение различных CRT функций
+*/
+
+#include "headers.hpp"
+
+// dest и src НЕ ДОЛЖНЫ пересекаться
+char * __cdecl far_strncpy(char * dest,const char * src,size_t DestSize)
+{
+ char *tmpsrc = dest;
+
+ while (DestSize>1 && (*dest++ = *src++))
+ {
+ DestSize--;
+ }
+
+ *dest = 0;
+ return tmpsrc;
+}
+
+wchar_t * __cdecl far_wcsncpy(wchar_t * dest,const wchar_t * src,size_t DestSize)
+{
+ wchar_t *tmpsrc = dest;
+
+ while (DestSize>1 && (*dest++ = *src++))
+ DestSize--;
+
+ *dest = 0;
+ return tmpsrc;
+}
+
+#if defined(__APPLE__) || defined(__FreeBSD__)
+struct QSortExAdapterArg
+{
+ int (*__cdecl comp)(const void *, const void *, void *);
+ void *ctx;
+};
+
+static int QSortExAdapter(void *a, const void *left, const void *right)
+{
+ struct QSortExAdapterArg *aa = (struct QSortExAdapterArg *)a;
+ return aa->comp(left, right, aa->ctx);
+}
+
+void __cdecl far_qsortex(void *base, size_t num, size_t width,
+ int (*__cdecl comp)(const void *, const void *, void *), void *ctx)
+{
+ struct QSortExAdapterArg aa = { comp, ctx };
+ qsort_r(base, num, width, &aa, QSortExAdapter);
+}
+
+#else
+
+void __cdecl far_qsortex(void *base, size_t num, size_t width,
+ int (*__cdecl comp)(const void *, const void *, void *), void *ctx)
+{
+ qsort_r(base, num, width, comp, ctx);
+}
+
+#endif
+
+void __cdecl far_qsort(void *base, size_t num, size_t width,
+ int (*__cdecl comp)(const void *, const void *)
+)
+{
+ qsort(base, num, width, comp);
+}
diff --git a/far2l/src/base/farrtl.hpp b/far2l/src/base/farrtl.hpp
new file mode 100644
index 00000000..0789d87c
--- /dev/null
+++ b/far2l/src/base/farrtl.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+/*
+farrtl.cpp
+
+Переопределение различных CRT функций
+*/
+
+#include <WinCompat.h>
+
+char * __cdecl far_strncpy(char * dest,const char * src,size_t DestSize);
+wchar_t * __cdecl far_wcsncpy(wchar_t * dest,const wchar_t * src,size_t DestSize);
+
+void __cdecl far_qsortex(void *base, size_t num, size_t width,
+ int (__cdecl *comp_fp)(const void *, const void *, void *), void *ctx);
+
+void __cdecl far_qsort(void *base, size_t num, size_t width,
+ int (__cdecl *comp)(const void *, const void *) );
diff --git a/far2l/src/base/noncopyable.hpp b/far2l/src/base/noncopyable.hpp
new file mode 100644
index 00000000..5d56d980
--- /dev/null
+++ b/far2l/src/base/noncopyable.hpp
@@ -0,0 +1,52 @@
+#pragma once
+
+/*
+noncopyable.hpp
+Класс для бысторого запрета оператора присваивания и конструктора копирования.
+
+Пример использования:
+
+#include "noncopyable.hpp"
+class YourClass : private NonCopyable
+{
+};
+
+*/
+/*
+Copyright (c) 2009 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.
+*/
+
+class NonCopyable
+{
+ private:
+ NonCopyable(const NonCopyable &);
+ NonCopyable & operator=(const NonCopyable &);
+
+ protected:
+ NonCopyable() {};
+ ~NonCopyable() {};
+
+};