diff --git a/R/path.R b/R/path.R index 8dc557ef..72bc2f21 100644 --- a/R/path.R +++ b/R/path.R @@ -60,7 +60,7 @@ NULL #' path("foo", letters[1:3], ext = "txt") path <- function(..., ext = "") { args <- list(...) - assert_recyclable(args) + assert_recyclable(c(args, list(ext))) path_tidy(.Call(fs_path_, lapply(args, function(x) enc2utf8(as.character(x))), ext)) } diff --git a/src/path.cc b/src/path.cc index 354a75dc..979e8148 100644 --- a/src/path.cc +++ b/src/path.cc @@ -35,6 +35,9 @@ extern "C" SEXP fs_path_(SEXP paths, SEXP ext_sxp) { R_xlen_t max_col = Rf_xlength(paths); char buf[PATH_MAX]; char* b = buf; + if (max_col == 0) { + return Rf_allocVector(STRSXP, 0); + } for (R_xlen_t c = 0; c < max_col; ++c) { R_xlen_t len = Rf_xlength(VECTOR_ELT(paths, c)); if (len == 0) { @@ -45,7 +48,12 @@ extern "C" SEXP fs_path_(SEXP paths, SEXP ext_sxp) { } } - const char* ext = CHAR(STRING_ELT(ext_sxp, 0)); + R_xlen_t ext_len = Rf_xlength(ext_sxp); + if (ext_len == 0) { + return Rf_allocVector(STRSXP, 0); + } else if (ext_len > max_row) { + max_row = ext_len; + } SEXP out = PROTECT(Rf_allocVector(STRSXP, max_row)); for (R_xlen_t r = 0; r < max_row; ++r) { @@ -81,6 +89,7 @@ extern "C" SEXP fs_path_(SEXP paths, SEXP ext_sxp) { if (has_na) { SET_STRING_ELT(out, r, NA_STRING); } else { + const char* ext = CHAR(STRING_ELT(ext_sxp, r % ext_len)); if (strlen(ext) > 0) { *b++ = '.'; strcpy(b, ext); diff --git a/tests/testthat/test-path.R b/tests/testthat/test-path.R index 95069d58..66709c0b 100644 --- a/tests/testthat/test-path.R +++ b/tests/testthat/test-path.R @@ -68,6 +68,20 @@ describe("path", { ) expect_error(path(c("foo", "qux", "foo2"), c("bar", "baz")), "Arguments must have consistent lengths", class = "invalid_argument") + + expect_equal(path(ext = character()), fs_path(character())) + expect_equal(path("foo", ext = character()), fs_path(character())) + expect_equal(path("foo", ext = "bar"), fs_path("foo.bar")) + expect_equal( + path("foo", ext = c("bar", "baz")), + fs_path(c("foo.bar", "foo.baz")) + ) + expect_equal( + path(c("foo", "qux"), ext = c("bar", "baz")), + fs_path(c("foo.bar", "qux.baz")) + ) + + expect_error(path(c("foo", "qux", "foo2"), ext = c("bar", "baz")), "Arguments must have consistent lengths", class = "invalid_argument") }) })