From: Lars Ingebrigtsen Date: Sun, 25 Jul 2021 06:00:50 +0000 (+0200) Subject: Allow empty elements in directory-append X-Git-Tag: emacs-28.0.90~1708 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=aa9cba658768aba4da1b74ffb33d9962ffff5756;p=emacs.git Allow empty elements in directory-append * doc/lispref/files.texi (Directory Names): Document it. * src/fileio.c (Fdirectory_append): Allow empty elements. --- diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index 804cef292ee..e7a0ad2d06c 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi @@ -2355,7 +2355,9 @@ didn't end with a slash. @end group @end example -A zero-length directory or component is not allowed. +A @var{directory} or components that are @code{nil} or the empty +string are ignored---they are filtered out first and do not affect the +results in any way. This is almost the same as using @code{concat}, but @var{dirname} (and the non-final components) may or may not end with slash characters, diff --git a/src/fileio.c b/src/fileio.c index d6b3e7bca40..3d8b082a59c 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -751,14 +751,14 @@ For that reason, you should normally use `make-temp-file' instead. */) DEFUN ("directory-append", Fdirectory_append, Sdirectory_append, 1, MANY, 0, doc: /* Append COMPONENTS to DIRECTORY and return the resulting string. -COMPONENTS must be strings. +Elements in COMPONENTS must be a string or nil. DIRECTORY or the non-final elements in COMPONENTS may or may not end with a slash -- if they don't end with a slash, a slash will be inserted before contatenating. usage: (record DIRECTORY &rest COMPONENTS) */) (ptrdiff_t nargs, Lisp_Object *args) { - ptrdiff_t chars = 0, bytes = 0, multibytes = 0; + ptrdiff_t chars = 0, bytes = 0, multibytes = 0, eargs = 0; Lisp_Object *elements = args; Lisp_Object result; ptrdiff_t i; @@ -768,9 +768,13 @@ usage: (record DIRECTORY &rest COMPONENTS) */) for (i = 0; i < nargs; i++) { Lisp_Object arg = args[i]; + /* Skip empty and nil elements. */ + if (NILP (arg)) + continue; CHECK_STRING (arg); if (SCHARS (arg) == 0) - xsignal1 (Qfile_error, build_string ("Empty file name")); + continue; + eargs++; /* Multibyte and non-ASCII. */ if (STRING_MULTIBYTE (arg) && SCHARS (arg) != SBYTES (arg)) multibytes++; @@ -789,25 +793,41 @@ usage: (record DIRECTORY &rest COMPONENTS) */) } /* Convert if needed. */ - if (multibytes != 0 && multibytes != nargs) + if ((multibytes != 0 && multibytes != nargs) + || eargs != nargs) { - elements = xmalloc (nargs * sizeof *elements); + int j = 0; + elements = xmalloc (eargs * sizeof *elements); bytes = 0; + chars = 0; + + /* Filter out nil/"". */ for (i = 0; i < nargs; i++) { Lisp_Object arg = args[i]; + if (!NILP (arg) && SCHARS (arg) != 0) + elements[j++] = arg; + } + + for (i = 0; i < eargs; i++) + { + Lisp_Object arg = elements[i]; /* Use multibyte or all-ASCII strings as is. */ - if (STRING_MULTIBYTE (arg) || string_ascii_p (arg)) - elements[i] = arg; - else + if (!STRING_MULTIBYTE (arg) && !string_ascii_p (arg)) elements[i] = Fstring_to_multibyte (arg); arg = elements[i]; /* We have to recompute the number of bytes. */ - if (i == nargs - 1 + if (i == eargs - 1 || IS_DIRECTORY_SEP (*(SSDATA (arg) + SBYTES (arg) - 1))) - bytes += SBYTES (arg); + { + bytes += SBYTES (arg); + chars += SCHARS (arg); + } else - bytes += SBYTES (arg) + 1; + { + bytes += SBYTES (arg) + 1; + chars += SCHARS (arg) + 1; + } } } @@ -821,13 +841,13 @@ usage: (record DIRECTORY &rest COMPONENTS) */) /* Copy over the data. */ char *p = SSDATA (result); - for (i = 0; i < nargs; i++) + for (i = 0; i < eargs; i++) { Lisp_Object arg = elements[i]; memcpy (p, SSDATA (arg), SBYTES (arg)); p += SBYTES (arg); /* The last element shouldn't have a slash added at the end. */ - if (i < nargs - 1 && !IS_DIRECTORY_SEP (*(p - 1))) + if (i < eargs - 1 && !IS_DIRECTORY_SEP (*(p - 1))) *p++ = DIRECTORY_SEP; } diff --git a/test/src/fileio-tests.el b/test/src/fileio-tests.el index 73a7775279a..b1288f943e3 100644 --- a/test/src/fileio-tests.el +++ b/test/src/fileio-tests.el @@ -175,8 +175,11 @@ Also check that an encoding error can appear in a symlink." (aset string 2 255) (should (not (multibyte-string-p string))) (should (equal (directory-append "fóo" string) "fóo/aa\377aa"))) - (should-error (directory-append "foo" "")) - (should-error (directory-append "" "bar")) - (should-error (directory-append "" ""))) + (should (equal (directory-append "foo") "foo")) + (should (equal (directory-append "foo/") "foo/")) + (should (equal (directory-append "foo" "") "foo")) + (should (equal (directory-append "foo" "" "" "" nil) "foo")) + (should (equal (directory-append "" "bar") "bar")) + (should (equal (directory-append "" "") ""))) ;;; fileio-tests.el ends here