mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-30 12:21:25 -08:00
Act like POSIX sh if $HOME is relative
POSIX says sh ~/foo should act like $HOME/foo even if $HOME is
relative, so be consistent with that (Bug#33255).
* admin/merge-gnulib (GNULIB_MODULES): Add dosname.
* src/buffer.c (init_buffer): Use emacs_wd to get
initial working directory with slash appended if needed.
(default-directory): Say it must be absolute.
* src/emacs.c (emacs_wd): New global variable.
(init_cmdargs): Dir arg is now char const *.
(main): Set emacs_wd.
* src/emacs.c (main) [NS_IMPL_COCOA]:
* src/fileio.c (Fexpand_file_name):
Use get_homedir instead of egetenv ("HOME").
* src/fileio.c: Include dosname.h, for IS_ABSOLUTE_FILE_NAME.
(splice_dir_file, get_homedir): New functions.
* src/xrdb.c (gethomedir): Remove. All callers changed
to use get_homedir and splice_dir_file.
* test/src/fileio-tests.el (fileio-tests--relative-HOME): New test.
This commit is contained in:
parent
ce1fb157e8
commit
900276502f
7 changed files with 103 additions and 74 deletions
|
|
@ -30,7 +30,7 @@ GNULIB_MODULES='
|
|||
careadlinkat close-stream
|
||||
count-leading-zeros count-one-bits count-trailing-zeros
|
||||
crypto/md5-buffer crypto/sha1-buffer crypto/sha256-buffer crypto/sha512-buffer
|
||||
d-type diffseq dtoastr dtotimespec dup2
|
||||
d-type diffseq dosname dtoastr dtotimespec dup2
|
||||
environ execinfo explicit_bzero faccessat
|
||||
fcntl fcntl-h fdatasync fdopendir
|
||||
filemode filevercmp flexmember fpieee fstatat fsusage fsync
|
||||
|
|
|
|||
28
src/buffer.c
28
src/buffer.c
|
|
@ -5268,9 +5268,7 @@ init_buffer_once (void)
|
|||
void
|
||||
init_buffer (int initialized)
|
||||
{
|
||||
char *pwd;
|
||||
Lisp_Object temp;
|
||||
ptrdiff_t len;
|
||||
|
||||
#ifdef USE_MMAP_FOR_BUFFERS
|
||||
if (initialized)
|
||||
|
|
@ -5324,7 +5322,7 @@ init_buffer (int initialized)
|
|||
if (NILP (BVAR (&buffer_defaults, enable_multibyte_characters)))
|
||||
Fset_buffer_multibyte (Qnil);
|
||||
|
||||
pwd = emacs_get_current_dir_name ();
|
||||
char const *pwd = emacs_wd;
|
||||
|
||||
if (!pwd)
|
||||
{
|
||||
|
|
@ -5336,22 +5334,16 @@ init_buffer (int initialized)
|
|||
{
|
||||
/* Maybe this should really use some standard subroutine
|
||||
whose definition is filename syntax dependent. */
|
||||
len = strlen (pwd);
|
||||
if (!(IS_DIRECTORY_SEP (pwd[len - 1])))
|
||||
{
|
||||
/* Grow buffer to add directory separator and '\0'. */
|
||||
pwd = realloc (pwd, len + 2);
|
||||
if (!pwd)
|
||||
fatal ("get_current_dir_name: %s\n", strerror (errno));
|
||||
pwd[len] = DIRECTORY_SEP;
|
||||
pwd[len + 1] = '\0';
|
||||
len++;
|
||||
}
|
||||
ptrdiff_t len = strlen (pwd);
|
||||
bool add_slash = ! IS_DIRECTORY_SEP (pwd[len - 1]);
|
||||
|
||||
/* At this moment, we still don't know how to decode the directory
|
||||
name. So, we keep the bytes in unibyte form so that file I/O
|
||||
routines correctly get the original bytes. */
|
||||
bset_directory (current_buffer, make_unibyte_string (pwd, len));
|
||||
Lisp_Object dirname = make_unibyte_string (pwd, len + add_slash);
|
||||
if (add_slash)
|
||||
SSET (dirname, len, DIRECTORY_SEP);
|
||||
bset_directory (current_buffer, dirname);
|
||||
|
||||
/* Add /: to the front of the name
|
||||
if it would otherwise be treated as magic. */
|
||||
|
|
@ -5372,8 +5364,6 @@ init_buffer (int initialized)
|
|||
|
||||
temp = get_minibuffer (0);
|
||||
bset_directory (XBUFFER (temp), BVAR (current_buffer, directory));
|
||||
|
||||
free (pwd);
|
||||
}
|
||||
|
||||
/* Similar to defvar_lisp but define a variable whose value is the
|
||||
|
|
@ -5706,8 +5696,8 @@ visual lines rather than logical lines. See the documentation of
|
|||
DEFVAR_PER_BUFFER ("default-directory", &BVAR (current_buffer, directory),
|
||||
Qstringp,
|
||||
doc: /* Name of default directory of current buffer.
|
||||
It should be a directory name (as opposed to a directory file-name).
|
||||
On GNU and Unix systems, directory names end in a slash `/'.
|
||||
It should be an absolute directory name; on GNU and Unix systems,
|
||||
these names start with `/' or `~' and end with `/'.
|
||||
To interactively change the default directory, use command `cd'. */);
|
||||
|
||||
DEFVAR_PER_BUFFER ("auto-fill-function", &BVAR (current_buffer, auto_fill_function),
|
||||
|
|
|
|||
20
src/emacs.c
20
src/emacs.c
|
|
@ -204,6 +204,9 @@ HANDLE w32_daemon_event;
|
|||
char **initial_argv;
|
||||
int initial_argc;
|
||||
|
||||
/* The name of the working directory, or NULL if this info is unavailable. */
|
||||
char const *emacs_wd;
|
||||
|
||||
static void sort_args (int argc, char **argv);
|
||||
static void syms_of_emacs (void);
|
||||
|
||||
|
|
@ -406,7 +409,7 @@ terminate_due_to_signal (int sig, int backtrace_limit)
|
|||
/* Code for dealing with Lisp access to the Unix command line. */
|
||||
|
||||
static void
|
||||
init_cmdargs (int argc, char **argv, int skip_args, char *original_pwd)
|
||||
init_cmdargs (int argc, char **argv, int skip_args, char const *original_pwd)
|
||||
{
|
||||
int i;
|
||||
Lisp_Object name, dir, handler;
|
||||
|
|
@ -694,7 +697,7 @@ main (int argc, char **argv)
|
|||
char *ch_to_dir = 0;
|
||||
|
||||
/* If we use --chdir, this records the original directory. */
|
||||
char *original_pwd = 0;
|
||||
char const *original_pwd = 0;
|
||||
|
||||
/* Record (approximately) where the stack begins. */
|
||||
stack_bottom = (char *) &stack_bottom_variable;
|
||||
|
|
@ -794,6 +797,8 @@ main (int argc, char **argv)
|
|||
exit (0);
|
||||
}
|
||||
|
||||
emacs_wd = emacs_get_current_dir_name ();
|
||||
|
||||
if (argmatch (argv, argc, "-chdir", "--chdir", 4, &ch_to_dir, &skip_args))
|
||||
{
|
||||
#ifdef WINDOWSNT
|
||||
|
|
@ -804,13 +809,14 @@ main (int argc, char **argv)
|
|||
filename_from_ansi (ch_to_dir, newdir);
|
||||
ch_to_dir = newdir;
|
||||
#endif
|
||||
original_pwd = emacs_get_current_dir_name ();
|
||||
if (chdir (ch_to_dir) != 0)
|
||||
{
|
||||
fprintf (stderr, "%s: Can't chdir to %s: %s\n",
|
||||
argv[0], ch_to_dir, strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
original_pwd = emacs_wd;
|
||||
emacs_wd = emacs_get_current_dir_name ();
|
||||
}
|
||||
|
||||
#if defined (HAVE_SETRLIMIT) && defined (RLIMIT_STACK) && !defined (CYGWIN)
|
||||
|
|
@ -1289,21 +1295,21 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
|
|||
{
|
||||
#ifdef NS_IMPL_COCOA
|
||||
/* Started from GUI? */
|
||||
/* FIXME: Do the right thing if getenv returns NULL, or if
|
||||
/* FIXME: Do the right thing if get_homedir returns "", or if
|
||||
chdir fails. */
|
||||
if (! inhibit_window_system && ! isatty (STDIN_FILENO) && ! ch_to_dir)
|
||||
chdir (getenv ("HOME"));
|
||||
chdir (get_homedir ());
|
||||
if (skip_args < argc)
|
||||
{
|
||||
if (!strncmp (argv[skip_args], "-psn", 4))
|
||||
{
|
||||
skip_args += 1;
|
||||
if (! ch_to_dir) chdir (getenv ("HOME"));
|
||||
if (! ch_to_dir) chdir (get_homedir ());
|
||||
}
|
||||
else if (skip_args+1 < argc && !strncmp (argv[skip_args+1], "-psn", 4))
|
||||
{
|
||||
skip_args += 2;
|
||||
if (! ch_to_dir) chdir (getenv ("HOME"));
|
||||
if (! ch_to_dir) chdir (get_homedir ());
|
||||
}
|
||||
}
|
||||
#endif /* COCOA */
|
||||
|
|
|
|||
62
src/fileio.c
62
src/fileio.c
|
|
@ -96,6 +96,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include <acl.h>
|
||||
#include <allocator.h>
|
||||
#include <careadlinkat.h>
|
||||
#include <dosname.h>
|
||||
#include <fsusage.h>
|
||||
#include <stat-time.h>
|
||||
#include <tempname.h>
|
||||
|
|
@ -1093,8 +1094,7 @@ the root directory. */)
|
|||
{
|
||||
Lisp_Object tem;
|
||||
|
||||
if (!(newdir = egetenv ("HOME")))
|
||||
newdir = newdirlim = "";
|
||||
newdir = get_homedir ();
|
||||
nm++;
|
||||
#ifdef WINDOWSNT
|
||||
if (newdir[0])
|
||||
|
|
@ -1109,7 +1109,7 @@ the root directory. */)
|
|||
#endif
|
||||
tem = build_string (newdir);
|
||||
newdirlim = newdir + SBYTES (tem);
|
||||
/* `egetenv' may return a unibyte string, which will bite us
|
||||
/* get_homedir may return a unibyte string, which will bite us
|
||||
if we expect the directory to be multibyte. */
|
||||
if (multibyte && !STRING_MULTIBYTE (tem))
|
||||
{
|
||||
|
|
@ -1637,7 +1637,6 @@ See also the function `substitute-in-file-name'.")
|
|||
}
|
||||
#endif
|
||||
|
||||
/* If /~ or // appears, discard everything through first slash. */
|
||||
static bool
|
||||
file_name_absolute_p (const char *filename)
|
||||
{
|
||||
|
|
@ -1650,6 +1649,61 @@ file_name_absolute_p (const char *filename)
|
|||
);
|
||||
}
|
||||
|
||||
/* Put into BUF the concatenation of DIR and FILE, with an intervening
|
||||
directory separator if needed. Return a pointer to the null byte
|
||||
at the end of the concatenated string. */
|
||||
char *
|
||||
splice_dir_file (char *buf, char const *dir, char const *file)
|
||||
{
|
||||
char *e = stpcpy (buf, dir);
|
||||
*e = DIRECTORY_SEP;
|
||||
e += ! (buf < e && IS_DIRECTORY_SEP (e[-1]));
|
||||
return stpcpy (e, file);
|
||||
}
|
||||
|
||||
/* Get the home directory, an absolute file name. Return the empty
|
||||
string on failure. The returned value does not survive garbage
|
||||
collection, calls to this function, or calls to the getpwnam class
|
||||
of functions. */
|
||||
char const *
|
||||
get_homedir (void)
|
||||
{
|
||||
char const *home = egetenv ("HOME");
|
||||
if (!home)
|
||||
{
|
||||
static char const *userenv[] = {"LOGNAME", "USER"};
|
||||
struct passwd *pw = NULL;
|
||||
for (int i = 0; i < ARRAYELTS (userenv); i++)
|
||||
{
|
||||
char *user = egetenv (userenv[i]);
|
||||
if (user)
|
||||
{
|
||||
pw = getpwnam (user);
|
||||
if (pw)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!pw)
|
||||
pw = getpwuid (getuid ());
|
||||
if (pw)
|
||||
home = pw->pw_dir;
|
||||
if (!home)
|
||||
return "";
|
||||
}
|
||||
if (IS_ABSOLUTE_FILE_NAME (home))
|
||||
return home;
|
||||
if (!emacs_wd)
|
||||
error ("$HOME is relative to unknown directory");
|
||||
static char *ahome;
|
||||
static ptrdiff_t ahomesize;
|
||||
ptrdiff_t ahomelenbound = strlen (emacs_wd) + 1 + strlen (home) + 1;
|
||||
if (ahomesize <= ahomelenbound)
|
||||
ahome = xpalloc (ahome, &ahomesize, ahomelenbound + 1 - ahomesize, -1, 1);
|
||||
splice_dir_file (ahome, emacs_wd, home);
|
||||
return ahome;
|
||||
}
|
||||
|
||||
/* If /~ or // appears, discard everything through first slash. */
|
||||
static char *
|
||||
search_embedded_absfilename (char *nm, char *endp)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4061,6 +4061,8 @@ extern void syms_of_marker (void);
|
|||
|
||||
/* Defined in fileio.c. */
|
||||
|
||||
extern char *splice_dir_file (char *, char const *, char const *);
|
||||
extern char const *get_homedir (void);
|
||||
extern Lisp_Object expand_and_dir_to_file (Lisp_Object);
|
||||
extern Lisp_Object write_region (Lisp_Object, Lisp_Object, Lisp_Object,
|
||||
Lisp_Object, Lisp_Object, Lisp_Object,
|
||||
|
|
@ -4185,6 +4187,7 @@ extern void syms_of_frame (void);
|
|||
/* Defined in emacs.c. */
|
||||
extern char **initial_argv;
|
||||
extern int initial_argc;
|
||||
extern char const *emacs_wd;
|
||||
#if defined (HAVE_X_WINDOWS) || defined (HAVE_NS)
|
||||
extern bool display_arg;
|
||||
#endif
|
||||
|
|
|
|||
54
src/xrdb.c
54
src/xrdb.c
|
|
@ -202,35 +202,6 @@ magic_db (const char *string, ptrdiff_t string_len, const char *class,
|
|||
}
|
||||
|
||||
|
||||
static char *
|
||||
gethomedir (void)
|
||||
{
|
||||
struct passwd *pw;
|
||||
char *ptr;
|
||||
char *copy;
|
||||
|
||||
if ((ptr = getenv ("HOME")) == NULL)
|
||||
{
|
||||
if ((ptr = getenv ("LOGNAME")) != NULL
|
||||
|| (ptr = getenv ("USER")) != NULL)
|
||||
pw = getpwnam (ptr);
|
||||
else
|
||||
pw = getpwuid (getuid ());
|
||||
|
||||
if (pw)
|
||||
ptr = pw->pw_dir;
|
||||
}
|
||||
|
||||
if (ptr == NULL)
|
||||
return xstrdup ("/");
|
||||
|
||||
ptrdiff_t len = strlen (ptr);
|
||||
copy = xmalloc (len + 2);
|
||||
strcpy (copy + len, "/");
|
||||
return memcpy (copy, ptr, len);
|
||||
}
|
||||
|
||||
|
||||
/* Find the first element of SEARCH_PATH which exists and is readable,
|
||||
after expanding the %-escapes. Return 0 if we didn't find any, and
|
||||
the path name of the one we found otherwise. */
|
||||
|
|
@ -316,12 +287,11 @@ get_user_app (const char *class)
|
|||
if (! db)
|
||||
{
|
||||
/* Check in the home directory. This is a bit of a hack; let's
|
||||
hope one's home directory doesn't contain any %-escapes. */
|
||||
char *home = gethomedir ();
|
||||
hope one's home directory doesn't contain ':' or '%'. */
|
||||
char const *home = get_homedir ();
|
||||
db = search_magic_path (home, class, "%L/%N");
|
||||
if (! db)
|
||||
db = search_magic_path (home, class, "%N");
|
||||
xfree (home);
|
||||
}
|
||||
|
||||
return db;
|
||||
|
|
@ -346,10 +316,9 @@ get_user_db (Display *display)
|
|||
else
|
||||
{
|
||||
/* Use ~/.Xdefaults. */
|
||||
char *home = gethomedir ();
|
||||
ptrdiff_t homelen = strlen (home);
|
||||
char *filename = xrealloc (home, homelen + sizeof xdefaults);
|
||||
strcpy (filename + homelen, xdefaults);
|
||||
char const *home = get_homedir ();
|
||||
char *filename = xmalloc (strlen (home) + 1 + sizeof xdefaults);
|
||||
splice_dir_file (filename, home, xdefaults);
|
||||
db = XrmGetFileDatabase (filename);
|
||||
xfree (filename);
|
||||
}
|
||||
|
|
@ -380,13 +349,12 @@ get_environ_db (void)
|
|||
if (STRINGP (system_name))
|
||||
{
|
||||
/* Use ~/.Xdefaults-HOSTNAME. */
|
||||
char *home = gethomedir ();
|
||||
ptrdiff_t homelen = strlen (home);
|
||||
ptrdiff_t filenamesize = (homelen + sizeof xdefaults
|
||||
+ 1 + SBYTES (system_name));
|
||||
p = filename = xrealloc (home, filenamesize);
|
||||
lispstpcpy (stpcpy (stpcpy (filename + homelen, xdefaults), "-"),
|
||||
system_name);
|
||||
char const *home = get_homedir ();
|
||||
p = filename = xmalloc (strlen (home) + 1 + sizeof xdefaults
|
||||
+ 1 + SBYTES (system_name));
|
||||
char *e = splice_dir_file (p, home, xdefaults);
|
||||
*e++ = '/';
|
||||
lispstpcpy (e, system_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -95,3 +95,11 @@ Also check that an encoding error can appear in a symlink."
|
|||
(should (equal (file-name-as-directory "d:/abc/") "d:/abc/"))
|
||||
(should (equal (file-name-as-directory "D:\\abc/") "d:/abc/"))
|
||||
(should (equal (file-name-as-directory "D:/abc//") "d:/abc//")))
|
||||
|
||||
(ert-deftest fileio-tests--relative-HOME ()
|
||||
"Test that expand-file-name works even when HOME is relative."
|
||||
(let ((old-home (getenv "HOME")))
|
||||
(setenv "HOME" "a/b/c")
|
||||
(should (equal (expand-file-name "~/foo")
|
||||
(expand-file-name "a/b/c/foo")))
|
||||
(setenv "HOME" old-home)))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue