Files CCore/inc/Path.h CCore/src/Path.cpp
There is a set of classes to work with file paths. A path may have the following components:
A path may have multiple device components, directory components, a file name may have multiple file extension components:
host:d:\exchange\device.1\device.log.txt
This structure is a collection of tools for the path scanning.
struct PathBase
{
static bool IsSlash(char ch) { return ch=='/' || ch=='\\' ; }
static bool IsDot(char ch) { return ch=='.'; }
static bool IsColon(char ch) { return ch==':'; }
static bool IsTilde(char ch) { return ch=='~'; }
static bool IsDot(StrLen name) { return name.len==1 && name[0]=='.' ; }
static bool IsDotDot(StrLen name) { return name.len==2 && name[0]=='.' && name[1]=='.' ; }
static bool IsTilde(StrLen name) { return name.len==1 && name[0]=='~' ; }
enum NameType
{
Name,
EmptyName,
DotName,
DotDotName
};
static NameType GetNameType(StrLen name);
struct ToPrefix
{
StrLen prefix;
StrLen suffix;
bool no;
void set(StrLen str,StrLen cur);
void set(StrLen str);
};
struct ToPrefixDel
{
StrLen prefix;
StrLen suffix;
bool no;
void set(StrLen str,StrLen cur);
void set(StrLen str);
};
struct ToSuffix
{
StrLen prefix;
StrLen suffix;
bool no;
void set(StrLen str,StrLen cur);
void set(StrLen str);
};
template <bool Is(char ch),class To>
struct ForwardScan : To
{
explicit ForwardScan(StrLen str);
};
template <bool Is(char ch),class To>
struct BackwardScan : To
{
explicit BackwardScan(StrLen str);
};
};
IsSlash() tests if the given character is slash.
IsDot() tests if the given character is dot.
IsColon() tests if the given character is colon.
IsDot() tests if the given name is the single dot name.
IsDotDot() tests if the given name is the double dot name.
IsTilde() tests if the given name is the single tilde name.
GetNameType() checks the type of the given name. There are four possible answers:
The following set of classes is used to split the given string into components.
ForwardScan scans forward the given string for the character, satisfying the given condition. If such character is found, it calls the method set(StrLen str,StrLen cur) of the base class. Otherwise the method set(StrLen str) is called.
BackwardScan is similar to the ForwardScan, but scans backward.
The remaining classes are used to split the string at the found position.
ToPrefix splits after the found position, i.e. the found character goes to the prefix. In case the required character is not found, the prefix is empty.
ToPrefixDel is similar to the ToPrefix, but it removes the found character from the prefix.
ToSuffix splits before the found position, i.e. the found character goes to the suffix. In case the required character is not found, the suffix is empty.
struct SplitDev : PathBase
{
StrLen dev; // first dev:
StrLen dev_path;
bool no_dev;
explicit SplitDev(StrLen dev_path);
bool operator ! () const { return no_dev; }
};
This Class-function splits the given path into the first device component and the rest. The no_dev is true, if there is no device component. In this case the dev is null and the dev_path is the given path. Colon goes to the dev.
host: d:\exchange\device.1\device.log.txt
struct SplitPath : PathBase
{
StrLen dev; // all dev1:dev2:...:
StrLen path;
bool no_dev;
explicit SplitPath(StrLen dev_path);
bool operator ! () const { return no_dev; }
};
This Class-function splits the given path into the all device components and the rest. The no_dev is true, if there is no device component. In this case the dev is null and the path is the given path. Colon goes to the dev.
host:d: \exchange\device.1\device.log.txt
struct SplitDir : PathBase
{
StrLen dir; // first dir/
StrLen path;
bool no_path;
explicit SplitDir(StrLen path);
bool operator ! () const { return no_path; }
};
This Class-function splits the given path (assumed without device component) into the first directory component and the rest. The no_path is true, if there is no directory component. In this case the dir is null and the path is the given path. Slash goes to the dir.
\ exchange\device.1\device.log.txt
exchange\ device.1\device.log.txt
struct SplitName : PathBase
{
StrLen path; // all dir1/dir2/.../
StrLen name;
bool no_path;
explicit SplitName(StrLen path);
bool operator ! () const { return no_path; }
NameType getNameType() const { return GetNameType(name); }
};
This Class-function splits the given path (assumed without device component) into the all directory components and the rest. The no_path is true, if there is no directory component. In this case path is null and the name is the given path. Slash goes to the path.
getNameType() returns the type of the file name component.
\exchange\device.1\ device.log.txt
struct SplitFullExt : PathBase
{
StrLen name;
StrLen ext; // all .ext1.ext2...
bool no_ext;
explicit SplitFullExt(StrLen name);
bool operator ! () const { return no_ext; }
};
This Class-function splits the given file name into the all extensions and the name. The no_ext is true, if there is no extension. In this case the ext is null and the name is the given name. Dot goes to the ext.
device .log.txt
struct SplitExt : PathBase
{
StrLen name;
StrLen ext; // last .ext
bool no_ext;
explicit SplitExt(StrLen name);
bool operator ! () const { return no_ext; }
};
This Class-function splits the given file name into the last extension and the rest. The no_ext is true, if there is no extension. In this case the ext is null and the name is the given name. Dot goes to the ext.
device.log .txt
struct SplitDevName : PathBase
{
StrLen dev_name; // first dev_name: , : removed
StrLen dev_path;
bool no_dev;
explicit SplitDevName(StrLen dev_path);
bool operator ! () const { return no_dev; }
};
SplitDevName is similar to the SplitDev, except it removes colon from the dev_name.
host d:\exchange\device.1\device.log.txt
struct SplitDirName : PathBase
{
StrLen dir_name; // first dir_name/ , / removed
StrLen path;
bool no_path;
explicit SplitDirName(StrLen path);
bool operator ! () const { return no_path; }
NameType getNameType() const { return GetNameType(dir_name); }
};
SplitDirName is similar to the SplitDir, except it removes slash from the dir_name.
getNameType() returns the type of the directory name component.
exchange\device.1\device.log.txt
exchange device.1\device.log.txt
struct SplitPathName : PathBase
{
StrLen path; // all dir1/dir2/.../ , / removed
StrLen name;
bool no_path;
explicit SplitPathName(StrLen path);
bool operator ! () const { return no_path; }
NameType getNameType() const { return GetNameType(name); }
};
SplitPathName is similar to the SplitName, except it removes slash from the path.
\exchange\device.1 device.log.txt
The class Path is designed to manipulate with a path. The path inside Path is stored in the internal buffer. It has a non-mutable prefix. This prefix is determined by the constructor. The string after prefix is a normalized path. I.e. it may be empty or "." or "dir1/dir2/.../dir_or_file", where dirs are normal names, dir_of_file may be ".".
class Path : public NoCopyBase<PathBase>
{
char buf[MaxPathLen];
ulen buf_len;
....
public:
enum BeginType
{
BeginEmpty,
BeginRoot
};
explicit Path(BeginType=BeginRoot);
explicit Path(StrLen dev_name);
using PrintProxyType = StrLen ;
operator StrLen() const { return StrLen(buf,buf_len); }
bool isRoot() const;
bool isRootDir() const;
void root();
void rootDir();
void add(StrLen name);
void back();
void addPath(StrLen path);
void copyPath(const Path &path);
};
Path(Path::BeginEmpty) constructor creates a path object with the empty path prefix.
Path(Path::BeginRoot) constructor creates a path object with the path prefix equals "/".
Path(StrLen dev_name) constructor creates a path object, which has the path prefix dev_name+":/";
Path is castable to the StrLen type and printable using this type as the PrintProxyType.
root() sets the Path value to its path prefix.
rootDir() sets the Path value to its path prefix + ".".
isRoot() checks if the object is at the root() state.
isRootDir() checks if the object is at the rootDir() state.
add() adds a top path component. It properly handles single dot and double dot names. An exception is thrown in case of error.
back() removes the top path component. The path must not be in the root() or the rootDir() state — an exception will be thrown.
addPath() adds multiple path components. If the argument is started with slash, then path is assumed absolute, otherwise — relative to the current value. The empty argument does nothing.
copyPath() copies the argument.