Home

Awesome

Apathy Path Manipulation

I find myself occasionally needing to do path manipulation in C++, and while Boost.Filesystem is a useful tool, my qualm with it is that it requires Boost to be installed on the target system. For some cases, this is too large a requirement, and so I have often wanted this library.

Installation

Apathy is a header-only library, and so all you need to do is to include it in your code (this works particularly well with git submodules):

#include <apathy/path.hpp>

It imports a single member Path in the apathy namespace.

Usage

Most of the path manipulators return a reference to the current path, so that they can be chained:

/* Check if ./foo/bar exists */
Path::cwd().relative("foo").relative("bar").exists();
/* Make a sanitized absolute directory for ./foo///../a/b */
Path("./foo///../a/b").absolute().sanitize();

Operators

Path objects support the operators ==, !=, << (which appends to the path) and =:

/* Makes sure they're exact matches */
Path("./foo") == "./foo";
Path("./foo") != "foo";

/* Appends to the path */
Path p("foo");
p << "bar" << 5 << 3.1459 << Path("what");

In addition to these comparators, there's also an equivalent method that checks whether the two paths refer to the same resource. To do so, copies of both are made absolute and sanitized and then a strict string comparison is made:

/* These are equivalent, but not equal */
Path a("./foo////a/b/./d/../c");
Path b("foo/a/b/c");

/* These are true */
a.equivalent(b);
b.equivalent(a);
/* This is not */
a == b;

Modifiers

All of these methods modify the path they're associated with, and return a reference to the modified path so that they can be chained:

/* Create a path to foo/bar/baz
Path p("foo");
std::cout << p.append("bar").append("baz").string() << std::endl;
/* Now p is "foo/bar/baz" */
/* Gives "foo/bar/whiz" */
Path("foo").relative("bar/whiz");
/* Gives "/bar/whiz" */
Path("foo").relative("/bar/whiz");
/* Gives /foo/bar/ */
Path("foo/bar/whiz").up();
/* Gives <cwd>/foo/bar */
Path("foo/bar").absolute();
/* Gives /foo/bar */
Path("/foo/bar").absolute();
/* Gives a/b/c/ */
Path("foo/.././a////b/d/../c");
/* Gives a/b/c/ */
Path("a/b/c").directory();
/* Gives a/b/c */
Path("a/b/c/////").trim();

Breaking It Down

There are a number of ways to get access to the various components of the path:

Copiers

While the modifiers change the instance itself and return a reference, some methods return a modified copy of the instance, leaving the original unchanged:

/* I'd like to leave the original path unchanged */
Path p("foo/bar");
p.copy().absolute();

/* Equivalent to... */
Path(p).absolute();
/* Points to foo/bar, leaving original unchanged */
Path p("foo/bar/whiz");
p.parent();

Tests

You can run some simple checks about the path:

As well as get information about the filesystem:

Utility Functions

Lastly, there are a number of utility functions for dealing with paths and the filesystem:

Roadmap

The interface is a little bit in flux, but I now need this code in more than one projects, so it was time for it to move into its own repository.