Skip to content

Working with Paths Files

Finalspace edited this page May 29, 2026 · 2 revisions

Table of Contents

Path constants

FPL provides a couple of path constants you can use, if needed:

Name Description
FPL_MAX_PATH_LENGTH Defines the maximum length of any path
FPL_MAX_FILENAME_LENGTH Defines the maximum length of a single filename without path
FPL_PATH_SEPARATOR Defines the path separator character
FPL_FILE_EXT_SEPARATOR Defines the file extension separator character

Note: All length constants include the null-terminator character as well, so you don't have to add one to the length when using!

Utilities

Combining paths

Use fplPathCombine() to combine multiple parts of a path to build one single path from it.

Unfortunately, this function requires you to pass the number of parts you want to combine :-(

If you know how to get the count of the variadic arguments (va_list) in C99, please contact me or write a GitHub issue! Thanks.

Example:

const char *assetsRootPath = ...
char textureAssetFilePath[];
if ((textureAssetFilePath, (textureAssetFilePath), 3, assetsRootPath, "textures", "mytexture.png") != ) {
    // ... Do something with the textureAssetFilePath
}

char tempPath[1024];
(tempPath, (tempPath), 3, "One", "Another", "Last");
// POSIX tempPath = One/Another/Last
// Win32 tempPath = One\Another\Last

Note: This is the recommended way to construct any kind of path because it will handle path separators correctly.

This function is designed to be compatible with .NET

Path.Combine() .

Warning: Do not pass the wrong number of maximum arguments as a third-argument, otherwise, your application may end up crashing horribly.

Extracting the file path

Use fplExtractFilePath() to extract the directory from the given path.

Using this on a path with a file will extract the path where the file is stored.

Using this on a directory path will extract the path of the parent directory.

Example:

const char *inputPath = ...
char newPath[];
if ((inputPath, &newPath, (newPath)) != ) {
    // ... Do something with the newPath
}

Note: This function is designed to be compatible with .NET

Path.GetDirectoryName() or

ExtractFilePath() on Delphi/FreePascal.

The original path is not altered in any way, therefore the source argument is defined as const.

Warning: Do not use manually constructed source paths with fixed path separators such as

/ or

\ , otherwise you will lose platform independence! Use

fplPathCombine() to build new paths from multiple paths if needed.

The return value of

fplExtractFilePath returns the pointer to the last-written character and

NOT the pointer to the first character!

Extracting the file name

Use fplExtractFileName() to extract the filename from any path.

Using this on a full or relative file-path will extract the name of the file.

Using this on a directory path will extract the name of the last directory in the path.

Example:

const char *inputFilePath = ...
const char *fileName = (inputFilePath);

// ... Do something with the fileName

// Results:
// /my/path/to/the/file.ico -> file.ico
// /my/path/to/the/starting.file.ico -> starting.file.ico
// c:\Program Files (x86)\Xenorate\Xenorate.exe -> Xenorate.exe
// myAwesomeFilename.executable -> myAwesomeFilename.executable
// passthrough -> passthrough
// /my/path/to/the/ ->

Note: This function is designed to be compatible with .NET

Path.GetFileName() or

ExtractFileName() on Delphi/FreePascal.

The original path is not altered in any way, therefore the source argument is defined as const.

Warning: Do not use manually constructed source paths with fixed path separators such as

/ or

\ , otherwise you will lose platform independence! Use

fplPathCombine() to build new paths from multiple paths if needed.

Extracting the file extension

Use fplExtractFileExtension() to extract the file extension from a path.

This will return anything starting from the last found file extension separator FPL_FILE_EXT_SEPARATOR to the very end of the path - containing the starting dot.

Using this on a path or filename will get you just the file extension if there is any.

Example:

const char *inputFilePath = ...
const char *fileExt = (inputFilePath);

// ... Do something with the fileExt

// Results:
// /my/path/to/the/file.ico -> .ico
// /my/path/to/the/starting.file.ico -> .file.ico
// c:\Program Files (x86)\Xenorate\Xenorate.exe -> .exe
// myAwesomeFilename.executable -> .executable
// /my/path/what.ever/libMyAwesome.so -> .so
// i_dont_have_any_dots_in_the_name ->

Note: This function is designed to be compatible with .NET

Path.GetExtension() or

ExtractFileExt() on Delphi/FreePascal.

The original path is not altered in any way, therefore the source argument is defined as const.

Warning: Do not use manually constructed source paths with fixed path separators such as

/ or

\ , otherwise you will lose platform independence! Use

fplPathCombine() to build new paths from multiple paths if needed.

Changing the file extension

Use fplChangeFileExtension() to change/add a file extensions on a file path.

Example:

const char *inputFilePath = ...
char changedFileExt[];
if ((inputFilePath, ".log", changedFileExt, (changedFileExt)) != ) {
    // ... Do something with the changedFileExt
}

Note: This function is designed to be compatible with .NET

Path.ChangeFileExtension() .

The original path is not altered in any way, therefore the source arguments are defined as const.

Warning: Do not use manually constructed source paths with fixed path separators such as

/ or

\ , otherwise you will lose platform independence! Use

fplPathCombine() to build new paths from multiple paths if needed.

Retrieving paths

Getting the home directory path

Use fplGetHomePath() to retrieve the home directory path for the current user.

On a POSIX based system this will most likely return something like "/usr/home/the_username_in_question"

On a Win32 based system this will most likely return something like "c:\Users\TheUsernameInQuestion"

Example:

char homePath[];
(&homePath, (homePath));
// ... Do something with the homePath

Note: There is no guarantee that this path ends with a trailing path separator, such as

/ on POSIX or

\ on Win32! If needed use

fplEnforcePathSeparator to always enforce a path separator.

Warning: The return value of

fplGetHomePath returns the pointer to the last-written character and

NOT the pointer to the first character!

Get executable file path

Use fplGetExecutableFilePath() to retrieve the full-path to your current executable.

On a POSIX based system this will most likely return something like "/some/path/../my_application"

On a Win32 based system this will most likely return something like "c:\Some\Path\..\MyApplication.exe"

Example:

// Get executable file path
char exeFilePath[];
(&exeFilePath, (exeFilePath));

// Get executable directory path
char appPath[];
if ((exeFilePath, &appPath, (appPath)) != ) {
    // ... Do something with appPath
}

Note: There is no guarantee that this path ends with a trailing path separator, such as

/ on POSIX or

\ on Win32! If needed use

fplEnforcePathSeparator to always enforce a path separator.

The name of the executable is always included in the path and will contain the file extension if there is one.

Warning: The return value of

fplExtractFilePath returns the pointer to the last-written character and

NOT the pointer to the first character!

Directory Traversing

FPL provides a powerful and easy directory traversal API, to find either files, directories, or both using a wildcard matching system.

Finding files by wildcard

Use fplDirectoryListBegin() to start finding files in a path.

If this function succeeds, the result for the first match is written into the fplFileEntry structure.

After this you repeatedly call fplDirectoryListNext(), to get the next match into the fplFileEntry structure - until the function returns false.

Example:

const char *sourcePath = ...
fplFileEntry fileEntry;
size_t fileCount = 0;

// Find all .so files (For-loop style)
fileCount = 0;
for(bool hasEntry = (sourcePath, "*.so", &entry); hasEntry; hasEntry = (&entry)) {
    // ... do something with entry.name
    ++fileCount;
}

// Find all .so files (While style)
fileCount = 0;
if ((sourcePath, "*.so", &entry)) {
    // The first file was found
    // ... do something with entry.name
    ++fileCount;

    // Loop until no file is found
    while ((&entry)) {
        // ... do something with entry.name
        ++fileCount;
    }
}

// Find all .so files (For-loop style, break out after reaching a limit of maximum allowed files)
size_t maxFileCount = ...
fileCount = 0;
for(bool hasEntry = (sourcePath, "*.so", &entry); hasEntry; hasEntry = (&entry)) {
    if (fileCount < maxFileCount) {
        // ... do something with entry.name
    } else {
        // Release resources, when we exit out the iteration
        (&entry);
        break;
    }
    ++fileCount;
}

Note: When

fplDirectoryListBegin() or

fplDirectoryListNext() does not find any match, the internal resources are released automatically.

Warning: If you manually stop the iteration, please call

fplDirectoryListEnd() to release its internal resources - otherwise you may leak memory!

Recursively get all files in a directory

There is no recursion support built-in in FPL, but you can easily make one using fplDirectoryListBegin() .

Just iterate through the file entries, which are already explained here: Finding files by wildcard

You can check fplFileEntry::type ,to check for either a fplFileEntryType_Directory or a fplFileEntryType_File type to start a recursion or not.

Example:

// Some existing awesome file-list container api
typedef struct file_list_t {
    size_t capacity;
    size_t count;
    char **items;
} file_list_t;
void init_file_list(file_list_t *outList);
void free_file_list(file_list_t *outList);
void push_file_list_item(file_list_t *outList, const char *item);

static void GetFilesFromDirectory(const char *rootPath, const bool recursive, file_list_t *outList) {
    fplEntry entry;
    for(bool hasEntry = (rootPath, "*", &entry); hasEntry; hasEntry = (&entry)) {
        char path[];
        (path, (path), 2, rootPath, entry.name);
        if (entry.type ==  && recursive) {
            GetFilesFromDirectory(path, true, outList);
        } else if (entry.type == ) {
            push_file_list_item(outList, path);
        }
    }
    return(result);
}

int main(int argc, char **argv) {
    if (argc < 2) {
        return 1;
    }
    const char *rootPath = argv[1];
    file_list_t outFileList;
    init_file_list(&outFileList);
    GetFilesFromDirectory(rootPath, true, &outFileList);
    // ... do something with our file list
    free_file_list(&outFileList);
    return 0;
}

Final Platform Layer

Pages

Topics

Data Structures

Clone this wiki locally