From 50e9e580077869b2f2ced5916299bade6b4f4efd Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Mon, 1 Sep 2014 20:05:43 +0400 Subject: [PATCH] Avoid extra calls to strlen in filesystem I/O routines. * fileio.c (Fexpand_file_name): Avoid calls to strlen if the length of 'newdir' is known or may be precalculated. (file_accessible_directory_p): Prefer to pass Lisp_Object, not 'char *', and so use precalculated length. (Ffile_accessible_directory_p): * callproc.c (encode_current_directory, init_callproc): * charset.c (init_charset): * lread.c (load_path_check, load_path_default): Adjust users. * lisp.h (file_accessible_directory_p): Tweak prototype. --- src/ChangeLog | 13 +++++++++++++ src/callproc.c | 6 +++--- src/charset.c | 2 +- src/fileio.c | 48 ++++++++++++++++++++++++++++++++---------------- src/lisp.h | 2 +- src/lread.c | 2 +- 6 files changed, 51 insertions(+), 22 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 02435801d69..a5ec9c35efa 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,16 @@ +2014-09-01 Dmitry Antipov + + Avoid extra calls to strlen in filesystem I/O routines. + * fileio.c (Fexpand_file_name): Avoid calls to strlen if + the length of 'newdir' is known or may be precalculated. + (file_accessible_directory_p): Prefer to pass Lisp_Object, + not 'char *', and so use precalculated length. + (Ffile_accessible_directory_p): + * callproc.c (encode_current_directory, init_callproc): + * charset.c (init_charset): + * lread.c (load_path_check, load_path_default): Adjust users. + * lisp.h (file_accessible_directory_p): Tweak prototype. + 2014-09-01 Eli Zaretskii * w32proc.c (w32_compare_strings): Support "C" and "POSIX" diff --git a/src/callproc.c b/src/callproc.c index 2f68ea6f328..01008312155 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -129,7 +129,7 @@ encode_current_directory (void) if (STRING_MULTIBYTE (dir)) dir = ENCODE_FILE (dir); - if (! file_accessible_directory_p (SSDATA (dir))) + if (! file_accessible_directory_p (dir)) report_file_error ("Setting current directory", BVAR (current_buffer, directory)); @@ -1625,12 +1625,12 @@ init_callproc (void) #endif { tempdir = Fdirectory_file_name (Vexec_directory); - if (! file_accessible_directory_p (SSDATA (tempdir))) + if (! file_accessible_directory_p (tempdir)) dir_warning ("arch-dependent data dir", Vexec_directory); } tempdir = Fdirectory_file_name (Vdata_directory); - if (! file_accessible_directory_p (SSDATA (tempdir))) + if (! file_accessible_directory_p (tempdir)) dir_warning ("arch-independent data dir", Vdata_directory); sh = getenv ("SHELL"); diff --git a/src/charset.c b/src/charset.c index 341ac356aff..6964208137b 100644 --- a/src/charset.c +++ b/src/charset.c @@ -2298,7 +2298,7 @@ init_charset (void) { Lisp_Object tempdir; tempdir = Fexpand_file_name (build_string ("charsets"), Vdata_directory); - if (! file_accessible_directory_p (SSDATA (tempdir))) + if (! file_accessible_directory_p (tempdir)) { /* This used to be non-fatal (dir_warning), but it should not happen, and if it does sooner or later it will cause some diff --git a/src/fileio.c b/src/fileio.c index d9c7397c2de..d4929184cee 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -889,7 +889,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) bool collapse_newdir = 1; bool is_escaped = 0; #endif /* DOS_NT */ - ptrdiff_t length; + ptrdiff_t length, newdirlen; Lisp_Object handler, result, handled_name; bool multibyte; Lisp_Object hdir; @@ -1147,6 +1147,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) append it to the current working directory. */ newdir = 0; + newdirlen = -1; if (nm[0] == '~') /* prefix ~ */ { @@ -1171,10 +1172,12 @@ filesystem tree, not (expand-file-name ".." dirname). */) else #endif tem = build_string (newdir); + newdirlen = SBYTES (tem); if (multibyte && !STRING_MULTIBYTE (tem)) { hdir = DECODE_FILE (tem); newdir = SSDATA (hdir); + newdirlen = SBYTES (hdir); } #ifdef DOS_NT collapse_newdir = 0; @@ -1201,10 +1204,12 @@ filesystem tree, not (expand-file-name ".." dirname). */) bite us since we expect the directory to be multibyte. */ tem = build_string (newdir); + newdirlen = SBYTES (tem); if (multibyte && !STRING_MULTIBYTE (tem)) { hdir = DECODE_FILE (tem); newdir = SSDATA (hdir); + newdirlen = SBYTES (hdir); } nm = p; #ifdef DOS_NT @@ -1234,7 +1239,8 @@ filesystem tree, not (expand-file-name ".." dirname). */) Lisp_Object tem = build_string (adir); tem = DECODE_FILE (tem); - memcpy (adir, SSDATA (tem), SBYTES (tem) + 1); + newdirlen = SBYTES (tem); + memcpy (adir, SSDATA (tem), newdirlen + 1); } } if (!adir) @@ -1245,6 +1251,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) adir[1] = ':'; adir[2] = '/'; adir[3] = 0; + newdirlen = 3; } newdir = adir; } @@ -1265,11 +1272,13 @@ filesystem tree, not (expand-file-name ".." dirname). */) && !newdir) { newdir = SSDATA (default_directory); + newdirlen = SBYTES (default_directory); #ifdef DOS_NT /* Note if special escape prefix is present, but remove for now. */ if (newdir[0] == '/' && newdir[1] == ':') { is_escaped = 1; + newdirlen -= 2; newdir += 2; } #endif @@ -1305,14 +1314,14 @@ filesystem tree, not (expand-file-name ".." dirname). */) if (IS_DRIVE (newdir[0]) && IS_DEVICE_SEP (newdir[1])) { drive = (unsigned char) newdir[0]; + newdirlen -= 2; newdir += 2; } if (!IS_DIRECTORY_SEP (nm[0])) { - ptrdiff_t newlen = strlen (newdir); - char *tmp = alloca (newlen + file_name_as_directory_slop + char *tmp = alloca (newdirlen + file_name_as_directory_slop + strlen (nm) + 1); - file_name_as_directory (tmp, newdir, newlen, multibyte); + file_name_as_directory (tmp, newdir, newdirlen, multibyte); strcat (tmp, nm); nm = tmp; } @@ -1329,8 +1338,11 @@ filesystem tree, not (expand-file-name ".." dirname). */) Lisp_Object tem = build_string (adir); tem = DECODE_FILE (tem); - memcpy (adir, SSDATA (tem), SBYTES (tem) + 1); + newdirlen = SBYTES (tem); + memcpy (adir, SSDATA (tem), newdirlen + 1); } + else + newdirlen = strlen (aidr); newdir = adir; } @@ -1338,6 +1350,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) if (IS_DRIVE (newdir[0]) && IS_DEVICE_SEP (newdir[1])) { drive = newdir[0]; + newdirlen -= 2; newdir += 2; } @@ -1349,17 +1362,18 @@ filesystem tree, not (expand-file-name ".." dirname). */) if (IS_DIRECTORY_SEP (newdir[0]) && IS_DIRECTORY_SEP (newdir[1]) && !IS_DIRECTORY_SEP (newdir[2])) { - char *adir = strcpy (alloca (strlen (newdir) + 1), newdir); + char *adir = strcpy (alloca (newdirlen + 1), newdir); char *p = adir + 2; while (*p && !IS_DIRECTORY_SEP (*p)) p++; p++; while (*p && !IS_DIRECTORY_SEP (*p)) p++; *p = 0; newdir = adir; + newdirlen = strlen (adir); } else #endif - newdir = ""; + newdirlen = 0, newdir = ""; } } #endif /* DOS_NT */ @@ -1368,7 +1382,8 @@ filesystem tree, not (expand-file-name ".." dirname). */) { /* Ignore any slash at the end of newdir, unless newdir is just "/" or "//". */ - length = strlen (newdir); + length = newdirlen; + eassert (length == strlen (newdir)); while (length > 1 && IS_DIRECTORY_SEP (newdir[length - 1]) && ! (length == 2 && IS_DIRECTORY_SEP (newdir[0]))) length--; @@ -2765,23 +2780,24 @@ searchable directory. */) } absname = ENCODE_FILE (absname); - return file_accessible_directory_p (SSDATA (absname)) ? Qt : Qnil; + return file_accessible_directory_p (absname) ? Qt : Qnil; } /* If FILE is a searchable directory or a symlink to a searchable directory, return true. Otherwise return false and set errno to an error number. */ bool -file_accessible_directory_p (char const *file) +file_accessible_directory_p (Lisp_Object file) { #ifdef DOS_NT /* There's no need to test whether FILE is searchable, as the searchable/executable bit is invented on DOS_NT platforms. */ - return file_directory_p (file); + return file_directory_p (SSDATA (file)); #else /* On POSIXish platforms, use just one system call; this avoids a race and is typically faster. */ - ptrdiff_t len = strlen (file); + const char *data = SSDATA (file); + ptrdiff_t len = SBYTES (file); char const *dir; bool ok; int saved_errno; @@ -2793,15 +2809,15 @@ file_accessible_directory_p (char const *file) "/" and "//" are distinct on some platforms, whereas "/", "///", "////", etc. are all equivalent. */ if (! len) - dir = file; + dir = data; else { /* Just check for trailing '/' when deciding whether to append '/'. That's simpler than testing the two special cases "/" and "//", and it's a safe optimization here. */ char *buf = SAFE_ALLOCA (len + 3); - memcpy (buf, file, len); - strcpy (buf + len, &"/."[file[len - 1] == '/']); + memcpy (buf, data, len); + strcpy (buf + len, &"/."[data[len - 1] == '/']); dir = buf; } diff --git a/src/lisp.h b/src/lisp.h index 53d6cf8009e..05b27ab9f00 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -4029,7 +4029,7 @@ extern _Noreturn void report_file_error (const char *, Lisp_Object); extern bool internal_delete_file (Lisp_Object); extern Lisp_Object emacs_readlinkat (int, const char *); extern bool file_directory_p (const char *); -extern bool file_accessible_directory_p (const char *); +extern bool file_accessible_directory_p (Lisp_Object); extern void init_fileio (void); extern void syms_of_fileio (void); extern Lisp_Object make_temp_name (Lisp_Object, bool); diff --git a/src/lread.c b/src/lread.c index 639d574ac6b..7626e16e818 100644 --- a/src/lread.c +++ b/src/lread.c @@ -4213,7 +4213,7 @@ load_path_check (Lisp_Object lpath) if (STRINGP (dirfile)) { dirfile = Fdirectory_file_name (dirfile); - if (! file_accessible_directory_p (SSDATA (dirfile))) + if (! file_accessible_directory_p (dirfile)) dir_warning ("Lisp directory", XCAR (path_tail)); } } -- 2.39.5