ALib C++ Framework
by
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
ftree.cpp
1//##################################################################################################
2// ALib C++ Framework
3//
4// Copyright 2013-2025 A-Worx GmbH, Germany
5// Published under 'Boost Software License' (a free software license, see LICENSE.txt)
6//##################################################################################################
7#include "alib_precompile.hpp"
8#if !defined(ALIB_C20_MODULES) || ((ALIB_C20_MODULES != 0) && (ALIB_C20_MODULES != 1))
9# error "Configuration MACRO ALIB_C20_MODULES has to be given to the compiler as either 0 or 1"
10#endif
11#if ALIB_C20_MODULES
12 module;
13#endif
14//========================================= Global Fragment ========================================
17#if !defined ( _WIN32 )
18# include <pwd.h>
19# include <grp.h>
20#endif
21
22
23//============================================== Module ============================================
24#if ALIB_C20_MODULES
25 module ALib.Files;
26 import ALib.Lang;
27 import ALib.Characters.Functions;
28 import ALib.Strings;
29# if ALIB_ALOX
30 import ALib.ALox;
31 import ALib.ALox.Impl;
32# endif
33# if ALIB_EXPRESSIONS
34 import ALib.Expressions;
35# endif
36#if ALIB_DEBUG
37# include "ALib.Format.H"
38#endif
39#else
40# include "ALib.Lang.H"
42# include "ALib.Strings.H"
44# include "ALib.ALox.H"
45# include "ALib.ALox.Impl.H"
46# include "ALib.Expressions.H"
47#if ALIB_DEBUG
48# include "ALib.Format.H"
49#endif
50# include "ALib.Files.H"
51#endif
52//========================================== Implementation ========================================
53
54using namespace alib::system;
55namespace alib::files {
56
57//==================================================================================================
58//=== FTreeNodeHandler
59//==================================================================================================
60namespace detail {
61
64 const PathString& symLinkDest,
65 const PathString& symLinkRealPath ) {
67 || node->Type() == FInfo::Types::SYMBOLIC_LINK
68 || node->Type() == FInfo::Types::SYMBOLIC_LINK_DIR,
69 "FILES", "Given node is not a directory or symbolic link." )
70
72 == symLinkDest.IsEmpty(),
73 "FILES", "Error in symbolic link parameter" )
74
75
76 auto& v = *node;
77 bool isAllocated= v.GetExtendedInfo(); // this might happen with forced rescans
78
79 auto pool= node.Tree<FTree>().Pool();
81 switch (v.Type()) {
83 {
84 if( isAllocated )
85 *static_cast<FInfo::EIDirectory*>(v.GetExtendedInfo())= FInfo::EIDirectory();
86 else
87 v.SetExtendedInfo( pool.New<FInfo::EIDirectory>() );
88 }
89 return;
90
92 {
93 if( isAllocated )
94 *static_cast<FInfo::EISymLinkFile*>(v.GetExtendedInfo())= FInfo::EISymLinkFile();
95 else
96 v.SetExtendedInfo( pool.New<FInfo::EISymLinkFile>() );
97 v.SetLinkTarget( node.Tree<FTree>(), symLinkDest, symLinkRealPath);
98 }
99 return;
100
102 {
103 if( isAllocated )
104 *static_cast<FInfo::EISymLinkDir*>(v.GetExtendedInfo())= FInfo::EISymLinkDir();
105 else
106 v.SetExtendedInfo( pool.New<FInfo::EISymLinkDir>() );
107 v.SetLinkTarget( node.Tree<FTree>(), symLinkDest, symLinkRealPath);
108 }
109 return;
110
111 default:
112 return;
113 }
115}
116# include "ALib.Lang.CIMethods.H"
117
118} // namespace alib::files[::detail]
119
120//==================================================================================================
121//=== FTree
122//==================================================================================================
124: StringTree( allocator, DIRECTORY_SEPARATOR )
125, Pool ( allocator )
126, ogResolver( Pool )
127, listeners ( allocator ) {
129 numberFormat.FractionalPartWidth= 1;
130
131 DbgSetDCSName("FTree");
132
133 ALIB_DBG( if( alib::FILES.IsBootstrapped())
134 {
135 Log_SetDomain( "ALIB/FILES", Scope::Path)
136 Log_SetDomain( "FTREE" , Scope::Filename)
137 } )
138}
139
141 #if ALIB_DEBUG
142 for( auto& node : nodeTable )
143 if( node.data.custom ) {
144 Path path;
145 createCursor(node).AssemblePath(path);
146 ALIB_ERROR( "FILES",
147 "CustomData not deleted before destruction of class FTree.\n"
148 " First node found: {}.\n"
149 " Attached data type: {}" , path, node.data.dbgCustomType )
150 }
151 #endif
152
153 // we have to delete all nodes before the invocation of the base destructor, because
154 // this would use our pool allocator on existing nodes (which is then destructed already).
155 Clear();
156
157 // delete root value
158 auto* extendedInfo= Root()->GetExtendedInfo();
159 if( extendedInfo )
160 Pool().Delete( reinterpret_cast<FInfo::EIDirectory*>(extendedInfo) );
161
163}
164
166 lang::ContainerOp insertOrRemove,
168 const File* file,
169 const StringTree::Cursor* subTree,
170 const PathString& fileName,
171 const PathString& pathPrefix,
172 const PathString& pathSubstring ) {
173 // checks
174 ALIB_ASSERT_ERROR( file ==nullptr || &file->AsCursor().Tree() == this,"FILES","Given file does not belong to this FTree." )
175 ALIB_ASSERT_ERROR( subTree ==nullptr || subTree->IsValid() ,"FILES","Invalid cursor given." )
176 ALIB_ASSERT_ERROR( subTree ==nullptr || &subTree ->Tree() == this,"FILES","Given cursor does not belong to this FTree." )
177
178 //------------------------------------------ registration ----------------------------------------
179 if( insertOrRemove == lang::ContainerOp::Insert) {
180 listeners.emplace_back( ListenerRecord{ listener,
181 event,
182 (file ? file->AsCursor().Export() : ConstCursorHandle()),
183 (subTree ? subTree-> Export() : ConstCursorHandle()),
186 PathStringPA(Pool) } );
187 listeners.back().fileName << fileName;
188 listeners.back().pathPrefix << pathPrefix;
189 listeners.back().pathSubstring<< pathSubstring;
190
191 return;
192 }
193
194 //----------------------------------------------- de ---------------------------------------------
195 for (auto it= listeners.begin() ; it != listeners.end() ; ++it )
196 if( it->listener == listener
197 && it->event == event
198 && it->file == ( file ? file->AsCursor().Export() : ConstCursorHandle() )
199 && it->subTree == ( subTree ? subTree ->Export() : ConstCursorHandle() )
200 && it->fileName .Equals( fileName )
201 && it->pathPrefix .Equals( pathPrefix )
202 && it->pathSubstring.Equals( pathSubstring ) )
203 {
204 (void) listeners.erase( it );
205 return;
206 }
207
208 ALIB_WARNING("FILES", "Listener with matching set of parameters not found with deregistration.")
209
210} // FTree::registerListener
211
212
214 // checks
215 ALIB_ASSERT_ERROR( listener!=nullptr, "FILES", "Given listener is nullptr." )
216
217 //----------------------------------------------- de ---------------------------------------------
218 int cnt= 0;
219 for (auto it= listeners.begin() ; it != listeners.end() ; )
220 if( it->listener == listener ) {
221 Log_Verbose("Removing listener")
222 it= listeners.erase( it );
223 ++cnt;
224 }
225 else
226 ++it;
227
228 Log_If(cnt==0, Verbosity::Warning, "No listener found to be removed." )
229
230 return cnt;
231} // FTree::registerListener
232
234 const File& file,
235 const PathString& filePathGiven ) {
236 Path filePathBuffer;
237 const PathString* filePath= &filePathGiven;
238 for (auto it= listeners.begin() ; it != listeners.end() ; ++it )
239 if( event == it->event ) {
240 // if needed generate file path
241 if( filePath->IsEmpty()
242 && ( it->fileName .IsNotEmpty()
243 || it->pathPrefix .IsNotEmpty()
244 || it->pathSubstring.IsNotEmpty() ) )
245 {
246 (file.AsCursor().IsRoot() ? file.AsCursor()
247 : file.AsCursor().Parent() ).AssemblePath(filePathBuffer);
248 filePath= &filePathBuffer;
249 }
250
251 if( ( it->file .IsValid() && ( it->file == file.AsCursor().Export() ) )
252 || ( it->subTree .IsValid() && ( file.AsCursor().Distance( ImportCursor(it->subTree) ) >= 0 ) )
253 || ( it->fileName .IsNotEmpty() && it->fileName.Equals(file.AsCursor().Name()) )
254 || ( it->pathPrefix .IsNotEmpty() && filePath->StartsWith(it->pathPrefix) )
255 || ( it->pathSubstring.IsNotEmpty() && filePath->IndexOf(it->pathSubstring) >= 0 )
256 )
257 {
258 Log_Verbose("Notifying listener. Event=", event == FTreeListener::Event::CreateNode
259 ? "CreateNode" : "DeleteNode" )
260 it->listener->Notify( file, event );
261 } }
262} // FTree::notifyListeners
263
264
265# include "ALib.Lang.CIFunctions.H"
266void FTree::FixSums( Cursor directory) {
267 ALIB_ASSERT_ERROR( directory->Type() == FInfo::Types::DIRECTORY,
268 "FILES", "Given node is not a directory." )
269
270 FInfo::DirectorySums& sums= directory->Sums();
271 sums= FInfo::DirectorySums();
272 directory.GoToFirstChild();
273 while( directory.IsValid()) {
274 FInfo& v= *directory;
275 sums.TypeCounters[size_t(v.Type())]++;
276 if( v.IsDirectory() )
277 sums+= v.Sums();
278
279 directory.GoToNextSibling();
280} }
281
282//==================================================================================================
283//=== Debug Dump
284//==================================================================================================
285
286#if ALIB_DEBUG && !DOXYGEN
287
289 A_CHAR("{:ta h{2,r} on{10,r} gn{10,r} s(IEC){10,r} dm qqq FxFa (rd{3r}' D' rf{3r}' F' re{2r}' EA' rb{2r}'BL) 'nx l b }\n");
290
291AString& DbgDump( AString& target,
292 FTree& tree,
293 EnumBitSet<FInfo::Types> includedTypes,
294 FTree::Cursor startNode ,
295 unsigned depth ) {
296 if( startNode.IsInvalid() )
297 startNode= tree.Root().AsCursor();
298
301 fmt.Reset();
304
305 // loop over all nodes and dump
306 fmt.Format( target, DBG_DUMP_FORMAT, File(startNode) );
307
308 stit.SetMaxDepth( depth );
309 stit.Initialize ( startNode, lang::Inclusion::Exclude );
310 while( stit.IsValid()) {
311 if( includedTypes.Test(stit.Node()->Type()))
312 fmt.Format( target, DBG_DUMP_FORMAT, File(stit.Node()) );
313 stit.Next();
314 }
315
316 return target;
317}
318
319#endif // ALIB_DEBUG && !DOXYGEN (dump methods)
320# include "ALib.Lang.CIMethods.H"
321
322} // namespace alib::files
#define ALIB_ALLOW_SPARSE_ENUM_SWITCH
Definition alib.inl:611
#define A_CHAR(STR)
Definition alib.inl:1325
#define ALIB_WARNING(domain,...)
Definition alib.inl:1141
#define ALIB_ERROR(domain,...)
Definition alib.inl:1140
#define ALIB_LOCK_RECURSIVE_WITH(lock)
Definition alib.inl:1414
#define ALIB_POP_ALLOWANCE
Definition alib.inl:673
#define ALIB_DBG(...)
Definition alib.inl:931
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1144
#define Log_If(...)
#define Log_Verbose(...)
#define Log_SetDomain(...)
void SetMaxDepth(unsigned int newMaxDepth=(std::numeric_limits< unsigned >::max)())
void Initialize(CursorType startNode, lang::Inclusion includeStartNode)
void SetPathGeneration(lang::Switch pathGeneration)
StringTree(AllocatorType &allocator, CharacterType pathSeparator)
The entry type which is embedded in each tree node.
Definition finfo.inl:15
constexpr Types Type() const noexcept
Definition finfo.inl:377
constexpr ExtendedEntryInfo * GetExtendedInfo() const
Definition finfo.inl:412
constexpr bool IsDirectory() const noexcept
Definition finfo.inl:379
@ DIRECTORY
Directory/folder.
Definition finfo.inl:28
constexpr DirectorySums & Sums() const
Definition finfo.inl:424
FTree(MonoAllocator &allocator)
Definition ftree.cpp:123
PoolAllocator Pool
Definition ftree.inl:162
NumberFormat numberFormat
Definition ftree.inl:175
OwnerAndGroupResolver ogResolver
Definition ftree.inl:179
void notifyListeners(FTreeListener::Event event, const File &file, const system::PathString &filePath)
Definition ftree.cpp:233
int MonitorStop(FTreeListener *listener)
Definition ftree.cpp:213
void registerListener(FTreeListener *listener, lang::ContainerOp insertOrRemove, FTreeListener::Event event, const File *file, const StringTree::Cursor *subTree, const system::PathString &fileName, const system::PathString &pathPrefix, const system::PathString &pathSubstring)
Definition ftree.cpp:165
ListMA< ListenerRecord > listeners
The list of registered listeners.
Definition ftree.inl:196
~FTree()
Destructor.
Definition ftree.cpp:140
static void FixSums(Cursor directory)
Definition ftree.cpp:266
Cursor & AsCursor()
Definition ftree.inl:708
static threads::RecursiveLock DEFAULT_LOCK
Formatter & Format(AString &target, TArgs &&... args)
static SPFormatter DEFAULT
virtual BoxesMA & Reset()
constexpr bool Test(TInterface bit) noexcept
Definition bitset.inl:316
constexpr bool IsEmpty() const
Definition string.inl:353
integer IndexOf(TChar needle, integer startIdx=0) const
Definition string.inl:803
bool StartsWith(const TString &needle) const
Definition string.inl:739
This namespace implements internals of namespace #"alib::files;2".
Definition ftree.cpp:60
String DBG_DUMP_FORMAT
AString & DbgDump(AString &target, FTree &tree, EnumBitSet< FInfo::Types > includedTypes=EnumBitSet< FInfo::Types >(true), FTree::Cursor startNode=FTree::Cursor(), unsigned depth=(std::numeric_limits< unsigned int >::max)())
ContainerOp
Denotes standard container operations.
@ Insert
Denotes insertions.
@ Off
Switch it off, switched off, etc.
@ Exclude
Chooses exclusion.
strings::TString< PathCharType > PathString
The string-type used with this ALib Module.
Definition path.inl:33
strings::TAString< PathCharType, PoolAllocator > PathStringPA
A pool-allocated string representing a path.
Definition path.inl:46
constexpr PathCharType DIRECTORY_SEPARATOR
The standard path separator character. Defaults to '\' on Windows OS, '/' else.
Definition path.inl:63
monomem::TMonoAllocator< lang::HeapAllocator > MonoAllocator
format::Formatter Formatter
Type alias in namespace alib.
files::File File
Type alias in namespace alib.
Definition ftree.inl:1055
strings::TString< character > String
Type alias in namespace alib.
Definition string.inl:2172
system::Path Path
Type alias in namespace alib.
Definition path.inl:375
lang::TBitSet< TEnum, enumops::IterableTraits< TEnum >::End, enumops::IterableTraits< TEnum >::Begin > EnumBitSet
files::FilesCamp FILES
The singleton instance of ALib Camp class #"FilesCamp".
Definition filescamp.cpp:47
strings::TAString< character, lang::HeapAllocator > AString
Type alias in namespace alib.
containers::StringTreeIterator< TTree > StringTreeIterator
Type alias in namespace alib.
HashTable< TAllocator, typename NodeKey::ValueDescriptor, typename NodeKey::Hash, typename NodeKey::EqualTo, lang::Caching::Enabled, TRecycling > nodeTable
Recursively accumulated values for directories.
Definition finfo.inl:189
std::array< uint32_t, size_t(Types::MARKER_TYPES_END)> TypeCounters
Per-type counters.
Definition finfo.inl:191
Event
The type of change that imposes the notification of a listener.
Definition ftree.inl:96
Record used to manage registered listeners.
Definition ftree.inl:183
static void AllocateExtendedInfo(StringTree< MonoAllocator, FInfo, detail::FTreeNodeHandler >::Cursor &node, const system::PathString &symLinkDest, const system::PathString &symLinkRealPath)
Definition ftree.cpp:63