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
void
init_buffer (int initialized)
{
- char *pwd;
Lisp_Object temp;
- ptrdiff_t len;
#ifdef USE_MMAP_FOR_BUFFERS
if (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)
{
{
/* 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. */
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
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),
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);
/* 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;
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;
exit (0);
}
+ emacs_wd = emacs_get_current_dir_name ();
+
if (argmatch (argv, argc, "-chdir", "--chdir", 4, &ch_to_dir, &skip_args))
{
#ifdef WINDOWSNT
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)
{
#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 */
#include <acl.h>
#include <allocator.h>
#include <careadlinkat.h>
+#include <dosname.h>
#include <fsusage.h>
#include <stat-time.h>
#include <tempname.h>
{
Lisp_Object tem;
- if (!(newdir = egetenv ("HOME")))
- newdir = newdirlim = "";
+ newdir = get_homedir ();
nm++;
#ifdef WINDOWSNT
if (newdir[0])
#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))
{
}
#endif
\f
-/* If /~ or // appears, discard everything through first slash. */
static bool
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)
{
/* 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,
/* 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
}
-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. */
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;
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);
}
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);
}
}
(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)))