{"id":19016171,"url":"https://github.com/fosskers/filepaths","last_synced_at":"2026-01-05T22:19:14.023Z","repository":{"id":218900760,"uuid":"747663052","full_name":"fosskers/filepaths","owner":"fosskers","description":"Modern and consistent filepath manipulation for Common Lisp.","archived":false,"fork":false,"pushed_at":"2025-02-15T10:24:12.000Z","size":50,"stargazers_count":28,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-15T11:26:47.507Z","etag":null,"topics":["common-lisp"],"latest_commit_sha":null,"homepage":"","language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fosskers.png","metadata":{"files":{"readme":"README.org","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-24T11:50:20.000Z","updated_at":"2025-02-15T10:23:57.000Z","dependencies_parsed_at":"2024-11-08T19:42:30.433Z","dependency_job_id":"856a444b-e97d-4903-bbec-357ed28eaa96","html_url":"https://github.com/fosskers/filepaths","commit_stats":null,"previous_names":["fosskers/filepaths"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fosskers%2Ffilepaths","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fosskers%2Ffilepaths/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fosskers%2Ffilepaths/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fosskers%2Ffilepaths/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fosskers","download_url":"https://codeload.github.com/fosskers/filepaths/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240059494,"owners_count":19741668,"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":["common-lisp"],"created_at":"2024-11-08T19:41:32.684Z","updated_at":"2026-01-05T22:19:14.015Z","avatar_url":"https://github.com/fosskers.png","language":"Common Lisp","readme":"#+title: filepaths\n\nInspired by [[https://github.com/vindarel/cl-str][str]], this library offers modern and consistent filepath manipulation\nfor Common Lisp.\n\nIt addresses three main issues found with the status quo, namely:\n\n- Centrality: Functionality is spread across the standard library and =uiop=.\n- Completeness: A number of common operations found in newer languages are missing entirely.\n- Clarity: Function names are often unintuitive.\n\nThe =filepaths= library solves these issues by offering functions commonly found\nelsewhere while naming them what you'd generally expect them to be. For\ninstance:\n\n#+begin_src lisp :exports both\n(filepaths:join \"/home/you/code\" \"common-lisp\" \"hello.lisp\")\n#+end_src\n\n#+RESULTS:\n: #P\"/home/you/code/common-lisp/hello.lisp\"\n\nThere are many more functions available.\n\nNote that this library supports both Unix and Windows, but doesn't offer\nfunctions for communicating with the filesystem to test if files exist, etc.\n\n* Table of Contents :TOC_5_gh:noexport:\n- [[#compatibility][Compatibility]]\n- [[#installation][Installation]]\n- [[#usage][Usage]]\n  - [[#structural-tests][Structural Tests]]\n    - [[#root-empty][root?, empty?]]\n    - [[#absolute-relative][absolute?, relative?]]\n    - [[#starts-with-ends-with][starts-with?, ends-with?]]\n    - [[#directory][directory?]]\n  - [[#construction][Construction]]\n    - [[#join][join]]\n  - [[#component-access][Component Access]]\n    - [[#base-with-base][base, with-base]]\n    - [[#name-with-name][name, with-name]]\n    - [[#parent-with-parent][parent, with-parent]]\n    - [[#extension-with-extension-add-extension-drop-extension][extension, with-extension, add-extension, drop-extension]]\n  - [[#conversion][Conversion]]\n    - [[#components-from-list][components, from-list]]\n    - [[#ensure-directory-ensure-string-ensure-path][ensure-directory, ensure-string, ensure-path]]\n    - [[#to-string-from-string][to-string, from-string]]\n  - [[#conditions][Conditions]]\n- [[#see-also][See Also]]\n\n* Compatibility\n\n| Compiler | ~**.json~ | Verbatum ~..~ | Unicode Paths |\n|----------+---------+-------------+---------------|\n| SBCL     | Yes     | Yes         | Yes           |\n| ECL      | [[https://gitlab.com/embeddable-common-lisp/ecl/-/issues/751][No]]      | Yes         | Yes           |\n| ABCL     | Yes     | [[https://github.com/armedbear/abcl/issues/672][No]]          | Yes           |\n| CMUCL    | Yes     | Yes         | Yes           |\n| CCL      | Yes     | [[https://github.com/Clozure/ccl/issues/477][No]]          | Yes           |\n| Clasp    | [[https://github.com/clasp-developers/clasp/issues/1594][No]]      | Yes         | Yes (2.7)     |\n| Allegro  | Yes     | No          | Yes           |\n\n* Installation\n\nThis library is available on [[https://ultralisp.org/projects/fosskers/filepaths][Ultralisp]]. It uses only standard library functions\nand has no external dependencies.\n\n* Usage\n\nIt is recommended that you import this library with the nickname =path= or =p=,\nalthough the usage examples further down all use the full name, =filepaths=.\n\n#+begin_src lisp\n(:local-nicknames (:p :filepaths))\n#+end_src\n\nNote that nearly every function here can be passed either a =pathname= or a\n=string=.\n\n** Structural Tests\n\n*** root?, empty?\n\n=root?=: Is the given PATH the root directory?\n\n#+begin_src lisp :exports both\n(filepaths:root? #p\"/\")\n#+end_src\n\n#+RESULTS:\n: T\n\n=empty?=: Is the given PATH an empty string?\n\n#+begin_src lisp :exports both\n(filepaths:empty? #p\"\")\n#+end_src\n\n#+RESULTS:\n: T\n\n*** absolute?, relative?\n\n=absolute?=: Yields T when the given PATH is a full, absolute path.\n\n#+begin_src lisp :exports both\n(filepaths:absolute? \"/home/colin/foo.txt\")\n#+end_src\n\n#+RESULTS:\n: T\n\n=relative?=: Yields T when the given PATH is a relative one.\n\n#+begin_src lisp :exports both\n(filepaths:relative? #p\"bar/foo.txt\")\n#+end_src\n\n#+RESULTS:\n: T\n\n*** starts-with?, ends-with?\n\n=starts-with?=: Are the initial components of a PATH some BASE?\n\n#+begin_src lisp :exports both\n(filepaths:starts-with? #p\"/foo/bar/baz/zing.json\" \"/foo/bar\")\n#+end_src\n\n#+RESULTS:\n: T\n\n=ends-with?=: Are the final components of a PATH some given CHILD?\n\n#+begin_src lisp :exports both\n(filepaths:ends-with? #p\"/foo/bar/baz/zing.json\" \"baz/zing.json\")\n#+end_src\n\n#+RESULTS:\n: T\n\n*** directory?\n\n=directory?=: Yields T if the PATH represents a directory. It only tests for\nstructure; the filesystem isn't probed.\n\n#+begin_src lisp :exports both\n(filepaths:directory? #p\"/foo/bar/\")\n#+end_src\n\n#+RESULTS:\n: T\n\n#+begin_src lisp :exports both\n(filepaths:directory? #p\"/foo/bar/baz.txt\")\n#+end_src\n\n#+RESULTS:\n: NIL\n\n** Construction\n\n*** join\n\n=join=: Combine one or more components together.\n\n#+begin_src lisp :exports both\n(filepaths:join \"/foo\" \"bar\" \"baz\" \"test.json\")\n#+end_src\n\n#+RESULTS:\n: #P\"/foo/bar/baz/test.json\"\n\nThe arguments can already be partial paths.\n\n#+begin_src lisp :exports both\n(filepaths:join #p\"/bar/baz/\" #p\"foo.json\")\n#+end_src\n\n#+RESULTS:\n: #P\"/bar/baz/foo.json\"\n\n** Component Access\n\n*** base, with-base\n\n =base=: The non-extension, non-directory portion of the filename of a PATH.\n\n#+begin_src lisp :exports both\n(filepaths:base #p\"/foo/bar/baz.txt\")\n#+end_src\n\n#+RESULTS:\n: baz\n\n=with-base=: Swap the base portion of a PATH with a NEW one. Yields a new path object.\n\n#+begin_src lisp :exports both\n(filepaths:with-base #p\"/foo/bar/baz.txt\" \"jack\")\n#+end_src\n\n#+RESULTS:\n: #P\"/foo/bar/jack.txt\"\n\n*** name, with-name\n\n=name=: The filename of a PATH with no other directory components.\n\n#+begin_src lisp :exports both\n(filepaths:name #p\"/foo/bar/baz.txt\")\n#+end_src\n\n#+RESULTS:\n: baz.txt\n\n=with-name=: Swap the filename portion of a PATH with a NEW one. Yields a new path object.\n\n#+begin_src lisp :exports both\n(filepaths:with-name #p\"/foo/bar/baz.txt\" \"jack.json\")\n#+end_src\n\n#+RESULTS:\n: #P\"/foo/bar/jack.json\"\n\n*** parent, with-parent\n\n=parent=: Yield PATH without its final component, if there is one.\n\n#+begin_src lisp :exports both\n(filepaths:parent #p\"/foo/bar/baz.txt\")\n#+end_src\n\n#+RESULTS:\n: #P\"/foo/bar/\"\n\n=with-parent=: Swap the parent portion of a PATH.\n\n#+begin_src lisp :exports both\n(filepaths:with-parent #p\"/foo/bar/baz.json\" #p\"/zing\")\n#+end_src\n\n#+RESULTS:\n: #P\"/zing/baz.json\"\n\n*** extension, with-extension, add-extension, drop-extension\n\n=extension=: The extension of a given PATH.\n\n#+begin_src lisp :exports both\n(filepaths:extension #p\"/foo/bar.json\")\n#+end_src\n\n#+RESULTS:\n: json\n\n=with-extension=: Swap the entire extension of a given PATH. Yields a new path object.\n\n#+begin_src lisp :exports both\n(filepaths:with-extension #p\"/foo/bar/baz.txt\" \"json\")\n#+end_src\n\n#+RESULTS:\n: #P\"/foo/bar/baz.json\"\n\n\n=add-extension=: Add an extension to the given path, even if it already has one.\n\n#+begin_src lisp :exports both\n(filepaths:add-extension #p\"/foo/bar/baz.txt\" \"zip\")\n#+end_src\n\n#+RESULTS:\n: #P\"/foo/bar/baz.txt.zip\"\n\n=drop-extension=: Remove an extension from a PATH.\n\n#+begin_src lisp :exports both\n(filepaths:drop-extension #p\"/foo/bar/baz.json\")\n#+end_src\n\n#+RESULTS:\n: #P\"/foo/bar/baz\"\n\n#+begin_src lisp :exports both\n(filepaths:drop-extension #p\"/foo/bar/baz.json.zip\")\n#+end_src\n\n#+RESULTS:\n: #P\"/foo/bar/baz.json\"\n\n** Conversion\n\n*** components, from-list\n\n=components=: Every component of a PATH broken up as a list.\n\n#+begin_src lisp :results verbatim :exports both\n(filepaths:components #p\"/foo/bar/baz.json\")\n#+end_src\n\n#+RESULTS:\n: (\"/\" \"foo\" \"bar\" \"baz.json\")\n\n=from-list=: Given a LIST of path components, construct a proper pathname object.\n\n#+begin_src lisp :exports both\n(filepaths:from-list '(\"foo\" \"bar\" \"baz\"))\n#+end_src\n\n#+RESULTS:\n: #P\"foo/bar/baz\"\n\n#+begin_src lisp :exports both\n(filepaths:from-list (filepaths:components \"/foo/bar/baz/file.txt\"))\n#+end_src\n\n#+RESULTS:\n: #P\"/foo/bar/baz/file.txt\"\n\n*** ensure-directory, ensure-string, ensure-path\n\n=ensure-directory=: If a given PATH doesn't end in a path separator, add one.\n\n#+begin_src lisp :exports both\n(filepaths:ensure-directory #p\"/foo/bar/baz\")\n#+end_src\n\n#+RESULTS:\n: #P\"/foo/bar/baz/\"\n\n=ensure-string=: A PATH is definitely a string after this.\n\n#+begin_src lisp :results verbatim :exports both\n(type-of (filepaths:ensure-string #p\"/foo/bar\"))\n#+end_src\n\n#+RESULTS:\n: (SIMPLE-BASE-STRING 8)\n\n=ensure-path=: A PATH is definitely a pathname after this.\n\n#+begin_src lisp :exports both\n(type-of (filepaths:ensure-path \"/foo/bar\"))\n#+end_src\n\n#+RESULTS:\n: PATHNAME\n\n*** to-string, from-string\n\n=to-string=: Convert a PATH object into string.\n\n#+begin_src lisp :exports both\n(filepaths:to-string #p\"/foo/bar/baz.txt\")\n#+end_src\n\n#+RESULTS:\n: /foo/bar/baz.txt\n\n=from-string=: Convert a string into a proper filepath object.\n\n#+begin_src lisp :exports both\n(filepaths:from-string \"/foo/bar/baz.txt\")\n#+end_src\n\n#+RESULTS:\n: #P\"/foo/bar/baz.txt\"\n\n** Conditions\n\nFor certain functions in this library, it is not appropriate to return =nil= in\ncase of an error. The following conditions are thus triggered under certain\ncircumstances:\n\n- =no-filename=\n- =empty-path=\n- =root-no-parent=\n\n* See Also\n\n- https://shinmera.github.io/pathname-utils/\n- https://codeberg.org/fourier/ppath\n- https://quickdocs.org/uiop\n","funding_links":[],"categories":["Online editors ##"],"sub_categories":["Third-party APIs"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffosskers%2Ffilepaths","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffosskers%2Ffilepaths","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffosskers%2Ffilepaths/lists"}