Skip to content

Commit

Permalink
realpath(1): implement --relative-to=DIR
Browse files Browse the repository at this point in the history
  • Loading branch information
q66 committed Sep 12, 2024
1 parent ea374ad commit 722f369
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src.custom/realpath/realpath.1
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ and a normalized path is printed.
The
.Ar path
is normalized logically, without resolving any symlinks.
.It Fl -relative-to Ar DIR
Print result relative to
.Ar DIR .
.It Fl q, -quiet
Most error messages are suppressed. The return failure code is still issued.
.It Fl z, -zero
Expand Down
33 changes: 33 additions & 0 deletions src.custom/realpath/realpath.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <err.h>

enum {
ARG_RELATIVE_TO = 127,
ARG_HELP,
ARG_VERSION,
};
Expand All @@ -48,6 +49,8 @@ static bool canonical_missing = false;
static bool quiet = false;
static bool strip = false;
static bool zero = false;
static bool isrel = false;
static fs::path relpath{};

extern char const *__progname;

Expand Down Expand Up @@ -86,6 +89,7 @@ static void usage_realpath(bool help) {
" -e, --canonicalize-existing all components must exist (default)\n"
" -m, --canonicalize-missing no component must exist\n"
" -s, --strip, --no-symlinks don't expand symlinks, only normalize\n"
" --relative-to=DIR print result reslative to DIR\n"
" -q, --quiet suppress most error messages\n"
" -z, --zero delimit with NUL instead of newline\n"
" --help print this help message\n"
Expand Down Expand Up @@ -119,6 +123,9 @@ static bool do_realpath(fs::path sp, bool newl) {
return false;
}
/* process */
if (isrel) {
np = np.lexically_relative(relpath);
}
auto cstr = np.c_str();
write(STDOUT_FILENO, cstr, std::strlen(cstr));
if (!newl) {
Expand Down Expand Up @@ -243,13 +250,16 @@ static int realpath_main(int argc, char **argv) {
{"canonicalize-missing", no_argument, 0, 'm'},
{"strip", no_argument, 0, 's'},
{"no-symlinks", no_argument, 0, 's'},
{"relative-to", required_argument, 0, ARG_RELATIVE_TO},
{"quiet", no_argument, 0, 'q'},
{"zero", no_argument, 0, 'z'},
{"help", no_argument, 0, ARG_HELP},
{"version", no_argument, 0, ARG_VERSION},
{nullptr, 0, 0, 0},
};

char const *relstr = nullptr;

for (;;) {
int oind = 0;
auto c = getopt_long(argc, argv, "emqsz", lopts, &oind);
Expand All @@ -270,6 +280,11 @@ static int realpath_main(int argc, char **argv) {
case 'z':
zero = true;
break;
case ARG_RELATIVE_TO:
isrel = true;
relstr = optarg;
relpath = relstr;
break;
case ARG_HELP:
usage_realpath(true);
return 0;
Expand All @@ -282,6 +297,24 @@ static int realpath_main(int argc, char **argv) {
}
}

if (isrel) {
std::error_code ec{};
/* make absolute according to current rules */
if (strip && relpath.is_relative()) {
relpath = (fs::current_path(ec) / relpath).lexically_normal();
} else if (strip) {
relpath = relpath.lexically_normal();
} else if (canonical_missing) {
relpath = fs::weakly_canonical(relpath, ec);
} else {
relpath = fs::canonical(relpath, ec);
}
if (ec) {
errno = ec.value();
err(1, "%s", relstr);
}
}

if (optind >= argc) {
std::error_code ec{};
/* no arguments */
Expand Down

0 comments on commit 722f369

Please sign in to comment.