diff options
| author | Lars Ingebrigtsen | 2021-07-24 17:22:43 +0200 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2021-07-24 17:22:43 +0200 |
| commit | b4543dfa9e72deeee607ffa9396a680c51a00968 (patch) | |
| tree | 09493193d03f4961a8007c709f1b8a8598ac26d6 /src | |
| parent | 8cd66a3170b4117d3cbcdce7a09837e3c2ea0e43 (diff) | |
| download | emacs-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.c | 116 |
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 | ||
| 752 | DEFUN ("directory-append", Fdirectory_append, Sdirectory_append, 2, 2, 0, | 752 | DEFUN ("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. |
| 754 | DIRECTORY may or may not end with a slash -- the return value from | 754 | COMPONENTS must be a list of strings. DIRECTORY or the non-final |
| 755 | this function will be the same. */) | 755 | elements in COMPONENTS may or may not end with a slash -- if they don't |
| 756 | (Lisp_Object directory, Lisp_Object file) | 756 | end with a slash, a slash will be inserted before contatenating. |
| 757 | usage: (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 | ||