aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Ingebrigtsen2021-07-25 08:00:50 +0200
committerLars Ingebrigtsen2021-07-25 08:00:50 +0200
commitaa9cba658768aba4da1b74ffb33d9962ffff5756 (patch)
tree39d07450a850e5b46687f18c367e64e723cbb7a3
parent03f844249cb15a8380d09041a537803c933a2769 (diff)
downloademacs-aa9cba658768aba4da1b74ffb33d9962ffff5756.tar.gz
emacs-aa9cba658768aba4da1b74ffb33d9962ffff5756.zip
Allow empty elements in directory-append
* doc/lispref/files.texi (Directory Names): Document it. * src/fileio.c (Fdirectory_append): Allow empty elements.
-rw-r--r--doc/lispref/files.texi4
-rw-r--r--src/fileio.c46
-rw-r--r--test/src/fileio-tests.el9
3 files changed, 42 insertions, 17 deletions
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.
2355@end group 2355@end group
2356@end example 2356@end example
2357 2357
2358A zero-length directory or component is not allowed. 2358A @var{directory} or components that are @code{nil} or the empty
2359string are ignored---they are filtered out first and do not affect the
2360results in any way.
2359 2361
2360This is almost the same as using @code{concat}, but @var{dirname} (and 2362This is almost the same as using @code{concat}, but @var{dirname} (and
2361the non-final components) may or may not end with slash characters, 2363the 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. */)
751 751
752DEFUN ("directory-append", Fdirectory_append, Sdirectory_append, 1, MANY, 0, 752DEFUN ("directory-append", Fdirectory_append, Sdirectory_append, 1, MANY, 0,
753 doc: /* Append COMPONENTS to DIRECTORY and return the resulting string. 753 doc: /* Append COMPONENTS to DIRECTORY and return the resulting string.
754COMPONENTS must be strings. 754Elements in COMPONENTS must be a string or nil.
755DIRECTORY or the non-final elements in COMPONENTS may or may not end 755DIRECTORY or the non-final elements in COMPONENTS may or may not end
756with a slash -- if they don't end with a slash, a slash will be 756with a slash -- if they don't end with a slash, a slash will be
757inserted before contatenating. 757inserted before contatenating.
758usage: (record DIRECTORY &rest COMPONENTS) */) 758usage: (record DIRECTORY &rest COMPONENTS) */)
759 (ptrdiff_t nargs, Lisp_Object *args) 759 (ptrdiff_t nargs, Lisp_Object *args)
760{ 760{
761 ptrdiff_t chars = 0, bytes = 0, multibytes = 0; 761 ptrdiff_t chars = 0, bytes = 0, multibytes = 0, eargs = 0;
762 Lisp_Object *elements = args; 762 Lisp_Object *elements = args;
763 Lisp_Object result; 763 Lisp_Object result;
764 ptrdiff_t i; 764 ptrdiff_t i;
@@ -768,9 +768,13 @@ usage: (record DIRECTORY &rest COMPONENTS) */)
768 for (i = 0; i < nargs; i++) 768 for (i = 0; i < nargs; i++)
769 { 769 {
770 Lisp_Object arg = args[i]; 770 Lisp_Object arg = args[i];
771 /* Skip empty and nil elements. */
772 if (NILP (arg))
773 continue;
771 CHECK_STRING (arg); 774 CHECK_STRING (arg);
772 if (SCHARS (arg) == 0) 775 if (SCHARS (arg) == 0)
773 xsignal1 (Qfile_error, build_string ("Empty file name")); 776 continue;
777 eargs++;
774 /* Multibyte and non-ASCII. */ 778 /* Multibyte and non-ASCII. */
775 if (STRING_MULTIBYTE (arg) && SCHARS (arg) != SBYTES (arg)) 779 if (STRING_MULTIBYTE (arg) && SCHARS (arg) != SBYTES (arg))
776 multibytes++; 780 multibytes++;
@@ -789,25 +793,41 @@ usage: (record DIRECTORY &rest COMPONENTS) */)
789 } 793 }
790 794
791 /* Convert if needed. */ 795 /* Convert if needed. */
792 if (multibytes != 0 && multibytes != nargs) 796 if ((multibytes != 0 && multibytes != nargs)
797 || eargs != nargs)
793 { 798 {
794 elements = xmalloc (nargs * sizeof *elements); 799 int j = 0;
800 elements = xmalloc (eargs * sizeof *elements);
795 bytes = 0; 801 bytes = 0;
802 chars = 0;
803
804 /* Filter out nil/"". */
796 for (i = 0; i < nargs; i++) 805 for (i = 0; i < nargs; i++)
797 { 806 {
798 Lisp_Object arg = args[i]; 807 Lisp_Object arg = args[i];
808 if (!NILP (arg) && SCHARS (arg) != 0)
809 elements[j++] = arg;
810 }
811
812 for (i = 0; i < eargs; i++)
813 {
814 Lisp_Object arg = elements[i];
799 /* Use multibyte or all-ASCII strings as is. */ 815 /* Use multibyte or all-ASCII strings as is. */
800 if (STRING_MULTIBYTE (arg) || string_ascii_p (arg)) 816 if (!STRING_MULTIBYTE (arg) && !string_ascii_p (arg))
801 elements[i] = arg;
802 else
803 elements[i] = Fstring_to_multibyte (arg); 817 elements[i] = Fstring_to_multibyte (arg);
804 arg = elements[i]; 818 arg = elements[i];
805 /* We have to recompute the number of bytes. */ 819 /* We have to recompute the number of bytes. */
806 if (i == nargs - 1 820 if (i == eargs - 1
807 || IS_DIRECTORY_SEP (*(SSDATA (arg) + SBYTES (arg) - 1))) 821 || IS_DIRECTORY_SEP (*(SSDATA (arg) + SBYTES (arg) - 1)))
808 bytes += SBYTES (arg); 822 {
823 bytes += SBYTES (arg);
824 chars += SCHARS (arg);
825 }
809 else 826 else
810 bytes += SBYTES (arg) + 1; 827 {
828 bytes += SBYTES (arg) + 1;
829 chars += SCHARS (arg) + 1;
830 }
811 } 831 }
812 } 832 }
813 833
@@ -821,13 +841,13 @@ usage: (record DIRECTORY &rest COMPONENTS) */)
821 841
822 /* Copy over the data. */ 842 /* Copy over the data. */
823 char *p = SSDATA (result); 843 char *p = SSDATA (result);
824 for (i = 0; i < nargs; i++) 844 for (i = 0; i < eargs; i++)
825 { 845 {
826 Lisp_Object arg = elements[i]; 846 Lisp_Object arg = elements[i];
827 memcpy (p, SSDATA (arg), SBYTES (arg)); 847 memcpy (p, SSDATA (arg), SBYTES (arg));
828 p += SBYTES (arg); 848 p += SBYTES (arg);
829 /* The last element shouldn't have a slash added at the end. */ 849 /* The last element shouldn't have a slash added at the end. */
830 if (i < nargs - 1 && !IS_DIRECTORY_SEP (*(p - 1))) 850 if (i < eargs - 1 && !IS_DIRECTORY_SEP (*(p - 1)))
831 *p++ = DIRECTORY_SEP; 851 *p++ = DIRECTORY_SEP;
832 } 852 }
833 853
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."
175 (aset string 2 255) 175 (aset string 2 255)
176 (should (not (multibyte-string-p string))) 176 (should (not (multibyte-string-p string)))
177 (should (equal (directory-append "fóo" string) "fóo/aa\377aa"))) 177 (should (equal (directory-append "fóo" string) "fóo/aa\377aa")))
178 (should-error (directory-append "foo" "")) 178 (should (equal (directory-append "foo") "foo"))
179 (should-error (directory-append "" "bar")) 179 (should (equal (directory-append "foo/") "foo/"))
180 (should-error (directory-append "" ""))) 180 (should (equal (directory-append "foo" "") "foo"))
181 (should (equal (directory-append "foo" "" "" "" nil) "foo"))
182 (should (equal (directory-append "" "bar") "bar"))
183 (should (equal (directory-append "" "") "")))
181 184
182;;; fileio-tests.el ends here 185;;; fileio-tests.el ends here