[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
feature/android 44cf1ed7e59 2/2: Update Android port
From: |
Po Lu |
Subject: |
feature/android 44cf1ed7e59 2/2: Update Android port |
Date: |
Tue, 7 Mar 2023 01:55:28 -0500 (EST) |
branch: feature/android
commit 44cf1ed7e593022df01a47b701e7796e9d70d2fb
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>
Update Android port
* src/lread.c (lread_fd, file_tell, infile, skip_dyn_bytes)
(skip_dyn_eof, readbyte_from_stdio, safe_to_load_version)
(close_infile_unwind, close_file_unwind_android_fd): New
function.
(Fload, Flocate_file_internal, openp): New argument PLATFORM.
All callers changed.
(skip_lazy_string): Add optimized versions of various functions
for accessing Android assets.
---
src/callproc.c | 2 +-
src/charset.c | 3 +-
src/emacs.c | 3 +-
src/image.c | 9 +-
src/lisp.h | 3 +-
src/lread.c | 283 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
src/process.c | 2 +-
src/sound.c | 2 +-
src/w32.c | 3 +-
src/w32proc.c | 2 +-
10 files changed, 268 insertions(+), 44 deletions(-)
diff --git a/src/callproc.c b/src/callproc.c
index ea9c946f158..8d3519fdab2 100644
--- a/src/callproc.c
+++ b/src/callproc.c
@@ -516,7 +516,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int
filefd,
int ok;
ok = openp (Vexec_path, args[0], Vexec_suffixes, &path,
- make_fixnum (X_OK), false, false);
+ make_fixnum (X_OK), false, false, NULL);
if (ok < 0)
report_file_error ("Searching for program", args[0]);
}
diff --git a/src/charset.c b/src/charset.c
index 7987ffa0c5e..8e909c5f03c 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -486,7 +486,8 @@ load_charset_map_from_file (struct charset *charset,
Lisp_Object mapfile,
specpdl_ref count = SPECPDL_INDEX ();
record_unwind_protect_nothing ();
specbind (Qfile_name_handler_alist, Qnil);
- fd = openp (Vcharset_map_path, mapfile, suffixes, NULL, Qnil, false, false);
+ fd = openp (Vcharset_map_path, mapfile, suffixes, NULL, Qnil, false, false,
+ NULL);
fp = fd < 0 ? 0 : fdopen (fd, "r");
if (!fp)
{
diff --git a/src/emacs.c b/src/emacs.c
index 2f953510a3d..3df98e6fae2 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -531,7 +531,8 @@ init_cmdargs (int argc, char **argv, int skip_args, char
const *original_pwd)
{
Lisp_Object found;
int yes = openp (Vexec_path, Vinvocation_name, Vexec_suffixes,
- &found, make_fixnum (X_OK), false, false);
+ &found, make_fixnum (X_OK), false, false,
+ NULL);
if (yes == 1)
{
/* Add /: to the front of the name
diff --git a/src/image.c b/src/image.c
index 2e6aa0ce0e3..a244b23ecd2 100644
--- a/src/image.c
+++ b/src/image.c
@@ -760,7 +760,7 @@ image_create_bitmap_from_file (struct frame *f, Lisp_Object
file)
/* Search bitmap-file-path for the file, if appropriate. */
if (openp (Vx_bitmap_file_path, file, Qnil, &found,
- make_fixnum (R_OK), false, false)
+ make_fixnum (R_OK), false, false, NULL)
< 0)
return -1;
@@ -807,7 +807,7 @@ image_create_bitmap_from_file (struct frame *f, Lisp_Object
file)
/* Search bitmap-file-path for the file, if appropriate. */
if (openp (Vx_bitmap_file_path, file, Qnil, &found,
- make_fixnum (R_OK), false, false)
+ make_fixnum (R_OK), false, false, NULL)
< 0)
return -1;
@@ -896,7 +896,7 @@ image_create_bitmap_from_file (struct frame *f, Lisp_Object
file)
/* Search bitmap-file-path for the file, if appropriate. */
if (openp (Vx_bitmap_file_path, file, Qnil, &found,
- make_fixnum (R_OK), false, false)
+ make_fixnum (R_OK), false, false, NULL)
< 0)
return -1;
@@ -4148,7 +4148,8 @@ image_find_image_fd (Lisp_Object file, int *pfd)
/* Try to find FILE in data-directory/images, then x-bitmap-file-path. */
fd = openp (search_path, file, Qnil, &file_found,
- pfd ? Qt : make_fixnum (R_OK), false, false);
+ pfd ? Qt : make_fixnum (R_OK), false, false,
+ NULL);
if (fd == -2)
{
/* The file exists locally, but has a file name handler.
diff --git a/src/lisp.h b/src/lisp.h
index 56ef338a5b1..f7ba6775975 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4514,7 +4514,8 @@ extern bool suffix_p (Lisp_Object, const char *);
extern Lisp_Object save_match_data_load (Lisp_Object, Lisp_Object, Lisp_Object,
Lisp_Object, Lisp_Object);
extern int openp (Lisp_Object, Lisp_Object, Lisp_Object,
- Lisp_Object *, Lisp_Object, bool, bool);
+ Lisp_Object *, Lisp_Object, bool, bool,
+ void **);
enum { S2N_IGNORE_TRAILING = 1 };
extern Lisp_Object string_to_number (char const *, int, ptrdiff_t *);
extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object),
diff --git a/src/lread.c b/src/lread.c
index 150d8a01e10..48f95ce5f40 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -62,6 +62,24 @@ along with GNU Emacs. If not, see
<https://www.gnu.org/licenses/>. */
#include <fcntl.h>
+#if !defined HAVE_ANDROID || defined ANDROID_STUBIFY \
+ || (__ANDROID_API__ < 9)
+
+#define lread_fd int
+#define lread_fd_cmp(n) (fd == (n))
+#define lread_fd_p (fd >= 0)
+#define lread_close emacs_close
+#define lread_fstat fstat
+#define lread_read_quit emacs_read_quit
+#define lread_lseek lseek
+
+#define file_stream FILE *
+#define file_seek fseek
+#define file_stream_valid_p(p) (p)
+#define file_stream_close emacs_fclose
+#define file_stream_invalid NULL
+#define file_get_char getc
+
#ifdef HAVE_FSEEKO
#define file_offset off_t
#define file_tell ftello
@@ -70,6 +88,79 @@ along with GNU Emacs. If not, see
<https://www.gnu.org/licenses/>. */
#define file_tell ftell
#endif
+#else
+
+#include "android.h"
+
+/* Use an Android file descriptor under Android instead, as this
+ allows loading directly from asset files without loading each asset
+ into memory and creating a separate file descriptor every time.
+
+ Note that `struct android_fd_or_asset' as used here is different
+ from that returned from `android_open_asset'; if fd.asset is NULL,
+ then fd.fd is either a valid file descriptor or -1, meaning that
+ the file descriptor is invalid.
+
+ However, lread requires the ability to seek inside asset files,
+ which is not provided under Android 2.2. So when building for that
+ particular system, fall back to the usual file descriptor-based
+ code. */
+
+#define lread_fd struct android_fd_or_asset
+#define lread_fd_cmp(n) (!fd.asset && fd.fd == (n))
+#define lread_fd_p (fd.asset || fd.fd >= 0)
+#define lread_close android_close_asset
+#define lread_fstat android_asset_fstat
+#define lread_read_quit android_asset_read_quit
+#define lread_lseek android_asset_lseek
+
+/* The invalid file stream. */
+
+static struct android_fd_or_asset invalid_file_stream =
+ {
+ -1,
+ NULL,
+ };
+
+#define file_stream struct android_fd_or_asset
+#define file_offset off_t
+#define file_tell(n) (android_asset_lseek ((n), 0, SEEK_CUR))
+#define file_seek android_asset_lseek
+#define file_stream_valid_p(p) ((p).asset || (p).fd >= 0)
+#define file_stream_close android_close_asset
+#define file_stream_invalid invalid_file_stream
+
+/* Return a single character from the file input stream STREAM.
+ Value and errors are the same as getc. */
+
+static int
+file_get_char (file_stream stream)
+{
+ int c;
+ char byte;
+ ssize_t rc;
+
+ retry:
+ rc = android_asset_read (stream, &byte, 1);
+
+ if (rc == 0)
+ c = EOF;
+ else if (rc == -1)
+ {
+ if (errno == EINTR)
+ goto retry;
+ else
+ c = EOF;
+ }
+ else
+ c = (unsigned char) byte;
+
+ return c;
+}
+
+#define USE_ANDROID_ASSETS
+#endif
+
#if IEEE_FLOATING_POINT
# include <ieee754.h>
# ifndef INFINITY
@@ -113,7 +204,7 @@ static Lisp_Object read_objects_completed;
static struct infile
{
/* The input stream. */
- FILE *stream;
+ file_stream stream;
/* Lookahead byte count. */
signed char lookahead;
@@ -375,7 +466,7 @@ skip_dyn_bytes (Lisp_Object readcharfun, ptrdiff_t n)
if (FROM_FILE_P (readcharfun))
{
block_input (); /* FIXME: Not sure if it's needed. */
- fseek (infile->stream, n - infile->lookahead, SEEK_CUR);
+ file_seek (infile->stream, n - infile->lookahead, SEEK_CUR);
unblock_input ();
infile->lookahead = 0;
}
@@ -399,7 +490,7 @@ skip_dyn_eof (Lisp_Object readcharfun)
if (FROM_FILE_P (readcharfun))
{
block_input (); /* FIXME: Not sure if it's needed. */
- fseek (infile->stream, 0, SEEK_END);
+ file_seek (infile->stream, 0, SEEK_END);
unblock_input ();
infile->lookahead = 0;
}
@@ -480,10 +571,12 @@ readbyte_from_stdio (void)
return infile->buf[--infile->lookahead];
int c;
- FILE *instream = infile->stream;
+ file_stream instream = infile->stream;
block_input ();
+#if !defined USE_ANDROID_ASSETS
+
/* Interrupted reads have been observed while reading over the network. */
while ((c = getc (instream)) == EOF && errno == EINTR && ferror (instream))
{
@@ -493,6 +586,35 @@ readbyte_from_stdio (void)
clearerr (instream);
}
+#else
+
+ {
+ char byte;
+ ssize_t rc;
+
+ retry:
+ rc = android_asset_read (instream, &byte, 1);
+
+ if (rc == 0)
+ c = EOF;
+ else if (rc == -1)
+ {
+ if (errno == EINTR)
+ {
+ unblock_input ();
+ maybe_quit ();
+ block_input ();
+ goto retry;
+ }
+ else
+ c = EOF;
+ }
+ else
+ c = (unsigned char) byte;
+ }
+
+#endif
+
unblock_input ();
return (c == EOF ? -1 : c);
@@ -1062,7 +1184,7 @@ lisp_file_lexically_bound_p (Lisp_Object readcharfun)
safe to load. Only files compiled with Emacs can be loaded. */
static int
-safe_to_load_version (Lisp_Object file, int fd)
+safe_to_load_version (Lisp_Object file, lread_fd fd)
{
struct stat st;
char buf[512];
@@ -1071,12 +1193,12 @@ safe_to_load_version (Lisp_Object file, int fd)
/* If the file is not regular, then we cannot safely seek it.
Assume that it is not safe to load as a compiled file. */
- if (sys_fstat (fd, &st) == 0 && !S_ISREG (st.st_mode))
+ if (lread_fstat (fd, &st) == 0 && !S_ISREG (st.st_mode))
return 0;
/* Read the first few bytes from the file, and look for a line
specifying the byte compiler version used. */
- nbytes = emacs_read_quit (fd, buf, sizeof buf);
+ nbytes = lread_read_quit (fd, buf, sizeof buf);
if (nbytes > 0)
{
/* Skip to the next newline, skipping over the initial `ELC'
@@ -1091,7 +1213,7 @@ safe_to_load_version (Lisp_Object file, int fd)
version = 0;
}
- if (lseek (fd, 0, SEEK_SET) < 0)
+ if (lread_lseek (fd, 0, SEEK_SET) < 0)
report_file_error ("Seeking to start of file", file);
return version;
@@ -1165,7 +1287,7 @@ close_infile_unwind (void *arg)
{
struct infile *prev_infile = arg;
eassert (infile && infile != prev_infile);
- emacs_fclose (infile->stream);
+ file_stream_close (infile->stream);
infile = prev_infile;
}
@@ -1194,6 +1316,22 @@ loadhist_initialize (Lisp_Object filename)
specbind (Qcurrent_load_list, Fcons (filename, Qnil));
}
+#ifdef USE_ANDROID_ASSETS
+
+/* Like `close_file_unwind'. However, PTR is a pointer to an Android
+ file descriptor instead of a system file descriptor. */
+
+static void
+close_file_unwind_android_fd (void *ptr)
+{
+ struct android_fd_or_asset *fd;
+
+ fd = ptr;
+ android_close_asset (*fd);
+}
+
+#endif
+
DEFUN ("load", Fload, Sload, 1, 5, 0,
doc: /* Execute a file of Lisp code named FILE.
First try FILE with `.elc' appended, then try with `.el', then try
@@ -1242,8 +1380,12 @@ Return t if the file exists and loads successfully. */)
(Lisp_Object file, Lisp_Object noerror, Lisp_Object nomessage,
Lisp_Object nosuffix, Lisp_Object must_suffix)
{
- FILE *stream UNINIT;
- int fd;
+ file_stream stream UNINIT;
+ lread_fd fd;
+#ifdef USE_ANDROID_ASSETS
+ int rc;
+ void *asset;
+#endif
specpdl_ref fd_index UNINIT;
specpdl_ref count = SPECPDL_INDEX ();
Lisp_Object found, efound, hist_file_name;
@@ -1284,7 +1426,12 @@ Return t if the file exists and loads successfully. */)
since it would try to load a directory as a Lisp file. */
if (SCHARS (file) == 0)
{
+#if !defined USE_ANDROID_ASSETS
fd = -1;
+#else
+ fd.asset = NULL;
+ fd.fd = -1;
+#endif
errno = ENOENT;
}
else
@@ -1323,12 +1470,22 @@ Return t if the file exists and loads successfully. */)
suffixes = CALLN (Fappend, suffixes, Vload_file_rep_suffixes);
}
- fd =
- openp (Vload_path, file, suffixes, &found, Qnil, load_prefer_newer,
- no_native);
+#if !defined USE_ANDROID_ASSETS
+ fd = openp (Vload_path, file, suffixes, &found, Qnil,
+ load_prefer_newer, no_native, NULL);
+#else
+ asset = NULL;
+ rc = openp (Vload_path, file, suffixes, &found, Qnil,
+ load_prefer_newer, no_native, &asset);
+ fd.fd = rc;
+ fd.asset = asset;
+
+ /* fd.asset will be non-NULL if this is actually an asset
+ file. */
+#endif
}
- if (fd == -1)
+ if (lread_fd_cmp (-1))
{
if (NILP (noerror))
report_file_error ("Cannot open load file", file);
@@ -1340,7 +1497,7 @@ Return t if the file exists and loads successfully. */)
Vuser_init_file = found;
/* If FD is -2, that means openp found a magic file. */
- if (fd == -2)
+ if (lread_fd_cmp (-2))
{
if (NILP (Fequal (found, file)))
/* If FOUND is a different file name from FILE,
@@ -1369,11 +1526,21 @@ Return t if the file exists and loads successfully. */)
#endif
}
+#if !defined USE_ANDROID_ASSETS
if (0 <= fd)
{
fd_index = SPECPDL_INDEX ();
record_unwind_protect_int (close_file_unwind, fd);
}
+#else
+ if (fd.asset || fd.fd >= 0)
+ {
+ /* Use a different kind of unwind_protect here. */
+ fd_index = SPECPDL_INDEX ();
+ record_unwind_protect_ptr (close_file_unwind_android_fd,
+ &fd);
+ }
+#endif
#ifdef HAVE_MODULES
bool is_module =
@@ -1439,11 +1606,12 @@ Return t if the file exists and loads successfully. */)
if (is_elc
/* version = 1 means the file is empty, in which case we can
treat it as not byte-compiled. */
- || (fd >= 0 && (version = safe_to_load_version (file, fd)) > 1))
+ || (lread_fd_p
+ && (version = safe_to_load_version (file, fd)) > 1))
/* Load .elc files directly, but not when they are
remote and have no handler! */
{
- if (fd != -2)
+ if (!lread_fd_cmp (-2))
{
struct stat s1, s2;
int result;
@@ -1500,9 +1668,9 @@ Return t if the file exists and loads successfully. */)
{
Lisp_Object val;
- if (fd >= 0)
+ if (lread_fd_p)
{
- emacs_close (fd);
+ lread_close (fd);
clear_unwind_protect (fd_index);
}
val = call4 (Vload_source_file_function, found, hist_file_name,
@@ -1512,12 +1680,12 @@ Return t if the file exists and loads successfully. */)
}
}
- if (fd < 0)
+ if (!lread_fd_p)
{
/* We somehow got here with fd == -2, meaning the file is deemed
to be remote. Don't even try to reopen the file locally;
just force a failure. */
- stream = NULL;
+ stream = file_stream_invalid;
errno = EINVAL;
}
else if (!is_module && !is_native_elisp)
@@ -1528,7 +1696,15 @@ Return t if the file exists and loads successfully. */)
efound = ENCODE_FILE (found);
stream = emacs_fopen (SSDATA (efound), fmode);
#else
+#if !defined USE_ANDROID_ASSETS
stream = fdopen (fd, fmode);
+#else
+ /* Android systems use special file descriptors which can point
+ into compressed data and double as file streams. FMODE is
+ unused. */
+ ((void) fmode);
+ stream = fd;
+#endif
#endif
}
@@ -1540,15 +1716,15 @@ Return t if the file exists and loads successfully. */)
{
/* `module-load' uses the file name, so we can close the stream
now. */
- if (fd >= 0)
+ if (lread_fd_p)
{
- emacs_close (fd);
+ lread_close (fd);
clear_unwind_protect (fd_index);
}
}
else
{
- if (! stream)
+ if (!file_stream_valid_p (stream))
report_file_error ("Opening stdio stream", file);
set_unwind_protect_ptr (fd_index, close_infile_unwind, infile);
input.stream = stream;
@@ -1684,7 +1860,8 @@ directories, make sure the PREDICATE function returns
`dir-ok' for them. */)
(Lisp_Object filename, Lisp_Object path, Lisp_Object suffixes, Lisp_Object
predicate)
{
Lisp_Object file;
- int fd = openp (path, filename, suffixes, &file, predicate, false, true);
+ int fd = openp (path, filename, suffixes, &file, predicate, false, true,
+ NULL);
if (NILP (predicate) && fd >= 0)
emacs_close (fd);
return file;
@@ -1825,14 +2002,20 @@ maybe_swap_for_eln (bool no_native, Lisp_Object
*filename, int *fd,
If NEWER is true, try all SUFFIXes and return the result for the
newest file that exists. Does not apply to remote files,
- or if a non-nil and non-t PREDICATE is specified.
+ platform-specific files, or if a non-nil and non-t PREDICATE is
+ specified.
- if NO_NATIVE is true do not try to load native code. */
+ If NO_NATIVE is true do not try to load native code.
+
+ If PLATFORM is non-NULL and the file being loaded lies in a special
+ directory, such as the Android `/assets' directory, return a handle
+ to that directory in *PLATFORM instead of a file descriptor; in
+ that case, value is -3. */
int
openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes,
Lisp_Object *storeptr, Lisp_Object predicate, bool newer,
- bool no_native)
+ bool no_native, void **platform)
{
ptrdiff_t fn_size = 100;
char buf[100];
@@ -1844,6 +2027,9 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object
suffixes,
ptrdiff_t max_suffix_len = 0;
int last_errno = ENOENT;
int save_fd = -1;
+#ifdef USE_ANDROID_ASSETS
+ struct android_fd_or_asset platform_fd;
+#endif
USE_SAFE_ALLOCA;
/* The last-modified time of the newest matching file found.
@@ -2013,7 +2199,30 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object
suffixes,
fd = -1;
else
#endif
- fd = emacs_open (pfn, O_RDONLY, 0);
+ {
+#if !defined USE_ANDROID_ASSETS
+ fd = emacs_open (pfn, O_RDONLY, 0);
+#else
+ if (platform)
+ {
+ platform_fd = android_open_asset (pfn, O_RDONLY, 0);
+
+ if (platform_fd.asset
+ && platform_fd.asset != (void *) -1)
+ {
+ *storeptr = string;
+ goto handle_platform_fd;
+ }
+
+ if (platform_fd.asset == (void *) -1)
+ fd = -1;
+ else
+ fd = platform_fd.fd;
+ }
+ else
+ fd = emacs_open (pfn, O_RDONLY, 0);
+#endif
+ }
if (fd < 0)
{
@@ -2081,6 +2290,16 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object
suffixes,
SAFE_FREE ();
errno = last_errno;
return -1;
+
+#ifdef USE_ANDROID_ASSETS
+ handle_platform_fd:
+
+ /* Here, openp found a platform specific file descriptor. It can't
+ be a directory under Android, so return it in *PLATFORM and then
+ -3 as the file descriptor. */
+ *platform = platform_fd.asset;
+ return -3;
+#endif
}
@@ -3489,7 +3708,7 @@ skip_lazy_string (Lisp_Object readcharfun)
ss->string = xrealloc (ss->string, ss->size);
}
- FILE *instream = infile->stream;
+ file_stream instream = infile->stream;
ss->position = (file_tell (instream) - infile->lookahead);
/* Copy that many bytes into the saved string. */
@@ -3499,7 +3718,7 @@ skip_lazy_string (Lisp_Object readcharfun)
ss->string[i++] = c = infile->buf[--infile->lookahead];
block_input ();
for (; i < nskip && c >= 0; i++)
- ss->string[i] = c = getc (instream);
+ ss->string[i] = c = file_get_char (instream);
unblock_input ();
ss->length = i;
diff --git a/src/process.c b/src/process.c
index bdaaba70fea..0eff789e599 100644
--- a/src/process.c
+++ b/src/process.c
@@ -2008,7 +2008,7 @@ usage: (make-process &rest ARGS) */)
{
tem = Qnil;
openp (Vexec_path, program, Vexec_suffixes, &tem,
- make_fixnum (X_OK), false, false);
+ make_fixnum (X_OK), false, false, NULL);
if (NILP (tem))
report_file_error ("Searching for program", program);
tem = Fexpand_file_name (tem, Qnil);
diff --git a/src/sound.c b/src/sound.c
index 145100cd433..a51cdb6d97a 100644
--- a/src/sound.c
+++ b/src/sound.c
@@ -1384,7 +1384,7 @@ Internal use only, use `play-sound' instead. */)
/* Open the sound file. */
current_sound->fd =
openp (list1 (Vdata_directory), attrs[SOUND_FILE], Qnil, &file, Qnil,
- false, false);
+ false, false, NULL);
if (current_sound->fd < 0)
sound_perror ("Could not open sound file");
diff --git a/src/w32.c b/src/w32.c
index 8d344d2e6da..f45750ea5c1 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -10328,7 +10328,8 @@ check_windows_init_file (void)
names from UTF-8 to ANSI. */
init_file = build_string ("term/w32-win");
fd =
- openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0, 0);
+ openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0, 0,
+ NULL);
if (fd < 0)
{
Lisp_Object load_path_print = Fprin1_to_string (Vload_path,
diff --git a/src/w32proc.c b/src/w32proc.c
index 77a4ac1ff7e..edc4394b17f 100644
--- a/src/w32proc.c
+++ b/src/w32proc.c
@@ -1956,7 +1956,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char
**envp)
program = build_string (cmdname);
full = Qnil;
openp (Vexec_path, program, Vexec_suffixes, &full, make_fixnum (X_OK),
- 0, 0);
+ 0, 0, NULL);
if (NILP (full))
{
errno = EINVAL;