ALib C++ Framework
by
Library Version: 2605 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
ftfile.cpp
1using namespace alib::system;
2namespace alib::filetree {
3
4strings::TAString<PathCharType>&
6 lang::Inclusion includeFilename ) const {
7
8 static constexpr int STACK_SIZE= 256;
9 FTree::CursorHandle nStack[STACK_SIZE];
10
11 FTFile actNode= (*this);
12 if(includeFilename == lang::Inclusion::Exclude)
13 actNode= actNode.GetSymbolicParent();
14
15 // if child and maxParent are the same, we do nothing
16 if (actNode.IsRoot())
17 return target;
18
19 // build stack
20 int sp =0;
21 while( !actNode.IsRoot() ) {
22 // local stack full? -> let a recursive call do the rest
23 if(sp == STACK_SIZE) {
24 FTFile(actNode).AssembleSymbolicPath( target, lang::Inclusion::Include );
25 break;
26 }
27
28 if(actNode.HasSymbolicParent()) {
29 auto parentNode= actNode;
30 actNode= actNode.GetSymbolicParent();
31 int i= 0;
32 for(; i < sp; ++i) {
33 if(nStack[i] == actNode.Export())
34 break;
35 }
36 if(i < sp) {
37 auto parent= parentNode.Parent();
38 if(parent.IsRoot())
39 break;
40 nStack[sp++]= parent.Export();
41 actNode= FTFile(parent.Parent());
42 } }
43 else {
44 nStack[sp++]= actNode.Export();
45 actNode= actNode.Parent();
46 } }
47
48 // unroll stack now from top to bottom
49 while( --sp >= 0) {
50 FTree::ConstCursorHandle ch = nStack[sp];
51 ConstCursor actual= GetFTree().ImportCursor(ch);
52 if( !actual.IsRoot() ) {
53 if( target.CharAtEnd() != DIRECTORY_SEPARATOR )
54 target << DIRECTORY_SEPARATOR;
55 target << actual.Name();
56 }
57 else
58 target << DIRECTORY_SEPARATOR;
59 }
60
61 return target;
62}
63
65 int perms= int(Value().Perms());
66 // This is a "hard-coded" optimized approach. It only works unless the values of enum
67 // Permissions are as they have been since decades...
68 static_assert( int(FileStatus::Permissions::OWNER_READ ) == 0400 &&
77 "This method is not compatible due to changes in the permission enumeration." );
78
79 target._<CHK>(""); // ensure valid target
80 std::array<char, 9> result;
81 std::array<char, 3> chars = {'r', 'w', 'x'};
82 int bit = 0400;
83 size_t charIdx = 0;
84 while( bit ) {
85 result[charIdx]= perms & bit ? chars[charIdx % 3] : '-';
86 charIdx++;
87 bit >>= 1;
88 }
89 target << result;
90
91 // This is the naive version that would not need the assertion above
92 // target << ( (perms & FileStatus::Permissions::OWNER_READ ) == FileStatus::Permissions::OWNER_READ ? 'r' : '-' )
93 // << ( (perms & FileStatus::Permissions::OWNER_WRITE ) == FileStatus::Permissions::OWNER_WRITE ? 'w' : '-' )
94 // << ( (perms & FileStatus::Permissions::OWNER_EXEC ) == FileStatus::Permissions::OWNER_EXEC ? 'x' : '-' )
95 // << ( (perms & FileStatus::Permissions::GROUP_READ ) == FileStatus::Permissions::GROUP_READ ? 'r' : '-' )
96 // << ( (perms & FileStatus::Permissions::GROUP_WRITE ) == FileStatus::Permissions::GROUP_WRITE ? 'w' : '-' )
97 // << ( (perms & FileStatus::Permissions::GROUP_EXEC ) == FileStatus::Permissions::GROUP_EXEC ? 'x' : '-' )
98 // << ( (perms & FileStatus::Permissions::OTHERS_READ ) == FileStatus::Permissions::OTHERS_READ ? 'r' : '-' )
99 // << ( (perms & FileStatus::Permissions::OTHERS_WRITE) == FileStatus::Permissions::OTHERS_WRITE ? 'w' : '-' )
100 // << ( (perms & FileStatus::Permissions::OTHERS_EXEC ) == FileStatus::Permissions::OTHERS_EXEC ? 'x' : '-' )
101 // ;
102 return target;
103}
104
106 if(nf == nullptr )
108
109 if ( targetData == lang::CurrentData::Clear )
110 target.Reset();
111
112 // this ensures that target is not nulled, as all other appends are NC-versions
113 target._("");
114
115 while ( format.IsNotEmpty() ) {
116 Box toBeAdded; // A box that most probably is set during the switch below. It will
117 // be added potentially embedded in a TField.
118 bool isUpper=false; // if set during run, the result string will be converted to upper case
119 Path pathBuffer; // A path that might be filled and assigned to the result box (toBeAdded).
120 String256 strBuffer; // A string that might be filled and assigned to the result box (toBeAdded).
123
124 // read n equal characters
125 int n= 1;
126 character c= format.ConsumeChar();
127 while ( format.ConsumeChar(c) )
128 ++n;
129
130 if( isupper(c) ) {
131 c= character( tolower(c) );
132 isUpper= true;
133 }
134 integer previousLength= target.Length();
135
136 auto& value= Value();
137 switch (c) {
138 // path, name, stem, extension
139 case 'n':
140 {
141 // read next character
142 c= character(tolower(format.ConsumeChar()));
143 switch(c) {
144 case 'a' : toBeAdded= Name(); break;
145 case 's' : toBeAdded= Stem(); break;
146 case 'e' : toBeAdded= Extension(); break;
147 case 'p' :
148 case 'f' : AssembleSymbolicPath( pathBuffer, c == 'f'
151 toBeAdded= pathBuffer;
152 break;
153 case 'r' :
154 case 'x' : AssembleRealPath ( pathBuffer, c == 'x'
157 toBeAdded= pathBuffer;
158 break;
159
160 default:
161 {
162 ALIB_WARNING( "ALIB", "Format Error: Token 'n' followed by unknown "
163 "specifier '{}' in FTFile::Format.", c )
164 target << "Format Error: Token 'n' followed by unknown specifier '" << c
165 << "' in FTFile::Format.";
166 return target;
167 } } }
168 break;
169
170
171 case 'a':
172 FormatAccessRights(strBuffer);
173 toBeAdded= strBuffer;
174 break;
175
176 case 't': // Type
177 if( n == 1 ) toBeAdded= FTValue::TypeNames1Letter (value.Type());
178 else if( n == 2 ) toBeAdded= FTValue::TypeNames2Letters(value.Type());
179 else if( n == 3 ) toBeAdded= FTValue::TypeNames3Letters(value.Type());
180 else toBeAdded= value.Type();
181 break;
182
183 case 'l': // Symlink information
184 {
185 String4K symlinkInfo;
186 if( ( value.Type() == FileStatus::Types::SYMBOLIC_LINK
187 || value.Type() == FileStatus::Types::SYMBOLIC_LINK_DIR )
188 && value.ScanState() >= FTValue::ScanStates::RESOLVED )
189 {
190 strBuffer << " -> " << value.GetLinkTarget();
191 if( value.GetRealLinkTarget().IsNotEmpty()
192 && !value.GetLinkTarget().Equals( value.GetRealLinkTarget()) )
193 strBuffer << " (" << value.GetRealLinkTarget() << ")";
194 toBeAdded= strBuffer;
195 }
196 break;
197 }
198 case 'b': // Symbolic parent
199 {
200 if(value.symParent != 0) {
201 const FTFile symbolicParent= GetSymbolicParent();
202 pathBuffer << " <- ";
203 symbolicParent.AssemblePath(pathBuffer, lang::CurrentData::Keep);
204 toBeAdded= pathBuffer;
205 }
206 break;
207 }
208
209 case 'f': // IsCrossingFS() / IsArtificialFS()
210 switch(c= character(tolower(format.ConsumeChar()))) {
211 case 'x' : toBeAdded= (value.IsCrossingFS() ? 'm' : '-') ; break;
212 case 'a' : toBeAdded= (value.IsArtificialFS() ? 'm' : '-') ; break;
213 default:
214 {
215 ALIB_WARNING( "ALIB", "Format Error: Unknown character {} after "
216 "token 'f' in FTFile::Format.", c )
217 target << "Format Error: Unknown character '" << c
218 << "' after token 'f' in FTFile::Format.";
219 return target;
220 } }
221 break;
222
223 case 'h': // Quantity of hard links
224 if( value.QtyHardLinks() != uint32_t(-1) ) toBeAdded= value.QtyHardLinks();
225 else toBeAdded= "-1";
226 break;
227
228 case 'q': // ScanState
229 if( n == 3 ) toBeAdded= FTValue::ScanStates3Letters(value.ScanState());
230 else toBeAdded= value.ScanState();
231 break;
232
233 case 'd': // date
234 {
235 CalendarDateTime date;
236 switch(c= character(tolower(format.ConsumeChar()))) {
237 case 'm' : date= value.MDate(); break;
238 case 'b' : date= value.BDate(); break;
239 case 'c' : date= value.CDate(); break;
240 case 'a' : date= value.ADate(); break;
241 default:
242 {
243 ALIB_WARNING( "ALIB",
244 "Format Error: Unknown character {} after token 'd' "
245 "in FTFile::Format.", c )
246 target << "Format Error: Unknown character '" << c
247 << "' after token 'd' in FTFile::Format.";
248 return target;
249 } }
250
251 String dateFormat= format.ConsumeField('{', '}' );
252 if( dateFormat.IsEmpty() )
253 dateFormat= A_CHAR("dd. MMM yyyy HH:mm");
254 date.Format( dateFormat, strBuffer );
255 toBeAdded= strBuffer;
256 break;
257 }
258
259 case 's': // size
260 {
261 bool automaticMode = true;
262 auto unit = ByteSizeUnits::IEC;
263
264 // entity specified in braces?
265 if( format.CharAtStart() == '(' ) {
266 format.ConsumeChar();
267 if( format.StartsWith<CHK,lang::Case::Ignore>(A_CHAR("SI"))) {
268 unit= ByteSizeUnits::SI;
269 format.ConsumeChars(2);
270 }
271 else if( format.StartsWith<CHK,lang::Case::Ignore>(A_CHAR("IEC"))) {
272 format.ConsumeChars(3);
273 } else {
274 enumrecords::Parse( format, unit );
275 automaticMode= false;
276 }
277
278 if( format.ConsumeChar() != ')' ) {
279 ALIB_WARNING( "ALIB",
280 "Format Error: Expected closing brace ')' after unit specification with token 's'." )
281 target << "Format Error: Expected closing brace ')' after unit specification with token 's'.";
282 return target;
283 } }
284
285 auto* ftreeNF= &GetFTree().GetNumberFormat();
286 if( !automaticMode ) {
287 // convert to given unit and output either a double or an integral.
288 ByteSizeIEC bs( value.Size() );
289 auto dval= bs.ConvertTo(unit);
290 if( unit==ByteSizeUnits::B || unit ==ByteSizeUnits::B_SI )
291 strBuffer << alib::Dec( uinteger(dval), 0, ftreeNF);
292 else
293 strBuffer << alib::Dec( dval , 0, ftreeNF);
294 } else {
295 // automatic output (automatically determine magnitude)
296 format::FormatByteSize( strBuffer, value.Size(), 900, 0, unit, *ftreeNF );
297 }
298 toBeAdded= strBuffer;
299 break;
300 }
301
302 case 'o': // owner
303 case 'g': // group
304 {
305 bool isOwner= c== 'o';
306 c= format.ConsumeChar();
307
308 if( c != 'i' && c != 'n' ) {
309 ALIB_WARNING( "ALIB",
310 "Format Error: Expected 'i' or 'n' specifier after token 'o' and 'g'."
311 " Given: '{}'", n )
312 target << "Format Error: Expected 'i' or 'n' specifier after token 'o' and 'g'."
313 " Given: '" << c << "'";
314 return target;
315 }
316 bool isName= (c == 'n');
317
318 if( isName ) {
319 auto& resolver= GetFTree().GetOGResolver();
320 toBeAdded= isOwner ? resolver.GetOwnerName(value)
321 : resolver.GetGroupName(value);
322 } else {
323 strBuffer << (isOwner ? value.Owner() : value.Group());
324 toBeAdded= strBuffer;
325 }
326 break;
327 }
328
329 // Extended directory info: sub-dirs, sub-files, access error, broken links
330 case 'r':
331 {
332 // read next character
333 c= character(tolower(format.ConsumeChar()));
334 if( !value.IsDirectory()
335 || value.ScanState() < FTValue::ScanStates::RECURSIVE )
336 {
337 toBeAdded= 0;
338 break;
339 }
340
341 FTValue::DirectorySums& dirInfo= value.Sums();
342 switch(c) {
343 case 'd' : toBeAdded= dirInfo.CountDirectories(); break;
344 case 'f' : toBeAdded= dirInfo.CountNonDirectories(); break;
345 case 'e' : toBeAdded= dirInfo.QtyErrsAccess; break;
346 case 'b' : toBeAdded= dirInfo.QtyErrsBrokenLink; break;
347 default:
348 {
349 ALIB_WARNING( "ALIB",
350 "Format Error: Token 'r' followed by unknown specifier '{}' "
351 "in FTFile::Format", c )
352 target << "Format Error: Token 'r' followed by unknown specifier '" << c
353 << "'in FTFile::Format";
354 return target;
355 } } }
356 break;
357
358
359 //--------------------------- single quotes and other characters -------------------------
360 case '\'':
361 {
362 // one or more pairs of single quotes?
363 if ( n > 1 ) {
364 int pairs= n / 2;
365 target.InsertChars<NC>( '\'', pairs );
366 n-= (pairs * 2);
367 }
368
369 // one single quote?
370 if ( n == 1 ) {
371 // search end
372 integer end= format.IndexOf( '\'' );
373 if ( end < 1 ) {
374 ALIB_WARNING( "ALIB", "Format Error: Missing single Quote" )
375 target << "Format Error: Missing closing single quote character <'>" ;
376 return target;
377 }
378
379 target._<NC>( format, 0, end );
380 format.ConsumeChars<NC>( end + 1 );
381 } }
382 break;
383
384
385 default: // otherwise: copy what was in
386 target.InsertChars<NC>( c, n );
387 break;
388 } // switch(c)
389
390 // field width, alignment specified in braces?
391 int width= -1;
393 if( format.CharAtStart() == '{' ) {
394 format.ConsumeChar();
395 format.ConsumeInt( width, &GetFTree().GetNumberFormat() );
396 format.ConsumeChar(',');
397 enumrecords::Parse( format, alignment );
398 if( format.ConsumeChar() != '}' ) {
399 ALIB_WARNING( "ALIB",
400 "Format Error: Expected closing brace '}' with field specifier {width/alignment}." )
401 target << "Format Error: Expected closing brace '}' with field specifier {width/alignment}.";
402 return target;
403 }
404 target << Field( toBeAdded, width, alignment );
405 }
406 else
407 target << toBeAdded;
408
409 // upper case conversion
410 if( isUpper )
411 target.ToUpper(previousLength);
412 }
413
414 return target;
415} // FTFile::Format
416
417void FFormat_File( const Box& box, const String& formatSpec, NumberFormat& nf, AString& target ) {
418 box.Unbox<FTFile>().Format( formatSpec.IsNotEmpty() ? formatSpec
419 : FILETREE.GetResource("FFMT"),
420 target,
422 &nf );
423}
424
425} // namespace alib::filetree
#define A_CHAR(STR)
#define ALIB_WARNING(domain,...)
Cursor ImportCursor(CursorHandle handle)
strings::TAString< PathCharType > & AssembleRealPath(strings::TAString< PathCharType > &target, lang::Inclusion includeFilename) const
Definition ftree.hpp:783
AString & Format(Substring format, AString &target, lang::CurrentData targetData=lang::CurrentData::Keep, NumberFormat *numberFormat=nullptr) const
Definition ftfile.cpp:105
FTFile()=default
Defaulted default constructor.
PathString Stem() const
Definition ftree.hpp:757
strings::TAString< PathCharType > & AssembleSymbolicPath(strings::TAString< PathCharType > &target, lang::Inclusion includeFilename) const
Definition ftfile.cpp:5
FTFile GetSymbolicParent()
Definition ftree.hpp:721
AString & FormatAccessRights(AString &target) const
Definition ftfile.cpp:64
FTFile Parent() const
Definition ftree.hpp:749
PathString Extension() const
Definition ftree.hpp:768
FTree & GetFTree() const
Definition ftree.hpp:626
FTree::ConstCursor ConstCursor
The constant version of type #".Cursor".
Definition ftree.hpp:621
NumberFormat & GetNumberFormat()
Definition ftree.hpp:288
const OwnerAndGroupResolver & GetOGResolver() const
Definition ftree.hpp:296
TAString & InsertChars(TChar c, integer qty)
TAString & ToUpper(integer regionStart=0, integer regionLength=MAX_LEN)
TAString & _(const TAppendable &src)
void DbgDisableBufferReplacementWarning()
Definition tastring.hpp:236
constexpr integer Length() const
Definition string.hpp:300
constexpr bool IsEmpty() const
Definition string.hpp:349
constexpr bool IsNotEmpty() const
Definition string.hpp:353
TChar CharAtEnd() const
Definition string.hpp:436
AString & Format(Substring format, AString &target, lang::CurrentData targetData=lang::CurrentData::Keep) const
Definition calendar.cpp:268
@ GROUP_READ
Posix S_IRGRP: The file's user group has read permission.
@ GROUP_EXEC
Posix S_IXGRP: The file's user group has execute/search permission.
@ OTHERS_EXEC
Posix S_IXOTH: Other users have execute/search permission.
@ GROUP_WRITE
Posix S_IWGRP: The file's user group has write permission.
@ OWNER_READ
Posix S_IRUSR: File owner has read permission.
@ OWNER_EXEC
Posix S_IXUSR: File owner has execute/search permission.
@ OWNER_WRITE
Posix S_IWUSR: File owner has write permission.
@ OTHERS_READ
Posix S_IROTH: Other users have read permission.
@ OTHERS_WRITE
Posix S_IWOTH: Other users have write permission.
@ RECURSIVE
Follow symlink target strings.
@ RESOLVED
Read symlink target strings.
bool Parse(strings::TSubstring< TChar > &input, TEnum &result)
void FFormat_File(const Box &box, const String &formatSpec, NumberFormat &nf, AString &target)
Definition ftfile.cpp:417
void FormatByteSize(AString &target, uinteger byteSize, uint16_t magnitudeThreshold, char unitSeparator, ByteSizeUnits unit, NumberFormat &nf)
Alignment
Denotes Alignments.
@ Right
Chooses right alignment.
@ Keep
Chooses not no clear existing data.
@ Clear
Chooses to clear existing data.
Inclusion
Denotes how members of a set something should be taken into account.
@ Exclude
Chooses exclusion.
@ Include
Chooses inclusion.
strings::TNumberFormat< character > NumberFormat
Type alias in namespace #"%alib".
filetree::FilesCamp FILETREE
The singleton instance of ALib Camp class #"FilesCamp".
lang::integer integer
Type alias in namespace #"%alib".
Definition integers.hpp:149
boxing::Box Box
Type alias in namespace #"%alib".
Definition box.hpp:1128
strings::TField< character > Field
Type alias in namespace #"%alib".
LocalString< 4096 > String4K
Type alias name for #"TLocalString;TLocalString<character,4096>".
strings::TString< character > String
Type alias in namespace #"%alib".
Definition string.hpp:2165
system::Path Path
Type alias in namespace #"%alib".
Definition path.hpp:417
strings::TDec< character > Dec
Type alias in namespace #"%alib".
Definition format.hpp:540
strings::TSubstring< character > Substring
Type alias in namespace #"%alib".
strings::util::CalendarDateTime CalendarDateTime
Type alias in namespace #"%alib".
Definition calendar.hpp:509
LocalString< 256 > String256
Type alias name for #"TLocalString;TLocalString<character,256>".
constexpr PathCharType DIRECTORY_SEPARATOR
The standard path separator character. Defaults to '\' on Windows OS, '/' else.
Definition path.hpp:63
format::ByteSizeIEC ByteSizeIEC
Type alias in namespace #"%alib".
Definition bytesize.hpp:211
strings::TAString< character, lang::HeapAllocator > AString
Type alias in namespace #"%alib".
characters::character character
Type alias in namespace #"%alib".
lang::uinteger uinteger
Type alias in namespace #"%alib".
Definition integers.hpp:152
See sibling type #"NC".
Definition chk_nc.hpp:30
Recursively accumulated values for directories.
Definition ftvalue.hpp:25
uint32_t QtyErrsBrokenLink
Number of broken symbolic links in the directory and its subfolders.
Definition ftvalue.hpp:29
uint32_t CountNonDirectories() const noexcept
Definition ftvalue.hpp:115
uint32_t CountDirectories() const noexcept
Definition ftvalue.hpp:106
uint32_t QtyErrsAccess
Number of access errors in the folder and subfolders.
Definition ftvalue.hpp:28
double ConvertTo(ByteSizeUnits unit)