summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2018-11-13 09:29:14 -0800
committerPaul Eggert <eggert@cs.ucla.edu>2018-11-13 09:32:50 -0800
commit900276502fbb4dcabdabc5d7d24b4bc5645f2cf3 (patch)
tree4d6c17f5b3cea0f4d5dfbc7243eb6495269a7e56 /src
parentce1fb157e840fd292c3db4632831c4514a663890 (diff)
downloademacs-900276502fbb4dcabdabc5d7d24b4bc5645f2cf3.tar.gz
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.
Diffstat (limited to 'src')
-rw-r--r--src/buffer.c28
-rw-r--r--src/emacs.c20
-rw-r--r--src/fileio.c62
-rw-r--r--src/lisp.h3
-rw-r--r--src/xrdb.c54
5 files changed, 94 insertions, 73 deletions
diff --git a/src/buffer.c b/src/buffer.c
index ac2de7d19f2..90ef886b229 100644
--- a/src/buffer.c
+++ b/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),
diff --git a/src/emacs.c b/src/emacs.c
index 512174d562e..acb4959bfea 100644
--- a/src/emacs.c
+++ b/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 */
diff --git a/src/fileio.c b/src/fileio.c
index 7fb865809f5..e178c39fc18 100644
--- a/src/fileio.c
+++ b/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)
{
diff --git a/src/lisp.h b/src/lisp.h
index f8ffb33a641..7e7dba631f3 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -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
diff --git a/src/xrdb.c b/src/xrdb.c
index 4abf1ad84ed..87c2faf6598 100644
--- a/src/xrdb.c
+++ b/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);
}
}