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:
parent
9ac6ff53b1
commit
5431a58e86
@ -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:
|
||||
|
4
etc/NEWS
4
etc/NEWS
@ -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,
|
||||
|
@ -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"
|
||||
|
46
src/fileio.c
46
src/fileio.c
@ -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);
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user