Path handling¶
EVFS needs to be able to work with file and directory paths. The library provides functions to help you manipulate paths in an OS agnostic way. These are pure string manipulations and the referenced files and directories do not have to exist on any VFS. The operations allow you to extract portions of a path, join paths together, normalize them, and convert relative paths into absolute.
The representation of absolute paths can vary between systems. In Unix derived systems a bare ‘/’ represents the root of the filesystem tree. On DOS/Windows systems this can be more elaborate with optional drive letters and other variants. To make path processing more universal, these functions work in conjunction with a method from each VFS that identifies the root component of a path and whether it is absolute. This portion of a path is left largely untouched by the EVFS library. Paths are passed through and validated by the underlying filesystem. Because of this behavior you will need at least one filesystem registered with EVFS before you can operate on paths. If you register multiple filesystems with different conventions for the root component you must ensure that the right VFS is referenced with its matching paths.
String ranges¶
The EVFS path API functions frequently take a StringRange
or AppendRange
struct as input and output parameters. These are part of a small string utility in ‘src/util/range_strings.c’. These structs represent a substring pointing into another string. StringRange
objects represent a substring that will not change bounds after a function call. AppendRange
objects cover the empty space at the end of a string to append into. They have their start position advanced after an append operation. They have the same layout and only differ by the presence of const pointers in StringRange
. These types can be casted back and forth as necessary.
The general procedure for using these types is to prepare a storage area for a string, either a local array or one produced by dynamic allocation. You then initialize the StringRange
to cover the char array. This can be accomplished with a static initializer for true arrays or by calling range_init()
with the start and size of the array when you have a pointer to allocated storage.
char buf[100];
StringRange buf_r = RANGE_FROM_ARRAY(buf); // Initializer can be used with array variables
char *buf2 = evfs_malloc(100);
StringRange buf2_r;
range_init(&buf_2_r, buf2, 100); // Initialize pointers
char *str; // Unknown length
StringRange str_r;
range_init(&str_r, str, strlen(str)+1); // When using strlen, add 1 to include the NUL
A substring pointed to by StringRange
will not necessarily be NUL terminated. To print the substring using printf()
formatted output, you use the “%.*s” specifier and the RANGE_FMT
macro:
StringRange *str;
printf("Substring in range is: '%.*s'\n", RANGE_FMT(str));
Path API¶
All of the functions that generate a new string from joining, normalization, or absolute conversion have been designed to safely overwrite their input string if it is also the output. This allows you to reuse an existing range and minimize the need for temporary buffers. These functions also avoid use of evfs_malloc()
whenever possible.
Most of these functions have an “_ex” suffix indicating that their last parameter is an optional VFS name. All of these forms have a macro defined without the suffix that uses the default VFS.
-
bool
evfs_path_root_component_ex
(const char *path, StringRange *root, const char *vfs_name)¶ Get the root portion of a path.
This is a virtual method that calls into a VFS specific implementation to handle different filesystem path formats. On POSIX style systems the root component of absolute paths is a leading sequence of one or more ‘/’ chars and nothing for relative paths. On DOS/Windows filesystems the root component may also have a colon separated volume letter or number on absolute or relative paths.
- Parameters
path – Path to extract root from
root – Substring of path corresponding to root or empty if none found
vfs_name – VFS to work on. Use default VFS if NULL
- Returns
true when the path is absolute
-
bool
evfs_path_is_absolute_ex
(const char *path, const char *vfs_name)¶ Detect if a path is absolute on the supplied VFS.
- Parameters
path – Path to test
vfs_name – VFS to work on. Use default VFS if NULL
- Returns
true if path is absolute
-
int
evfs_path_basename
(const char *path, StringRange *tail)¶ Get the file name portion of a path.
This copies the behavior of Python os.path.basename().
- Parameters
path – Path to extract basename from
tail – Substring of path corresponding to the basename
- Returns
EVFS_OK on success
-
int
evfs_path_extname
(const char *path, StringRange *ext)¶ Get the extension of a file.
This copies the behavior of Python os.path.splitext().
- Parameters
path – Path to extract extension from
ext – Substring of path corresponding to the extension
- Returns
EVFS_OK on success
-
int
evfs_path_dirname_ex
(const char *path, StringRange *head, const char *vfs_name)¶ Get the directory portion of a path.
This copies the behavior of Python os.path.dirname().
- Parameters
path – Path to extract dirname from
head – Substring of path corresponding to the dirname
vfs_name – VFS to work on. Use default VFS if NULL
- Returns
EVFS_OK on success
-
int
evfs_path_join_ex
(StringRange *head, StringRange *tail, StringRange *joined, const char *vfs_name)¶ Join two paths.
- Parameters
head – Substring of left portion to join
tail – Substring of right portion to join
joined – Substring of output string. This can be the same as the head substring.
vfs_name – VFS to work on. Use default VFS if NULL
- Returns
EVFS_OK on success
-
int
evfs_path_join_str_ex
(const char *head, const char *tail, StringRange *joined, const char *vfs_name)¶ Join two paths using char strings.
- Parameters
head – Substring of left portion to join
tail – Substring of right portion to join
joined – Substring of output string. This can be the same as the head path.
vfs_name – VFS to work on. Use default VFS if NULL
- Returns
EVFS_OK on success
-
int
evfs_path_normalize_ex
(const char *path, StringRange *normalized, const char *vfs_name)¶ Normalize a path.
This applies the following transformations:
Any root component is reduced to its minimal form.
Consecutive separators are merged into one
All separators after root component are converted to EVFS_DIR_SEP
“./” segments are removed
“../” segments are removed along with the preceeding segment
Trailing slashes are removed
- Parameters
path – Path to be normalized
normalized – Normalized output path. This can be the same string as path
vfs_name – VFS to work on. Use default VFS if NULL
- Returns
EVFS_OK on success
-
int
evfs_path_absolute_ex
(const char *path, StringRange *absolute, const char *vfs_name)¶ Convert a path to absolute form.
If the path is already absolute it is normalized. Otherwise it is joined to the current working directory and normalized.
- Parameters
path – Path to become absolute
absolute – Absolute output path. This can be the same string as path
vfs_name – VFS to work on. Use default VFS if NULL
- Returns
EVFS_OK on success
-
bool
evfs_vfs_path_is_absolute
(Evfs *vfs, const char *path)¶ Detect if a path is absolute on the supplied VFS.
This variant is for fs wrappers to use without a name lookup.
- Parameters
vfs – The VFS for the path
path – Path to test
- Returns
true if path is absolute