Expanding Tilde-based paths

Q: How do I expand a tilde-based path to its full path value?

A: Some situations may arise where you would like to expand a tilde-based relevant path into a resolved, absolute path. For example "~/" might resolve to "/Users/johndoe". Here are examples on how to accomplish this task under each development environment (Objective-C, POSIX and Core Foundation).

Note: Don't abuse this code. Use the code for resolving paths that have been generated at runtime or specified by user input. You should avoid storing paths. Use aliases for persistent storage of file/directory locations (unless your application requires path-tracking semantics).

Listing 1: Objective-C (result is autoreleased)

NSString *result = [@"~/Desktop" stringByExpandingTildeInPath];

Listing 2: POSIX (caller responsible for freeing result)

#include <glob.h>

char* CreatePathByExpandingTildePath(char* path)
{
    glob_t globbuf;
    char **v;
    char *expandedPath = NULL, *result = NULL;

    assert(path != NULL);

    if (glob(path, GLOB_TILDE, NULL, &globbuf) == 0) //success
    {
        v = globbuf.gl_pathv; //list of matched pathnames
        expandedPath = v[0]; //number of matched pathnames, gl_pathc == 1

        result = (char*)calloc(1, strlen(expandedPath) + 1); //the extra char is for the null-termination
        if(result)
            strncpy(result, expandedPath, strlen(expandedPath) + 1); //copy the null-termination as well

        globfree(&globbuf);
    }

    return result;
}

Listing 3: Core Foundation (caller responsible for releasing result)

#include <glob.h>

// This is the POSIX version in listing 2.
char*  CreatePathByExpandingTildePath(char* path);

CFStringRef CreateCFStringByExpandingTildePath(CFStringRef path)
{
    char pcPath[PATH_MAX];
    char *pcResult = NULL;
    CFStringRef result = NULL;

    if (CFStringGetFileSystemRepresentation(path, pcPath, PATH_MAX)) //CFString to CString
    {
        pcResult = CreatePathByExpandingTildePath(pcPath); //call the POSIX version
        if (pcResult)
        {
            result = CFStringCreateWithCString(NULL, pcResult, kCFStringEncodingUTF8); //CString to CFString
            free(pcResult); //free the memory allocated in CreatePathByExpandingTildePath()
        }
    }

    return result;
}

Document Revision History

Date Notes
2008-09-08 Simplified POSIX and CF versions using the embedded glob() function.
2007-09-24 Demonstrates how to resolve tilde-based relevant paths.

Posted: 2008-09-08


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.