{"id":13730428,"url":"https://github.com/dlecocq/apathy","last_synced_at":"2026-04-04T20:16:24.422Z","repository":{"id":5385459,"uuid":"6573564","full_name":"dlecocq/apathy","owner":"dlecocq","description":"C++ Path Manipulation","archived":false,"fork":false,"pushed_at":"2017-01-06T13:58:28.000Z","size":149,"stargazers_count":45,"open_issues_count":2,"forks_count":10,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-08-04T02:09:33.572Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dlecocq.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-11-07T03:22:03.000Z","updated_at":"2024-03-15T19:33:18.000Z","dependencies_parsed_at":"2022-07-06T14:03:32.143Z","dependency_job_id":null,"html_url":"https://github.com/dlecocq/apathy","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dlecocq%2Fapathy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dlecocq%2Fapathy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dlecocq%2Fapathy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dlecocq%2Fapathy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dlecocq","download_url":"https://codeload.github.com/dlecocq/apathy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224695477,"owners_count":17354418,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T02:01:14.703Z","updated_at":"2026-04-04T20:16:24.409Z","avatar_url":"https://github.com/dlecocq.png","language":"C++","funding_links":[],"categories":["C++"],"sub_categories":[],"readme":"Apathy Path Manipulation\n========================\nI find myself occasionally needing to do path manipulation in C++, and while\n[Boost.Filesystem](http://www.boost.org/doc/libs/1_52_0/libs/filesystem/doc/index.htm)\nis a useful tool, my qualm with it is that it requires Boost to be installed\non the target system. For some cases, this is too large a requirement, and so\nI have often wanted this library.\n\nInstallation\n============\n`Apathy` is a header-only library, and so all you need to do is to include it\nin your code (this works particularly well with\n[git submodules](http://git-scm.com/book/en/Git-Tools-Submodules)):\n\n```C++\n#include \u003capathy/path.hpp\u003e\n```\n\nIt imports a single member `Path` in the `apathy` namespace.\n\nUsage\n=====\nMost of the path manipulators return a reference to the current path, so that\nthey can be chained:\n\n```C++\n/* Check if ./foo/bar exists */\nPath::cwd().relative(\"foo\").relative(\"bar\").exists();\n/* Make a sanitized absolute directory for ./foo///../a/b */\nPath(\"./foo///../a/b\").absolute().sanitize();\n```\n\nOperators\n=========\nPath objects support the operators `==`, `!=`, `\u003c\u003c` (which appends to the path)\nand `=`:\n\n```C++\n/* Makes sure they're exact matches */\nPath(\"./foo\") == \"./foo\";\nPath(\"./foo\") != \"foo\";\n\n/* Appends to the path */\nPath p(\"foo\");\np \u003c\u003c \"bar\" \u003c\u003c 5 \u003c\u003c 3.1459 \u003c\u003c Path(\"what\");\n```\n\nIn addition to these comparators, there's also an `equivalent` method that\nchecks whether the two paths refer to the same resource. To do so, copies of\nboth are made absolute and sanitized and then a strict string comparison is\nmade:\n\n```C++\n/* These are equivalent, but not equal */\nPath a(\"./foo////a/b/./d/../c\");\nPath b(\"foo/a/b/c\");\n\n/* These are true */\na.equivalent(b);\nb.equivalent(a);\n/* This is not */\na == b;\n```\n\nModifiers\n=========\nAll of these methods modify the path they're associated with, and return a\nreference to the modified path so that they can be chained:\n\n- `append` -- appends a path segment to the current path:\n\n```C++\n/* Create a path to foo/bar/baz\nPath p(\"foo\");\nstd::cout \u003c\u003c p.append(\"bar\").append(\"baz\").string() \u003c\u003c std::endl;\n/* Now p is \"foo/bar/baz\" */\n```\n\n- `relative` -- evaluates one path relative to another. If the second path is\n    an absolute path, then updates the object to point to that path:\n\n```C++\n/* Gives \"foo/bar/whiz\" */\nPath(\"foo\").relative(\"bar/whiz\");\n/* Gives \"/bar/whiz\" */\nPath(\"foo\").relative(\"/bar/whiz\");\n```\n\n- `up` -- move to the parent directory:\n    \n```C++\n/* Gives /foo/bar/ */\nPath(\"foo/bar/whiz\").up();\n```\n\n- `absolute` -- convert the path to an absolute path. If it's a relative path,\n    then it's evaluated relative to the current working directory:\n\n```C++\n/* Gives \u003ccwd\u003e/foo/bar */\nPath(\"foo/bar\").absolute();\n/* Gives /foo/bar */\nPath(\"/foo/bar\").absolute();\n```\n\n- `sanitize` -- clean up repeated separators, evaluate `..` and `.`. If `..` is\n    used to exceed the segments in a relative path, it is transformed into an\n    absolute path. Otherwise, if it was a relative path, it remains a relative\n    path afterwards:\n\n```C++\n/* Gives a/b/c/ */\nPath(\"foo/.././a////b/d/../c\");\n```\n\n- `directory` -- ensure the path has a trailing separator to indicate it's a\n    directory:\n\n```C++\n/* Gives a/b/c/ */\nPath(\"a/b/c\").directory();\n```\n\n- `trim` -- removes any trailing separators from the path:\n\n```C++\n/* Gives a/b/c */\nPath(\"a/b/c/////\").trim();\n```\n\nBreaking It Down\n================\nThere are a number of ways to get access to the various components of the path:\n\n- `filename` -- name of the file without any directories\n- `extension` -- get a string of the extension of the path (if any)\n- `stem` -- get a copy of the path without the extension\n- `split` -- each of the directories in the path\n\nCopiers\n=======\nWhile the modifiers change the instance itself and return a reference, some\nmethods return a modified copy of the instance, leaving the original unchanged:\n\n- `copy` -- an easy shorthand for creating a copy of the path object, since\n    it's common to chain methods. Consider:\n\n```C++\n/* I'd like to leave the original path unchanged */\nPath p(\"foo/bar\");\np.copy().absolute();\n\n/* Equivalent to... */\nPath(p).absolute();\n```\n\n- `parent` -- returns a new path pointing to the parent directory:\n\n```C++\n/* Points to foo/bar, leaving original unchanged */\nPath p(\"foo/bar/whiz\");\np.parent();\n```\n\nTests\n=====\nYou can run some simple checks about the path:\n\n- `is_absolute` -- if the path is an absolute path\n- `trailing_slash` -- if the path has a trailing slash\n\nAs well as get information about the filesystem:\n\n- `exists` -- returns true if path can successfully be `stat`-ed\n- `is_directory` -- returns true if the path exists and `S_ISDIR`\n- `is_file` -- returns true if the path exists and `S_ISREG`\n\nUtility Functions\n=================\nLastly, there are a number of utility functions for dealing with paths and the\nfilesystem:\n\n- `cwd` -- get a path that refers to the current working directory\n- `touch` -- update and make sure a file exists\n- `makedirs` -- attempt to recursively make a directory\n- `rmdirs` -- attempt to recursively remove a directory\n- `listdir` -- return a vector of all the paths in the provided directory\n\nRoadmap\n=======\nThe interface is a little bit in flux, but I now need this code in more than\none projects, so it was time for it to move into its own repository.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdlecocq%2Fapathy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdlecocq%2Fapathy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdlecocq%2Fapathy/lists"}