aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Ingebrigtsen2021-07-24 17:22:43 +0200
committerLars Ingebrigtsen2021-07-24 17:22:43 +0200
commitb4543dfa9e72deeee607ffa9396a680c51a00968 (patch)
tree09493193d03f4961a8007c709f1b8a8598ac26d6 /src
parent8cd66a3170b4117d3cbcdce7a09837e3c2ea0e43 (diff)
downloademacs-b4543dfa9e72deeee607ffa9396a680c51a00968.tar.gz
emacs-b4543dfa9e72deeee607ffa9396a680c51a00968.zip
Extend directory-append to take an arbitrary number of components
* doc/lispref/files.texi (Directory Names): Document it. * lisp/emacs-lisp/shortdoc.el (file-name): Add new example. * src/fileio.c (Fdirectory_append): Change the function to take an arbitrary number of components.
Diffstat (limited to 'src')
-rw-r--r--src/fileio.c116
1 files changed, 79 insertions, 37 deletions
diff --git a/src/fileio.c b/src/fileio.c
index 277da48315e..a4f08383776 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -749,48 +749,90 @@ For that reason, you should normally use `make-temp-file' instead. */)
749 empty_unibyte_string, Qnil); 749 empty_unibyte_string, Qnil);
750} 750}
751 751
752DEFUN ("directory-append", Fdirectory_append, Sdirectory_append, 2, 2, 0, 752DEFUN ("directory-append", Fdirectory_append, Sdirectory_append, 1, MANY, 0,
753 doc: /* Return FILE (a string) appended to DIRECTORY (a string). 753 doc: /* Append COMPONENTS to DIRECTORY and return the resulting string.
754DIRECTORY may or may not end with a slash -- the return value from 754COMPONENTS must be a list of strings. DIRECTORY or the non-final
755this function will be the same. */) 755elements in COMPONENTS may or may not end with a slash -- if they don't
756 (Lisp_Object directory, Lisp_Object file) 756end with a slash, a slash will be inserted before contatenating.
757usage: (record DIRECTORY &rest COMPONENTS) */)
758 (ptrdiff_t nargs, Lisp_Object *args)
757{ 759{
758 USE_SAFE_ALLOCA; 760 ptrdiff_t chars = 0, bytes = 0, multibytes = 0;
759 char *p; 761 Lisp_Object *elements = args;
760 762 Lisp_Object result;
761 CHECK_STRING (file); 763 ptrdiff_t i;
762 CHECK_STRING (directory); 764
765 /* First go through the list to check the types and see whether
766 they're all of the same multibytedness. */
767 for (i = 0; i < nargs; i++)
768 {
769 Lisp_Object arg = args[i];
770 CHECK_STRING (arg);
771 if (SCHARS (arg) == 0)
772 xsignal1 (Qfile_error, build_string ("Empty file name"));
773 /* Multibyte and non-ASCII. */
774 if (STRING_MULTIBYTE (arg) && SCHARS (arg) != SBYTES (arg))
775 multibytes++;
776 /* We're not adding a slash to the final part. */
777 if (i == nargs - 1
778 || IS_DIRECTORY_SEP (*(SSDATA (arg) + SBYTES (arg) - 1)))
779 {
780 bytes += SBYTES (arg);
781 chars += SCHARS (arg);
782 }
783 else
784 {
785 bytes += SBYTES (arg) + 1;
786 chars += SCHARS (arg) + 1;
787 }
788 }
763 789
764 if (SCHARS (file) == 0) 790 /* Convert if needed. */
765 xsignal1 (Qfile_error, build_string ("Empty file name")); 791 if (multibytes != 0 && multibytes != nargs)
792 {
793 elements = xmalloc (nargs * sizeof *elements);
794 bytes = 0;
795 for (i = 0; i < nargs; i++)
796 {
797 Lisp_Object arg = args[i];
798 if (STRING_MULTIBYTE (arg))
799 elements[i] = arg;
800 else
801 elements[i] = make_multibyte_string (SSDATA (arg), SCHARS (arg),
802 SCHARS (arg));
803 arg = elements[i];
804 /* We have to recompute the number of bytes. */
805 if (i == nargs - 1
806 || IS_DIRECTORY_SEP (*(SSDATA (arg) + SBYTES (arg) - 1)))
807 bytes += SBYTES (arg);
808 else
809 bytes += SBYTES (arg) + 1;
810 }
811 }
766 812
767 if (SCHARS (directory) == 0) 813 /* Allocate an empty string. */
768 return file; 814 if (multibytes == 0)
815 result = make_uninit_string (chars);
816 else
817 result = make_uninit_multibyte_string (chars, bytes);
818 /* Null-terminate the string. */
819 *(SSDATA (result) + SBYTES (result)) = 0;
769 820
770 /* Make the strings the same multibytedness. */ 821 /* Copy over the data. */
771 if (STRING_MULTIBYTE (file) != STRING_MULTIBYTE (directory)) 822 char *p = SSDATA (result);
823 for (i = 0; i < nargs; i++)
772 { 824 {
773 if (STRING_MULTIBYTE (file)) 825 Lisp_Object arg = elements[i];
774 directory = make_multibyte_string (SSDATA (directory), 826 memcpy (p, SSDATA (arg), SBYTES (arg));
775 SCHARS (directory), 827 p += SBYTES (arg);
776 SCHARS (directory)); 828 /* The last element shouldn't have a slash added at the end. */
777 else 829 if (i < nargs -1 && !IS_DIRECTORY_SEP (*(p - 1)))
778 file = make_multibyte_string (SSDATA (file), 830 *p++ = DIRECTORY_SEP;
779 SCHARS (file), 831 }
780 SCHARS (file)); 832
781 } 833 if (multibytes != 0 && multibytes != nargs)
782 834 xfree (elements);
783 /* Allocate enough extra space in case we need to put a slash in 835
784 there. */
785 p = SAFE_ALLOCA (SBYTES (file) + SBYTES (directory) + 2);
786 ptrdiff_t offset = SBYTES (directory);
787 memcpy (p, SSDATA (directory), offset);
788 if (! IS_DIRECTORY_SEP (p[offset - 1]))
789 p[offset++] = DIRECTORY_SEP;
790 memcpy (p + offset, SSDATA (file), SBYTES (file));
791 p[offset + SBYTES (file)] = 0;
792 Lisp_Object result = build_string (p);
793 SAFE_FREE ();
794 return result; 836 return result;
795} 837}
796 838