1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-12-01 08:17:38 +00:00

Add new function `directory-append'

* doc/lispref/files.texi (Directory Names): Document it, and
remove the concat-based file concatenation description.
* lisp/emacs-lisp/shortdoc.el (file-name): Add.  And add more
expand-file-name examples.

* src/fileio.c (Fdirectory_append): New function.
This commit is contained in:
Lars Ingebrigtsen 2021-07-24 13:30:58 +02:00
parent 9ac6ff53b1
commit 5431a58e86
5 changed files with 77 additions and 40 deletions

View File

@ -2343,49 +2343,21 @@ entirely of directory separators.
@end example
@end defun
Given a directory name, you can combine it with a relative file name
using @code{concat}:
@defun directory-append filename directory
Combine @var{filename} with @var{directory} by optionally putting a
slash in the middle.
@example
(concat @var{dirname} @var{relfile})
@group
(directory-append "/tmp" "foo")
@result{} "/tmp/foo"
@end group
@end example
@noindent
Be sure to verify that the file name is relative before doing that.
If you use an absolute file name, the results could be syntactically
invalid or refer to the wrong file.
If you want to use a directory file name in making such a
combination, you must first convert it to a directory name using
@code{file-name-as-directory}:
@example
(concat (file-name-as-directory @var{dirfile}) @var{relfile})
@end example
@noindent
Don't try concatenating a slash by hand, as in
@example
;;; @r{Wrong!}
(concat @var{dirfile} "/" @var{relfile})
@end example
@noindent
because this is not portable. Always use
@code{file-name-as-directory}.
To avoid the issues mentioned above, or if the @var{dirname} value
might be @code{nil} (for example, from an element of @code{load-path}),
use:
@example
(expand-file-name @var{relfile} @var{dirname})
@end example
However, @code{expand-file-name} expands leading @samp{~} in
@var{relfile}, which may not be what you want. @xref{File Name
Expansion}.
This is almost the same as using @code{concat}, but @var{dirname} may
or may not end with a slash character, and this function will not
double that character.
@end defun
To convert a directory name to its abbreviation, use this
function:

View File

@ -3120,6 +3120,10 @@ The former is now declared obsolete.
* Lisp Changes in Emacs 28.1
+++
*** New function 'directory-append'.
This appends a file name to a directory name and returns the result.
+++
*** New function 'split-string-shell-command'.
This splits a shell command string into separate components,

View File

@ -273,8 +273,15 @@ There can be any number of :example/:result elements."
:eval (file-relative-name "/tmp/foo" "/tmp"))
(make-temp-name
:eval (make-temp-name "/tmp/foo-"))
(directory-append
:eval (directory-append "/tmp/" "foo")
:eval (directory-append "/tmp" "foo")
:eval (directory-append "/tmp" "~"))
(expand-file-name
:eval (expand-file-name "foo" "/tmp/"))
:eval (expand-file-name "foo" "/tmp/")
:eval (expand-file-name "foo" "/tmp///")
:eval (expand-file-name "foo" "/tmp/foo/.././")
:eval (expand-file-name "~" "/tmp/"))
(substitute-in-file-name
:eval (substitute-in-file-name "$HOME/foo"))
"Directory Functions"

View File

@ -749,6 +749,51 @@ For that reason, you should normally use `make-temp-file' instead. */)
empty_unibyte_string, Qnil);
}
DEFUN ("directory-append", Fdirectory_append, Sdirectory_append, 2, 2, 0,
doc: /* Return FILE (a string) appended to DIRECTORY (a string).
DIRECTORY may or may not end with a slash -- the return value from
this function will be the same. */)
(Lisp_Object directory, Lisp_Object file)
{
USE_SAFE_ALLOCA;
char *p;
CHECK_STRING (file);
CHECK_STRING (directory);
if (SCHARS (file) == 0)
xsignal1 (Qfile_error, build_string ("Empty file name"));
if (SCHARS (directory) == 0)
return file;
/* Make the strings the same multibytedness. */
if (STRING_MULTIBYTE (file) != STRING_MULTIBYTE (directory))
{
if (STRING_MULTIBYTE (file))
directory = make_multibyte_string (SSDATA (directory),
SCHARS (directory),
SCHARS (directory));
else
file = make_multibyte_string (SSDATA (file),
SCHARS (file),
SCHARS (file));
}
/* Allocate enough extra space in case we need to put a slash in
there. */
p = SAFE_ALLOCA (SBYTES (file) + SBYTES (directory) + 2);
ptrdiff_t offset = SBYTES (directory);
memcpy (p, SSDATA (directory), offset);
if (! IS_DIRECTORY_SEP (p[offset - 1]))
p[offset++] = DIRECTORY_SEP;
memcpy (p + offset, SSDATA (file), SBYTES (file));
p[offset + SBYTES (file)] = 0;
Lisp_Object result = build_string (p);
SAFE_FREE ();
return result;
}
/* NAME must be a string. */
static bool
file_name_absolute_no_tilde_p (Lisp_Object name)
@ -6488,6 +6533,7 @@ This includes interactive calls to `delete-file' and
defsubr (&Sdirectory_file_name);
defsubr (&Smake_temp_file_internal);
defsubr (&Smake_temp_name);
defsubr (&Sdirectory_append);
defsubr (&Sexpand_file_name);
defsubr (&Ssubstitute_in_file_name);
defsubr (&Scopy_file);

View File

@ -160,4 +160,12 @@ Also check that an encoding error can appear in a symlink."
(should-error (file-exists-p "/foo\0bar")
:type 'wrong-type-argument))
(ert-deftest fileio-tests/directory-append ()
(should (equal (directory-append "foo" "bar") "foo/bar"))
(should (equal (directory-append "foo/" "bar") "foo/bar"))
(should (equal (directory-append "foo//" "bar") "foo//bar"))
(should-error (directory-append "foo" ""))
(should (equal (directory-append "" "bar") "bar"))
(should-error (directory-append "" "")))
;;; fileio-tests.el ends here