rktio: move dlopen/dlsym/etc. adapter to rktio
Also, sync header-annotation improvements from the racket7 branch.
This commit is contained in:
parent
c87cdf5988
commit
98a78add9f
|
@ -11,6 +11,7 @@ CPPFLAGS = @PREFLAGS@
|
|||
ALL_CFLAGS = $(CFLAGS) $(CPPFLAGS) @OPTIONS@ @MZOPTIONS@ \
|
||||
-I$(builddir)/../racket \
|
||||
-I$(srcdir)/../racket/include -I$(srcdir)/../racket/src \
|
||||
-I$(srcdir)/../rktio -I$(builddir)/../rktio \
|
||||
$(LIBFFI_LOCAL_INCLUDE_@OWN_LIBFFI@)
|
||||
ARFLAGS = @ARFLAGS@
|
||||
NOOP = :
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "schpriv.h"
|
||||
#include "schmach.h"
|
||||
#include "schrktio.h"
|
||||
|
||||
#ifndef DONT_USE_FOREIGN
|
||||
|
||||
|
@ -127,76 +128,6 @@ static intptr_t add_check_overflow(const char *who, intptr_t a, intptr_t b)
|
|||
return SCHEME_INT_VAL(c);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Defining EnumProcessModules for openning `self' as an ffi-lib */
|
||||
|
||||
/* We'd like to use EnumProcessModules to find all loaded DLLs, but it's
|
||||
only available in NT 4.0 and later. The alternative, Module32{First,Next},
|
||||
is available *except* for NT 4.0! So we try EnumProcessModules first. */
|
||||
|
||||
#ifdef WINDOWS_DYNAMIC_LOAD
|
||||
#ifdef MZ_PRECISE_GC
|
||||
START_XFORM_SKIP;
|
||||
#endif
|
||||
|
||||
int epm_tried = 0;
|
||||
typedef BOOL (WINAPI *EnumProcessModules_t)(HANDLE hProcess,
|
||||
HMODULE* lphModule,
|
||||
DWORD cb,
|
||||
LPDWORD lpcbNeeded);
|
||||
EnumProcessModules_t _EnumProcessModules;
|
||||
#include <tlhelp32.h>
|
||||
|
||||
static BOOL mzEnumProcessModules(HANDLE hProcess, HMODULE* lphModule,
|
||||
DWORD cb, LPDWORD lpcbNeeded)
|
||||
{
|
||||
if (!epm_tried) {
|
||||
HMODULE hm;
|
||||
hm = LoadLibrary("psapi.dll");
|
||||
if (hm) {
|
||||
_EnumProcessModules =
|
||||
(EnumProcessModules_t)GetProcAddress(hm, "EnumProcessModules");
|
||||
}
|
||||
epm_tried = 1;
|
||||
}
|
||||
|
||||
if (_EnumProcessModules)
|
||||
return _EnumProcessModules(hProcess, lphModule, cb, lpcbNeeded);
|
||||
else {
|
||||
HANDLE snapshot;
|
||||
MODULEENTRY32 mod;
|
||||
int i, ok;
|
||||
|
||||
snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,
|
||||
GetCurrentProcessId());
|
||||
if (snapshot == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; 1; i++) {
|
||||
mod.dwSize = sizeof(mod);
|
||||
if (!i)
|
||||
ok = Module32First(snapshot, &mod);
|
||||
else
|
||||
ok = Module32Next(snapshot, &mod);
|
||||
if (!ok)
|
||||
break;
|
||||
if (cb >= sizeof(HMODULE)) {
|
||||
lphModule[i] = mod.hModule;
|
||||
cb -= sizeof(HMODULE);
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(snapshot);
|
||||
*lpcbNeeded = i * sizeof(HMODULE);
|
||||
return GetLastError() == ERROR_NO_MORE_FILES;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MZ_PRECISE_GC
|
||||
END_XFORM_SKIP;
|
||||
#endif
|
||||
#endif /* WINDOWS_DYNAMIC_LOAD */
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Library objects */
|
||||
|
||||
|
@ -204,9 +135,8 @@ END_XFORM_SKIP;
|
|||
static Scheme_Type ffi_lib_tag;
|
||||
typedef struct ffi_lib_struct {
|
||||
Scheme_Object so;
|
||||
NON_GCBALE_PTR(void) handle;
|
||||
NON_GCBALE_PTR(rktio_dll_t) handle;
|
||||
Scheme_Object* name;
|
||||
Scheme_Hash_Table* objects;
|
||||
int is_global;
|
||||
} ffi_lib_struct;
|
||||
#define SCHEME_FFILIBP(x) (SCHEME_TYPE(x)==ffi_lib_tag)
|
||||
|
@ -225,13 +155,11 @@ int ffi_lib_SIZE(void *p) {
|
|||
int ffi_lib_MARK(void *p) {
|
||||
ffi_lib_struct *s = (ffi_lib_struct *)p;
|
||||
gcMARK(s->name);
|
||||
gcMARK(s->objects);
|
||||
return gcBYTES_TO_WORDS(sizeof(ffi_lib_struct));
|
||||
}
|
||||
int ffi_lib_FIXUP(void *p) {
|
||||
ffi_lib_struct *s = (ffi_lib_struct *)p;
|
||||
gcFIXUP(s->name);
|
||||
gcFIXUP(s->objects);
|
||||
return gcBYTES_TO_WORDS(sizeof(ffi_lib_struct));
|
||||
}
|
||||
END_XFORM_SKIP;
|
||||
|
@ -245,8 +173,8 @@ static Scheme_Object *foreign_ffi_lib(int argc, Scheme_Object *argv[])
|
|||
{
|
||||
char *name;
|
||||
Scheme_Object *path, *hashname;
|
||||
void *handle;
|
||||
int null_ok = 0, as_global = 0;
|
||||
rktio_dll_t *handle;
|
||||
int as_global = 0;
|
||||
ffi_lib_struct *lib;
|
||||
if (!(SCHEME_PATH_STRINGP(argv[0]) || SCHEME_FALSEP(argv[0])))
|
||||
scheme_wrong_contract(MYNAME, "(or/c string? #f)", 0, argc, argv);
|
||||
|
@ -258,46 +186,27 @@ static Scheme_Object *foreign_ffi_lib(int argc, Scheme_Object *argv[])
|
|||
hashname = (Scheme_Object*)((name==NULL) ? "" : name);
|
||||
lib = (ffi_lib_struct*)scheme_hash_get(opened_libs, hashname);
|
||||
if (!lib) {
|
||||
Scheme_Hash_Table *ht;
|
||||
# ifdef WINDOWS_DYNAMIC_LOAD
|
||||
if (name==NULL) {
|
||||
/* openning the executable is marked by a NULL handle */
|
||||
handle = NULL;
|
||||
null_ok = 1;
|
||||
} else {
|
||||
wchar_t *wp;
|
||||
wp = scheme_path_to_wide_path(MYNAME, name);
|
||||
handle = LoadLibraryW(wp);
|
||||
}
|
||||
# else /* WINDOWS_DYNAMIC_LOAD undefined */
|
||||
# ifdef __ANDROID__
|
||||
if (!name) handle = RTLD_DEFAULT; else
|
||||
# endif /* __ANDROID__ */
|
||||
# ifdef __CYGWIN32__
|
||||
if (!name) { handle = RTLD_DEFAULT; null_ok = 1; } else
|
||||
# endif /* __CYGWIN32__ */
|
||||
handle = dlopen(name, RTLD_NOW | (as_global ? RTLD_GLOBAL : RTLD_LOCAL));
|
||||
# endif /* WINDOWS_DYNAMIC_LOAD */
|
||||
if (handle == NULL && !null_ok) {
|
||||
if (argc > 1 && SCHEME_TRUEP(argv[1])) return scheme_false;
|
||||
else {
|
||||
# ifdef WINDOWS_DYNAMIC_LOAD
|
||||
long err;
|
||||
err = GetLastError();
|
||||
scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
|
||||
MYNAME": couldn't open %V (%E)", argv[0], err);
|
||||
# else /* WINDOWS_DYNAMIC_LOAD undefined */
|
||||
scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
|
||||
MYNAME": couldn't open %V (%s)", argv[0], dlerror());
|
||||
# endif /* WINDOWS_DYNAMIC_LOAD */
|
||||
handle = rktio_dll_open(scheme_rktio, name, as_global);
|
||||
if (!handle) {
|
||||
char *msg;
|
||||
msg = rktio_dll_get_error(scheme_rktio);
|
||||
if (argc > 1 && SCHEME_TRUEP(argv[1])) {
|
||||
if (msg) free(msg);
|
||||
return scheme_false;
|
||||
} else {
|
||||
if (msg) {
|
||||
msg = scheme_strdup_and_free(msg);
|
||||
scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
|
||||
MYNAME": couldn't open %V (%s)", argv[0], msg);
|
||||
} else
|
||||
scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
|
||||
MYNAME": couldn't open %V (%R)", argv[0]);
|
||||
}
|
||||
}
|
||||
ht = scheme_make_hash_table(SCHEME_hash_string);
|
||||
lib = (ffi_lib_struct*)scheme_malloc_tagged(sizeof(ffi_lib_struct));
|
||||
lib->so.type = ffi_lib_tag;
|
||||
lib->handle = (handle);
|
||||
lib->name = (argv[0]);
|
||||
lib->objects = (ht);
|
||||
lib->is_global = (!name);
|
||||
scheme_hash_set(opened_libs, hashname, (Scheme_Object*)lib);
|
||||
/* no dlclose finalizer - since the hash table always keeps a reference */
|
||||
|
@ -354,18 +263,13 @@ int ffi_obj_FIXUP(void *p) {
|
|||
END_XFORM_SKIP;
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
static int adjustment_set;
|
||||
static uintptr_t adjustment;
|
||||
#endif /* __ANDROID__ */
|
||||
|
||||
/* (ffi-obj objname ffi-lib-or-libname) -> ffi-obj */
|
||||
#define MYNAME "ffi-obj"
|
||||
static Scheme_Object *foreign_ffi_obj(int argc, Scheme_Object *argv[])
|
||||
{
|
||||
ffi_obj_struct *obj;
|
||||
void *dlobj;
|
||||
ffi_lib_struct *lib = NULL, *lib2;
|
||||
ffi_lib_struct *lib = NULL;
|
||||
char *dlname;
|
||||
if (SCHEME_FFILIBP(argv[1]))
|
||||
lib = (ffi_lib_struct*)argv[1];
|
||||
|
@ -376,87 +280,31 @@ static Scheme_Object *foreign_ffi_obj(int argc, Scheme_Object *argv[])
|
|||
if (!SCHEME_BYTE_STRINGP(argv[0]))
|
||||
scheme_wrong_contract(MYNAME, "bytes?", 0, argc, argv);
|
||||
dlname = SCHEME_BYTE_STR_VAL(argv[0]);
|
||||
obj = (ffi_obj_struct*)scheme_hash_get(lib->objects, (Scheme_Object*)dlname);
|
||||
if (!obj) {
|
||||
# ifdef WINDOWS_DYNAMIC_LOAD
|
||||
if (lib->handle) {
|
||||
dlobj = GetProcAddress(lib->handle, dlname);
|
||||
} else {
|
||||
/* this is for the executable-open case, which was marked by a NULL
|
||||
* handle, deal with it by searching all current modules */
|
||||
# define NUM_QUICK_MODS 16
|
||||
HMODULE *mods, me, quick_mods[NUM_QUICK_MODS];
|
||||
DWORD cnt = NUM_QUICK_MODS * sizeof(HMODULE), actual_cnt, i;
|
||||
me = GetCurrentProcess();
|
||||
mods = quick_mods;
|
||||
if (mzEnumProcessModules(me, mods, cnt, &actual_cnt)) {
|
||||
if (actual_cnt > cnt) {
|
||||
cnt = actual_cnt;
|
||||
mods = (HMODULE *)scheme_malloc_atomic(cnt);
|
||||
if (!mzEnumProcessModules(me, mods, cnt, &actual_cnt))
|
||||
mods = NULL;
|
||||
} else
|
||||
cnt = actual_cnt;
|
||||
} else
|
||||
mods = NULL;
|
||||
if (mods) {
|
||||
cnt /= sizeof(HMODULE);
|
||||
for (i = 0; i < cnt; i++) {
|
||||
dlobj = GetProcAddress(mods[i], dlname);
|
||||
if (dlobj) break;
|
||||
}
|
||||
} else
|
||||
dlobj = NULL;
|
||||
}
|
||||
if (!dlobj) {
|
||||
long err;
|
||||
err = GetLastError();
|
||||
|
||||
dlobj = rktio_dll_find_object(scheme_rktio, lib->handle, dlname);
|
||||
if (!dlobj) {
|
||||
char *msg;
|
||||
msg = rktio_dll_get_error(scheme_rktio);
|
||||
if (msg) {
|
||||
msg = scheme_strdup_and_free(msg);
|
||||
scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
|
||||
MYNAME": couldn't get \"%s\" from %V (%E)",
|
||||
dlname, lib->name, err);
|
||||
}
|
||||
# else /* WINDOWS_DYNAMIC_LOAD undefined */
|
||||
dlobj = dlsym(lib->handle, dlname);
|
||||
# ifdef __ANDROID__
|
||||
if (dlobj && (lib->handle == RTLD_DEFAULT)) {
|
||||
/* Compensate for a bug in dlsym() that gets the address wrong by
|
||||
an offset (incorrect use of `link_bias'?): */
|
||||
if (!adjustment_set) {
|
||||
adjustment = ((uintptr_t)scheme_start_atomic_no_break
|
||||
- (uintptr_t)dlsym(RTLD_DEFAULT, "scheme_start_atomic_no_break"));
|
||||
adjustment_set = 1;
|
||||
}
|
||||
dlobj = (char *)dlobj XFORM_OK_PLUS adjustment;
|
||||
}
|
||||
# endif /* __ANDROID__ */
|
||||
if (!dlobj && lib->is_global) {
|
||||
/* Try every handle in the table of opened libraries. */
|
||||
int i;
|
||||
for (i = opened_libs->size; i--; ) {
|
||||
if (opened_libs->vals[i]) {
|
||||
lib2 = (ffi_lib_struct *)opened_libs->vals[i];
|
||||
dlobj = dlsym(lib2->handle, dlname);
|
||||
if (dlobj) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!dlobj) {
|
||||
const char *err;
|
||||
err = dlerror();
|
||||
if (err != NULL)
|
||||
scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
|
||||
MYNAME": couldn't get \"%s\" from %V (%s)",
|
||||
dlname, lib->name, err);
|
||||
}
|
||||
# endif /* WINDOWS_DYNAMIC_LOAD */
|
||||
MYNAME": couldn't get \"%s\" from %V (%s)",
|
||||
dlname, lib->name, msg);
|
||||
} else
|
||||
scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
|
||||
MYNAME": couldn't get \"%s\" from %V (%R)",
|
||||
dlname, lib->name);
|
||||
}
|
||||
|
||||
if (dlobj) {
|
||||
obj = (ffi_obj_struct*)scheme_malloc_tagged(sizeof(ffi_obj_struct));
|
||||
obj->so.type = ffi_obj_tag;
|
||||
obj->obj = (dlobj);
|
||||
obj->name = (dlname);
|
||||
obj->lib = (lib);
|
||||
scheme_hash_set(lib->objects, (Scheme_Object*)dlname, (Scheme_Object*)obj);
|
||||
}
|
||||
return (obj == NULL) ? scheme_false : (Scheme_Object*)obj;
|
||||
return (Scheme_Object *)obj;
|
||||
} else
|
||||
return scheme_false;
|
||||
}
|
||||
#undef MYNAME
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ exec racket "$0" > `echo "$0" | sed 's/rktc$/c/'` "$0"
|
|||
|
||||
#include "schpriv.h"
|
||||
#include "schmach.h"
|
||||
#include "schrktio.h"
|
||||
|
||||
#ifndef DONT_USE_FOREIGN
|
||||
|
||||
|
@ -130,83 +131,12 @@ static intptr_t add_check_overflow(const char *who, intptr_t a, intptr_t b)
|
|||
return SCHEME_INT_VAL(c);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Defining EnumProcessModules for openning `self' as an ffi-lib */
|
||||
|
||||
/* We'd like to use EnumProcessModules to find all loaded DLLs, but it's
|
||||
only available in NT 4.0 and later. The alternative, Module32{First,Next},
|
||||
is available *except* for NT 4.0! So we try EnumProcessModules first. */
|
||||
|
||||
@@IFDEF{WINDOWS_DYNAMIC_LOAD}{
|
||||
#ifdef MZ_PRECISE_GC
|
||||
START_XFORM_SKIP;
|
||||
#endif
|
||||
|
||||
int epm_tried = 0;
|
||||
typedef BOOL (WINAPI *EnumProcessModules_t)(HANDLE hProcess,
|
||||
HMODULE* lphModule,
|
||||
DWORD cb,
|
||||
LPDWORD lpcbNeeded);
|
||||
EnumProcessModules_t _EnumProcessModules;
|
||||
#include <tlhelp32.h>
|
||||
|
||||
static BOOL mzEnumProcessModules(HANDLE hProcess, HMODULE* lphModule,
|
||||
DWORD cb, LPDWORD lpcbNeeded)
|
||||
{
|
||||
if (!epm_tried) {
|
||||
HMODULE hm;
|
||||
hm = LoadLibrary("psapi.dll");
|
||||
if (hm) {
|
||||
_EnumProcessModules =
|
||||
(EnumProcessModules_t)GetProcAddress(hm, "EnumProcessModules");
|
||||
}
|
||||
epm_tried = 1;
|
||||
}
|
||||
|
||||
if (_EnumProcessModules)
|
||||
return _EnumProcessModules(hProcess, lphModule, cb, lpcbNeeded);
|
||||
else {
|
||||
HANDLE snapshot;
|
||||
MODULEENTRY32 mod;
|
||||
int i, ok;
|
||||
|
||||
snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,
|
||||
GetCurrentProcessId());
|
||||
if (snapshot == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; 1; i++) {
|
||||
mod.dwSize = sizeof(mod);
|
||||
if (!i)
|
||||
ok = Module32First(snapshot, &mod);
|
||||
else
|
||||
ok = Module32Next(snapshot, &mod);
|
||||
if (!ok)
|
||||
break;
|
||||
if (cb >= sizeof(HMODULE)) {
|
||||
lphModule[i] = mod.hModule;
|
||||
cb -= sizeof(HMODULE);
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(snapshot);
|
||||
*lpcbNeeded = i * sizeof(HMODULE);
|
||||
return GetLastError() == ERROR_NO_MORE_FILES;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MZ_PRECISE_GC
|
||||
END_XFORM_SKIP;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Library objects */
|
||||
|
||||
@cdefstruct[ffi-lib []
|
||||
[handle "NON_GCBALE_PTR(void)"]
|
||||
[handle "NON_GCBALE_PTR(rktio_dll_t)"]
|
||||
[name "Scheme_Object*"]
|
||||
[objects "Scheme_Hash_Table*"]
|
||||
[is_global "int"]]
|
||||
|
||||
THREAD_LOCAL_DECL(static Scheme_Hash_Table *opened_libs);
|
||||
|
@ -215,8 +145,8 @@ THREAD_LOCAL_DECL(static Scheme_Hash_Table *opened_libs);
|
|||
@cdefine[ffi-lib 1 3]{
|
||||
char *name;
|
||||
Scheme_Object *path, *hashname;
|
||||
void *handle;
|
||||
int null_ok = 0, as_global = 0;
|
||||
rktio_dll_t *handle;
|
||||
int as_global = 0;
|
||||
ffi_lib_struct *lib;
|
||||
if (!(SCHEME_PATH_STRINGP(argv[0]) || SCHEME_FALSEP(argv[0])))
|
||||
scheme_wrong_contract(MYNAME, "(or/c string? #f)", 0, argc, argv);
|
||||
|
@ -228,38 +158,24 @@ THREAD_LOCAL_DECL(static Scheme_Hash_Table *opened_libs);
|
|||
hashname = (Scheme_Object*)((name==NULL) ? "" : name);
|
||||
lib = (ffi_lib_struct*)scheme_hash_get(opened_libs, hashname);
|
||||
if (!lib) {
|
||||
Scheme_Hash_Table *ht;
|
||||
@@@IFDEF{WINDOWS_DYNAMIC_LOAD}{
|
||||
if (name==NULL) {
|
||||
/* openning the executable is marked by a NULL handle */
|
||||
handle = NULL;
|
||||
null_ok = 1;
|
||||
handle = rktio_dll_open(scheme_rktio, name, as_global);
|
||||
if (!handle) {
|
||||
char *msg;
|
||||
msg = rktio_dll_get_error(scheme_rktio);
|
||||
if (argc > 1 && SCHEME_TRUEP(argv[1])) {
|
||||
if (msg) free(msg);
|
||||
return scheme_false;
|
||||
} else {
|
||||
wchar_t *wp;
|
||||
wp = scheme_path_to_wide_path(MYNAME, name);
|
||||
handle = LoadLibraryW(wp);
|
||||
}
|
||||
}{
|
||||
@@IFDEF{__ANDROID__}{if (!name) handle = RTLD_DEFAULT; else}
|
||||
@@IFDEF{__CYGWIN32__}{if (!name) { handle = RTLD_DEFAULT; null_ok = 1; } else}
|
||||
handle = dlopen(name, RTLD_NOW | (as_global ? RTLD_GLOBAL : RTLD_LOCAL));
|
||||
}
|
||||
if (handle == NULL && !null_ok) {
|
||||
if (argc > 1 && SCHEME_TRUEP(argv[1])) return scheme_false;
|
||||
else {
|
||||
@@@IFDEF{WINDOWS_DYNAMIC_LOAD}{
|
||||
long err;
|
||||
err = GetLastError();
|
||||
if (msg) {
|
||||
msg = scheme_strdup_and_free(msg);
|
||||
scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
|
||||
MYNAME": couldn't open %V (%E)", argv[0], err);
|
||||
}{
|
||||
MYNAME": couldn't open %V (%s)", argv[0], msg);
|
||||
} else
|
||||
scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
|
||||
MYNAME": couldn't open %V (%s)", argv[0], dlerror());
|
||||
}
|
||||
MYNAME": couldn't open %V (%R)", argv[0]);
|
||||
}
|
||||
}
|
||||
ht = scheme_make_hash_table(SCHEME_hash_string);
|
||||
@cmake["lib" ffi-lib "handle" "argv[0]" "ht" "!name"]
|
||||
@cmake["lib" ffi-lib "handle" "argv[0]" "!name"]
|
||||
scheme_hash_set(opened_libs, hashname, (Scheme_Object*)lib);
|
||||
/* no dlclose finalizer - since the hash table always keeps a reference */
|
||||
/* maybe add some explicit unload at some point */
|
||||
|
@ -282,16 +198,11 @@ THREAD_LOCAL_DECL(static Scheme_Hash_Table *opened_libs);
|
|||
[name "char*"]
|
||||
[lib "NON_GCBALE_PTR(ffi_lib_struct)"]]
|
||||
|
||||
@@IFDEF{__ANDROID__}{
|
||||
static int adjustment_set;
|
||||
static uintptr_t adjustment;
|
||||
}
|
||||
|
||||
/* (ffi-obj objname ffi-lib-or-libname) -> ffi-obj */
|
||||
@cdefine[ffi-obj 2]{
|
||||
ffi_obj_struct *obj;
|
||||
void *dlobj;
|
||||
ffi_lib_struct *lib = NULL, *lib2;
|
||||
ffi_lib_struct *lib = NULL;
|
||||
char *dlname;
|
||||
if (SCHEME_FFILIBP(argv[1]))
|
||||
lib = (ffi_lib_struct*)argv[1];
|
||||
|
@ -302,83 +213,27 @@ static uintptr_t adjustment;
|
|||
if (!SCHEME_BYTE_STRINGP(argv[0]))
|
||||
scheme_wrong_contract(MYNAME, "bytes?", 0, argc, argv);
|
||||
dlname = SCHEME_BYTE_STR_VAL(argv[0]);
|
||||
obj = (ffi_obj_struct*)scheme_hash_get(lib->objects, (Scheme_Object*)dlname);
|
||||
if (!obj) {
|
||||
@@@IFDEF{WINDOWS_DYNAMIC_LOAD}{
|
||||
if (lib->handle) {
|
||||
dlobj = GetProcAddress(lib->handle, dlname);
|
||||
} else {
|
||||
/* this is for the executable-open case, which was marked by a NULL
|
||||
* handle, deal with it by searching all current modules */
|
||||
@DEFINE{NUM_QUICK_MODS 16}
|
||||
HMODULE *mods, me, quick_mods[NUM_QUICK_MODS];
|
||||
DWORD cnt = NUM_QUICK_MODS * sizeof(HMODULE), actual_cnt, i;
|
||||
me = GetCurrentProcess();
|
||||
mods = quick_mods;
|
||||
if (mzEnumProcessModules(me, mods, cnt, &actual_cnt)) {
|
||||
if (actual_cnt > cnt) {
|
||||
cnt = actual_cnt;
|
||||
mods = (HMODULE *)scheme_malloc_atomic(cnt);
|
||||
if (!mzEnumProcessModules(me, mods, cnt, &actual_cnt))
|
||||
mods = NULL;
|
||||
} else
|
||||
cnt = actual_cnt;
|
||||
} else
|
||||
mods = NULL;
|
||||
if (mods) {
|
||||
cnt /= sizeof(HMODULE);
|
||||
for (i = 0; i < cnt; i++) {
|
||||
dlobj = GetProcAddress(mods[i], dlname);
|
||||
if (dlobj) break;
|
||||
}
|
||||
} else
|
||||
dlobj = NULL;
|
||||
}
|
||||
if (!dlobj) {
|
||||
long err;
|
||||
err = GetLastError();
|
||||
|
||||
dlobj = rktio_dll_find_object(scheme_rktio, lib->handle, dlname);
|
||||
if (!dlobj) {
|
||||
char *msg;
|
||||
msg = rktio_dll_get_error(scheme_rktio);
|
||||
if (msg) {
|
||||
msg = scheme_strdup_and_free(msg);
|
||||
scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
|
||||
MYNAME": couldn't get \"%s\" from %V (%E)",
|
||||
dlname, lib->name, err);
|
||||
}
|
||||
}{
|
||||
dlobj = dlsym(lib->handle, dlname);
|
||||
@@IFDEF{__ANDROID__}{
|
||||
if (dlobj && (lib->handle == RTLD_DEFAULT)) {
|
||||
/* Compensate for a bug in dlsym() that gets the address wrong by
|
||||
an offset (incorrect use of `link_bias'?): */
|
||||
if (!adjustment_set) {
|
||||
adjustment = ((uintptr_t)scheme_start_atomic_no_break
|
||||
- (uintptr_t)dlsym(RTLD_DEFAULT, "scheme_start_atomic_no_break"));
|
||||
adjustment_set = 1;
|
||||
}
|
||||
dlobj = (char *)dlobj XFORM_OK_PLUS adjustment;
|
||||
}
|
||||
}
|
||||
if (!dlobj && lib->is_global) {
|
||||
/* Try every handle in the table of opened libraries. */
|
||||
int i;
|
||||
for (i = opened_libs->size; i--; ) {
|
||||
if (opened_libs->vals[i]) {
|
||||
lib2 = (ffi_lib_struct *)opened_libs->vals[i];
|
||||
dlobj = dlsym(lib2->handle, dlname);
|
||||
if (dlobj) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!dlobj) {
|
||||
const char *err;
|
||||
err = dlerror();
|
||||
if (err != NULL)
|
||||
scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
|
||||
MYNAME": couldn't get \"%s\" from %V (%s)",
|
||||
dlname, lib->name, err);
|
||||
}
|
||||
}
|
||||
@cmake["obj" ffi-obj "dlobj" "dlname" "lib"]
|
||||
scheme_hash_set(lib->objects, (Scheme_Object*)dlname, (Scheme_Object*)obj);
|
||||
MYNAME": couldn't get \"%s\" from %V (%s)",
|
||||
dlname, lib->name, msg);
|
||||
} else
|
||||
scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
|
||||
MYNAME": couldn't get \"%s\" from %V (%R)",
|
||||
dlname, lib->name);
|
||||
}
|
||||
return (obj == NULL) ? scheme_false : (Scheme_Object*)obj;
|
||||
|
||||
if (dlobj) {
|
||||
@cmake["obj" ffi-obj "dlobj" "dlname" "lib"]
|
||||
return (Scheme_Object *)obj;
|
||||
} else
|
||||
return scheme_false;
|
||||
}
|
||||
|
||||
/* (ffi-obj-lib ffi-obj) -> ffi-lib */
|
||||
|
|
|
@ -6120,7 +6120,7 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[])
|
|||
block_timer_signals(1);
|
||||
|
||||
result = rktio_process(scheme_rktio,
|
||||
command, argc, argv,
|
||||
command, argc, (rktio_const_string_t *)argv,
|
||||
stdout_fd, stdin_fd, stderr_fd,
|
||||
SCHEME_PATH_VAL(current_dir), envvars,
|
||||
flags);
|
||||
|
|
|
@ -31,6 +31,7 @@ OBJS = rktio_fs.@LTO@ \
|
|||
rktio_network.@LTO@ \
|
||||
rktio_pipe.@LTO@ \
|
||||
rktio_process.@LTO@ \
|
||||
rktio_signal.@LTO@ \
|
||||
rktio_envvars.@LTO@ \
|
||||
rktio_fs_change.@LTO@ \
|
||||
rktio_flock.@LTO@ \
|
||||
|
@ -38,6 +39,7 @@ OBJS = rktio_fs.@LTO@ \
|
|||
rktio_time.@LTO@ \
|
||||
rktio_syslog.@LTO@ \
|
||||
rktio_convert.@LTO@ \
|
||||
rktio_dll.@LTO@ \
|
||||
rktio_error.@LTO@ \
|
||||
rktio_hash.@LTO@ \
|
||||
rktio_wide.@LTO@ \
|
||||
|
@ -83,6 +85,9 @@ rktio_pipe.@LTO@: $(srcdir)/rktio_pipe.c $(RKTIO_HEADERS)
|
|||
rktio_process.@LTO@: $(srcdir)/rktio_process.c $(RKTIO_HEADERS)
|
||||
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_process.@LTO@ -c $(srcdir)/rktio_process.c
|
||||
|
||||
rktio_signal.@LTO@: $(srcdir)/rktio_signal.c $(RKTIO_HEADERS)
|
||||
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_signal.@LTO@ -c $(srcdir)/rktio_signal.c
|
||||
|
||||
rktio_envvars.@LTO@: $(srcdir)/rktio_envvars.c $(RKTIO_HEADERS)
|
||||
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_envvars.@LTO@ -c $(srcdir)/rktio_envvars.c
|
||||
|
||||
|
@ -104,6 +109,9 @@ rktio_syslog.@LTO@: $(srcdir)/rktio_syslog.c $(RKTIO_HEADERS)
|
|||
rktio_convert.@LTO@: $(srcdir)/rktio_convert.c $(RKTIO_HEADERS)
|
||||
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_convert.@LTO@ -c $(srcdir)/rktio_convert.c
|
||||
|
||||
rktio_dll.@LTO@: $(srcdir)/rktio_dll.c $(RKTIO_HEADERS)
|
||||
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_dll.@LTO@ -c $(srcdir)/rktio_dll.c
|
||||
|
||||
rktio_error.@LTO@: $(srcdir)/rktio_error.c $(RKTIO_HEADERS)
|
||||
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_error.@LTO@ -c $(srcdir)/rktio_error.c
|
||||
|
||||
|
|
|
@ -45,7 +45,8 @@
|
|||
(EOF WHITESPACE
|
||||
OPEN CLOSE COPEN CCLOSE SEMI COMMA STAR LSHIFT EQUAL
|
||||
__RKTIO_H__ EXTERN EXTERN/NOERR EXTERN/STEP EXTERN/ERR
|
||||
DEFINE TYPEDEF ENUM STRUCT VOID UNSIGNED SHORT INT CONST))
|
||||
DEFINE TYPEDEF ENUM STRUCT VOID UNSIGNED SHORT INT
|
||||
CONST NULLABLE))
|
||||
|
||||
(define lex
|
||||
(lexer-src-pos
|
||||
|
@ -73,6 +74,7 @@
|
|||
["RKTIO_EXTERN_NOERR" 'EXTERN/NOERR]
|
||||
["RKTIO_EXTERN_STEP" 'EXTERN/STEP]
|
||||
["RKTIO_EXTERN_ERR" 'EXTERN/ERR]
|
||||
["RKTIO_NULLABLE" 'NULLABLE]
|
||||
[(:seq (:or #\_ (:/ #\A #\Z #\a #\z))
|
||||
(:* (:or #\_ (:/ #\A #\Z #\a #\z #\0 #\9))))
|
||||
(token-ID (string->symbol lexeme))]
|
||||
|
@ -106,6 +108,7 @@
|
|||
[(DEFINE EXTERN/NOERR EXTERN) #f]
|
||||
[(DEFINE EXTERN/STEP EXTERN) #f]
|
||||
[(DEFINE EXTERN/ERR OPEN ID CLOSE EXTERN) #f]
|
||||
[(DEFINE NULLABLE) #f]
|
||||
[(STRUCT ID SEMI) #f]
|
||||
[(TYPEDEF <type> <id> SEMI)
|
||||
(if (eq? $2 $3)
|
||||
|
@ -147,6 +150,7 @@
|
|||
[(OPEN <expr> LSHIFT <expr> CLOSE) `(<< ,$2 ,$4)])
|
||||
(<type> [(ID) $1]
|
||||
[(CONST <type>) $2]
|
||||
[(NULLABLE <type>) `(nullable ,$2)]
|
||||
[(UNSIGNED SHORT) `unsigned-short]
|
||||
[(UNSIGNED INT) `unsigned]
|
||||
[(UNSIGNED) 'unsigned]
|
||||
|
@ -248,7 +252,8 @@
|
|||
[(and (pair? t) (eq? (car t) '*ref))
|
||||
(let ([s (update-type (cadr t))])
|
||||
(if (and as-argument?
|
||||
(or (pair? s)
|
||||
(or (and (pair? s)
|
||||
(not (eq? (car s) 'nullable)))
|
||||
(hash-ref defined-types s #f)))
|
||||
`(*ref ,s)
|
||||
`(ref ,s)))]
|
||||
|
|
|
@ -28,7 +28,7 @@ Return type conventions:
|
|||
information about a 0 result.
|
||||
|
||||
- A return type `rktio_tri_t` (alias for `int`) means that 0 is
|
||||
returned for an expected failuree, some `RKTIO_...` (alias for 1)
|
||||
returned for an expected failure, some `RKTIO_...` (alias for 1)
|
||||
is returned for success, and `RKTIO_...ERROR` (alias for -2) is
|
||||
returned for some error. The function will be annotated with
|
||||
`RKTIO_EXTERN_ERR(...)` to indicate the error value. Use
|
||||
|
@ -87,6 +87,8 @@ Thread and signal conventions:
|
|||
#define RKTIO_EXTERN_NOERR RKTIO_EXTERN
|
||||
#define RKTIO_EXTERN_STEP RKTIO_EXTERN
|
||||
|
||||
#define RKTIO_NULLABLE /* empty */
|
||||
|
||||
/*************************************************/
|
||||
/* Initialization and general datatypes */
|
||||
|
||||
|
@ -125,6 +127,11 @@ typedef unsigned short rktio_char16_t;
|
|||
/* A UTF-16 code unit. A `rktio_char16_t *` is meant to be the same as
|
||||
`wchar_t *` on Windows. */
|
||||
|
||||
typedef const char *rktio_const_string_t;
|
||||
/* An argument that is a NUL-terminated string, as opposed to a buffer
|
||||
where a length is provided separately and doesn't need to be
|
||||
NUL-terminated. */
|
||||
|
||||
/*************************************************/
|
||||
/* DLL paths */
|
||||
|
||||
|
@ -202,7 +209,7 @@ RKTIO_EXTERN_NOERR int rktio_fd_modes(rktio_t *rktio, rktio_fd_t *rfd);
|
|||
`rktio_system_fd` and those that are inferred. The
|
||||
`RKTIO_OPEN_INIT` flag is not recorded, however. */
|
||||
|
||||
RKTIO_EXTERN rktio_fd_t *rktio_open(rktio_t *rktio, const char *src, int modes);
|
||||
RKTIO_EXTERN rktio_fd_t *rktio_open(rktio_t *rktio, rktio_const_string_t src, int modes);
|
||||
/* Can report `RKTIO_ERROR_DOES_NOT_EXIST` in place of a system error
|
||||
in read mode, and can report `RKTIO_ERROR_IS_A_DIRECTORY`,
|
||||
`RKTIO_ERROR_EXISTS`, or `RKTIO_ERROR_ACCESS_DENIED` in place of a
|
||||
|
@ -295,9 +302,8 @@ rktio_tri_t rktio_poll_write_flushed(rktio_t *rktio, rktio_fd_t *rfd);
|
|||
(because the sent data doesn't persist beyond closing the pipe). */
|
||||
|
||||
RKTIO_EXTERN_ERR(RKTIO_LOCK_ERROR)
|
||||
rktio_tri_t rktio_file_lock_try(rktio_t *rktio, rktio_fd_t *rfd, int excl);
|
||||
RKTIO_EXTERN_ERR(RKTIO_LOCK_ERROR)
|
||||
rktio_ok_t rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd);
|
||||
rktio_tri_t rktio_file_lock_try(rktio_t *rktio, rktio_fd_t *rfd, rktio_bool_t excl);
|
||||
RKTIO_EXTERN rktio_ok_t rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd);
|
||||
/* Advisory file locks, where `excl` attempts to claim an exclusive
|
||||
lock. Whether these work in various situations depend on many OS
|
||||
details, where the differences involve promoting from non-exlcusive
|
||||
|
@ -348,7 +354,7 @@ typedef struct rktio_addrinfo_lookup_t rktio_addrinfo_lookup_t;
|
|||
typedef struct rktio_addrinfo_t rktio_addrinfo_t;
|
||||
|
||||
RKTIO_EXTERN rktio_addrinfo_lookup_t *rktio_start_addrinfo_lookup(rktio_t *rktio,
|
||||
const char *hostname, int portno,
|
||||
rktio_const_string_t hostname, int portno,
|
||||
int family, rktio_bool_t passive, rktio_bool_t tcp);
|
||||
/* The `family` argument should be one of the following: */
|
||||
#define RKTIO_FAMILY_ANY (-1)
|
||||
|
@ -385,7 +391,9 @@ rktio_tri_t rktio_poll_accept_ready(rktio_t *rktio, rktio_listener_t *listener);
|
|||
RKTIO_EXTERN rktio_fd_t *rktio_accept(rktio_t *rktio, rktio_listener_t *listener);
|
||||
/* Accepts one connection on a listener. */
|
||||
|
||||
RKTIO_EXTERN rktio_connect_t *rktio_start_connect(rktio_t *rktio, rktio_addrinfo_t *remote, rktio_addrinfo_t *local);
|
||||
RKTIO_EXTERN rktio_connect_t *rktio_start_connect(rktio_t *rktio,
|
||||
rktio_addrinfo_t *remote,
|
||||
RKTIO_NULLABLE rktio_addrinfo_t *local);
|
||||
/* Starts a connection request. Addreses must not be freed until the
|
||||
connection is complete, errored, or stopped. */
|
||||
|
||||
|
@ -417,7 +425,7 @@ RKTIO_EXTERN rktio_ok_t rktio_socket_shutdown(rktio_t *rktio, rktio_fd_t *rfd, i
|
|||
#define RKTIO_SHUTDOWN_READ 0
|
||||
#define RKTIO_SHUTDOWN_WRITE 1
|
||||
|
||||
RKTIO_EXTERN rktio_fd_t *rktio_udp_open(rktio_t *rktio, rktio_addrinfo_t *addr, int family);
|
||||
RKTIO_EXTERN rktio_fd_t *rktio_udp_open(rktio_t *rktio, RKTIO_NULLABLE rktio_addrinfo_t *addr, int family);
|
||||
/* The `addr` argument can be NULL to create a socket without
|
||||
specifying an interface, and `family` is used only if `addr` is not
|
||||
specified. */
|
||||
|
@ -428,11 +436,16 @@ RKTIO_EXTERN rktio_ok_t rktio_udp_bind(rktio_t *rktio, rktio_fd_t *rfd, rktio_ad
|
|||
RKTIO_EXTERN rktio_ok_t rktio_udp_connect(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr);
|
||||
|
||||
RKTIO_EXTERN_ERR(RKTIO_WRITE_ERROR)
|
||||
intptr_t rktio_udp_sendto(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr,
|
||||
intptr_t rktio_udp_sendto(rktio_t *rktio, rktio_fd_t *rfd, RKTIO_NULLABLE rktio_addrinfo_t *addr,
|
||||
const char *buffer, intptr_t len);
|
||||
/* Extends `rktio_write` to accept a destination `addr`, and binds `rfd` if it
|
||||
is not bound aready. The `addr` can be NULL if the socket is connected. */
|
||||
|
||||
RKTIO_EXTERN_ERR(RKTIO_WRITE_ERROR)
|
||||
intptr_t rktio_udp_sendto_in(rktio_t *rktio, rktio_fd_t *rfd, RKTIO_NULLABLE rktio_addrinfo_t *addr,
|
||||
const char *buffer, intptr_t start, intptr_t end);
|
||||
/* Like `rktio_udp_sendto`, but with starting and ending offsets within `buffer`. */
|
||||
|
||||
typedef struct rktio_length_and_addrinfo_t {
|
||||
intptr_t len;
|
||||
char **address; /* like the result of `rktio_socket_address` */
|
||||
|
@ -444,6 +457,10 @@ RKTIO_EXTERN rktio_length_and_addrinfo_t *rktio_udp_recvfrom(rktio_t *rktio, rkt
|
|||
be `RKTIO_ERROR_TRY_AGAIN` or `RKTIO_ERROR_INFO_TRY_AGAIN`, where
|
||||
the latter can happen if the sock claims to be ready to read. */
|
||||
|
||||
RKTIO_EXTERN rktio_length_and_addrinfo_t *rktio_udp_recvfrom_in(rktio_t *rktio, rktio_fd_t *rfd,
|
||||
char *buffer, intptr_t start, intptr_t end);
|
||||
/* Like `rktio_udp_recvfrom`, but with starting and ending offsets. */
|
||||
|
||||
RKTIO_EXTERN_ERR(RKTIO_PROP_ERROR) rktio_tri_t rktio_udp_get_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd);
|
||||
RKTIO_EXTERN rktio_ok_t rktio_udp_set_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd, rktio_bool_t on);
|
||||
RKTIO_EXTERN_ERR(RKTIO_PROP_ERROR) rktio_tri_t rktio_udp_get_multicast_ttl(rktio_t *rktio, rktio_fd_t *rfd);
|
||||
|
@ -451,19 +468,14 @@ RKTIO_EXTERN rktio_ok_t rktio_udp_set_multicast_ttl(rktio_t *rktio, rktio_fd_t *
|
|||
|
||||
#define RKTIO_PROP_ERROR (-2)
|
||||
|
||||
RKTIO_EXTERN char **rktio_socket_address(rktio_t *rktio, rktio_fd_t *rfd);
|
||||
RKTIO_EXTERN char **rktio_socket_peer_address(rktio_t *rktio, rktio_fd_t *rfd);
|
||||
RKTIO_EXTERN char **rktio_listener_address(rktio_t *rktio, rktio_listener_t *lnr);
|
||||
/* These return two strings in an array (where the array itself should
|
||||
be deallocated): address and service. */
|
||||
|
||||
RKTIO_EXTERN char *rktio_udp_multicast_interface(rktio_t *rktio, rktio_fd_t *rfd);
|
||||
RKTIO_EXTERN rktio_ok_t rktio_udp_set_multicast_interface(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr);
|
||||
RKTIO_EXTERN rktio_ok_t rktio_udp_set_multicast_interface(rktio_t *rktio, rktio_fd_t *rfd,
|
||||
RKTIO_NULLABLE rktio_addrinfo_t *addr);
|
||||
/* The `addr` argument can be NULL to auto-select the interface. */
|
||||
|
||||
RKTIO_EXTERN rktio_ok_t rktio_udp_change_multicast_group(rktio_t *rktio, rktio_fd_t *rfd,
|
||||
rktio_addrinfo_t *group_addr,
|
||||
rktio_addrinfo_t *intf_addr,
|
||||
RKTIO_NULLABLE rktio_addrinfo_t *intf_addr,
|
||||
int action);
|
||||
/* `action` values: */
|
||||
enum {
|
||||
|
@ -471,10 +483,16 @@ enum {
|
|||
RKTIO_DROP_MEMBERSHIP
|
||||
};
|
||||
|
||||
RKTIO_EXTERN char **rktio_socket_address(rktio_t *rktio, rktio_fd_t *rfd);
|
||||
RKTIO_EXTERN char **rktio_socket_peer_address(rktio_t *rktio, rktio_fd_t *rfd);
|
||||
RKTIO_EXTERN char **rktio_listener_address(rktio_t *rktio, rktio_listener_t *lnr);
|
||||
/* These return two strings in an array (where the array itself should
|
||||
be deallocated): address and service. */
|
||||
|
||||
/*************************************************/
|
||||
/* Environment variables */
|
||||
|
||||
RKTIO_EXTERN rktio_bool_t rktio_is_ok_envvar_name(rktio_t *rktio, const char *name);
|
||||
RKTIO_EXTERN rktio_bool_t rktio_is_ok_envvar_name(rktio_t *rktio, rktio_const_string_t name);
|
||||
/* Checks whether a string is valid as a new (e.g., no "="). */
|
||||
|
||||
RKTIO_EXTERN rktio_bool_t rktio_are_envvar_names_case_insensitive(rktio_t *rktio);
|
||||
|
@ -482,12 +500,12 @@ RKTIO_EXTERN rktio_bool_t rktio_are_envvar_names_case_insensitive(rktio_t *rktio
|
|||
That doesn't mean that clients need to case-fold names, but clients
|
||||
may want to immitate the OS. */
|
||||
|
||||
RKTIO_EXTERN char *rktio_getenv(rktio_t *rktio, const char *name);
|
||||
RKTIO_EXTERN char *rktio_getenv(rktio_t *rktio, rktio_const_string_t name);
|
||||
/* Gets an environment variable value, or reports
|
||||
`RKTIO_ERROR_NO_SUCH_ENVVAR` when returning NULL; the result must
|
||||
be freed. */
|
||||
|
||||
RKTIO_EXTERN rktio_ok_t rktio_setenv(rktio_t *rktio, const char *name, const char *val);
|
||||
RKTIO_EXTERN rktio_ok_t rktio_setenv(rktio_t *rktio, rktio_const_string_t name, rktio_const_string_t val);
|
||||
/* Set an environment variable's value, where a NULL value for `val`
|
||||
unsets it. */
|
||||
|
||||
|
@ -505,8 +523,8 @@ RKTIO_EXTERN rktio_envvars_t *rktio_envvars_copy(rktio_t *rktio, rktio_envvars_t
|
|||
RKTIO_EXTERN void rktio_envvars_free(rktio_t *rktio, rktio_envvars_t *envvars);
|
||||
/* Deallocates an environment-variables record: */
|
||||
|
||||
RKTIO_EXTERN char *rktio_envvars_get(rktio_t *rktio, rktio_envvars_t *envvars, const char *name);
|
||||
RKTIO_EXTERN void rktio_envvars_set(rktio_t *rktio, rktio_envvars_t *envvars, const char *name, const char *value);
|
||||
RKTIO_EXTERN char *rktio_envvars_get(rktio_t *rktio, rktio_envvars_t *envvars, rktio_const_string_t name);
|
||||
RKTIO_EXTERN void rktio_envvars_set(rktio_t *rktio, rktio_envvars_t *envvars, rktio_const_string_t name, rktio_const_string_t value);
|
||||
/* Access/update environment-variables record by name. */
|
||||
|
||||
RKTIO_EXTERN_NOERR intptr_t rktio_envvars_count(rktio_t *rktio, rktio_envvars_t *envvars);
|
||||
|
@ -527,9 +545,9 @@ typedef struct rktio_process_result_t {
|
|||
} rktio_process_result_t;
|
||||
|
||||
RKTIO_EXTERN rktio_process_result_t *rktio_process(rktio_t *rktio,
|
||||
const char *command, int argc, char **argv,
|
||||
rktio_const_string_t command, int argc, rktio_const_string_t *argv,
|
||||
rktio_fd_t *stdout_fd, rktio_fd_t *stdin_fd, rktio_fd_t *stderr_fd,
|
||||
const char *current_directory, rktio_envvars_t *envvars,
|
||||
rktio_const_string_t current_directory, rktio_envvars_t *envvars,
|
||||
int flags);
|
||||
/* `flags` flags: */
|
||||
#define RKTIO_PROCESS_NEW_GROUP (1<<0)
|
||||
|
@ -586,7 +604,7 @@ RKTIO_EXTERN_NOERR int rktio_fs_change_properties(rktio_t *rktio);
|
|||
typedef struct rktio_fs_change_t rktio_fs_change_t;
|
||||
struct rktio_ltps_t; /* forward reference */
|
||||
|
||||
RKTIO_EXTERN rktio_fs_change_t *rktio_fs_change(rktio_t *rktio, const char *path,
|
||||
RKTIO_EXTERN rktio_fs_change_t *rktio_fs_change(rktio_t *rktio, rktio_const_string_t path,
|
||||
struct rktio_ltps_t *ltps);
|
||||
/* Creates a filesystem-change tracker that reports changes in `path`
|
||||
after creation of the tracker. The properties repotred by
|
||||
|
@ -721,33 +739,33 @@ RKTIO_EXTERN void rktio_sleep(rktio_t *rktio, float nsecs, rktio_poll_set_t *fds
|
|||
/*************************************************/
|
||||
/* Files, directories, and links */
|
||||
|
||||
RKTIO_EXTERN rktio_bool_t rktio_file_exists(rktio_t *rktio, const char *filename);
|
||||
RKTIO_EXTERN rktio_bool_t rktio_directory_exists(rktio_t *rktio, const char *dirname);
|
||||
RKTIO_EXTERN rktio_bool_t rktio_link_exists(rktio_t *rktio, const char *filename);
|
||||
RKTIO_EXTERN rktio_bool_t rktio_is_regular_file(rktio_t *rktio, const char *filename);
|
||||
RKTIO_EXTERN rktio_bool_t rktio_file_exists(rktio_t *rktio, rktio_const_string_t filename);
|
||||
RKTIO_EXTERN rktio_bool_t rktio_directory_exists(rktio_t *rktio, rktio_const_string_t dirname);
|
||||
RKTIO_EXTERN rktio_bool_t rktio_link_exists(rktio_t *rktio, rktio_const_string_t filename);
|
||||
RKTIO_EXTERN rktio_bool_t rktio_is_regular_file(rktio_t *rktio, rktio_const_string_t filename);
|
||||
|
||||
RKTIO_EXTERN rktio_ok_t rktio_delete_file(rktio_t *rktio, const char *fn, rktio_bool_t enable_write_on_fail);
|
||||
RKTIO_EXTERN rktio_ok_t rktio_delete_file(rktio_t *rktio, rktio_const_string_t fn, rktio_bool_t enable_write_on_fail);
|
||||
|
||||
RKTIO_EXTERN rktio_ok_t rktio_rename_file(rktio_t *rktio, const char *dest, const char *src, rktio_bool_t exists_ok);
|
||||
RKTIO_EXTERN rktio_ok_t rktio_rename_file(rktio_t *rktio, rktio_const_string_t dest, rktio_const_string_t src, rktio_bool_t exists_ok);
|
||||
/* Can report `RKTIO_ERROR_EXISTS`. */
|
||||
|
||||
RKTIO_EXTERN char *rktio_get_current_directory(rktio_t *rktio);
|
||||
RKTIO_EXTERN rktio_ok_t rktio_set_current_directory(rktio_t *rktio, const char *path);
|
||||
RKTIO_EXTERN rktio_ok_t rktio_set_current_directory(rktio_t *rktio, rktio_const_string_t path);
|
||||
|
||||
RKTIO_EXTERN rktio_ok_t rktio_make_directory(rktio_t *rktio, const char *filename);
|
||||
RKTIO_EXTERN rktio_ok_t rktio_make_directory(rktio_t *rktio, rktio_const_string_t filename);
|
||||
/* Can report `RKTIO_ERROR_EXISTS`. */
|
||||
|
||||
RKTIO_EXTERN rktio_ok_t rktio_delete_directory(rktio_t *rktio, const char *filename, const char *current_directory,
|
||||
RKTIO_EXTERN rktio_ok_t rktio_delete_directory(rktio_t *rktio, rktio_const_string_t filename, rktio_const_string_t current_directory,
|
||||
rktio_bool_t enable_write_on_fail);
|
||||
/* The `current_directory` argument is used on Windows to avoid being
|
||||
in `filename` (instead) as a directory while trying to delete it.
|
||||
The `enable_write_on_fail` argument also applied to Windows. */
|
||||
|
||||
RKTIO_EXTERN char *rktio_readlink(rktio_t *rktio, const char *fullfilename);
|
||||
RKTIO_EXTERN char *rktio_readlink(rktio_t *rktio, rktio_const_string_t fullfilename);
|
||||
/* Argument should not have a trailing separator. Can report
|
||||
`RKTIO_ERROR_NOT_A_LINK`. */
|
||||
|
||||
RKTIO_EXTERN rktio_ok_t rktio_make_link(rktio_t *rktio, const char *src, const char *dest,
|
||||
RKTIO_EXTERN rktio_ok_t rktio_make_link(rktio_t *rktio, rktio_const_string_t src, rktio_const_string_t dest,
|
||||
rktio_bool_t dest_is_directory);
|
||||
/* The `dest_is_directory` argument is used only
|
||||
on Windows. Can report `RKTIO_ERROR_EXISTS`. */
|
||||
|
@ -757,10 +775,10 @@ RKTIO_EXTERN rktio_ok_t rktio_make_link(rktio_t *rktio, const char *src, const c
|
|||
|
||||
typedef intptr_t rktio_timestamp_t;
|
||||
|
||||
RKTIO_EXTERN rktio_filesize_t *rktio_file_size(rktio_t *rktio, const char *filename);
|
||||
RKTIO_EXTERN rktio_filesize_t *rktio_file_size(rktio_t *rktio, rktio_const_string_t filename);
|
||||
|
||||
RKTIO_EXTERN rktio_timestamp_t *rktio_get_file_modify_seconds(rktio_t *rktio, const char *file);
|
||||
RKTIO_EXTERN rktio_ok_t rktio_set_file_modify_seconds(rktio_t *rktio, const char *file, rktio_timestamp_t secs);
|
||||
RKTIO_EXTERN rktio_timestamp_t *rktio_get_file_modify_seconds(rktio_t *rktio, rktio_const_string_t file);
|
||||
RKTIO_EXTERN rktio_ok_t rktio_set_file_modify_seconds(rktio_t *rktio, rktio_const_string_t file, rktio_timestamp_t secs);
|
||||
|
||||
typedef struct rktio_identity_t {
|
||||
uintptr_t a, b, c;
|
||||
|
@ -768,7 +786,7 @@ typedef struct rktio_identity_t {
|
|||
} rktio_identity_t;
|
||||
|
||||
RKTIO_EXTERN rktio_identity_t *rktio_fd_identity(rktio_t *rktio, rktio_fd_t *fd);
|
||||
RKTIO_EXTERN rktio_identity_t *rktio_path_identity(rktio_t *rktio, const char *path, rktio_bool_t follow_links);
|
||||
RKTIO_EXTERN rktio_identity_t *rktio_path_identity(rktio_t *rktio, rktio_const_string_t path, rktio_bool_t follow_links);
|
||||
|
||||
/*************************************************/
|
||||
/* Permissions */
|
||||
|
@ -781,11 +799,11 @@ RKTIO_EXTERN rktio_identity_t *rktio_path_identity(rktio_t *rktio, const char *p
|
|||
#define RKTIO_PERMISSION_ERROR (-1)
|
||||
|
||||
RKTIO_EXTERN_ERR(RKTIO_PERMISSION_ERROR)
|
||||
int rktio_get_file_or_directory_permissions(rktio_t *rktio, const char *filename, rktio_bool_t all_bits);
|
||||
int rktio_get_file_or_directory_permissions(rktio_t *rktio, rktio_const_string_t filename, rktio_bool_t all_bits);
|
||||
/* Result is `RKTIO_PERMISSION_ERROR` for error, otherwise a combination of
|
||||
bits. If not `all_bits`, then use constants above. */
|
||||
|
||||
RKTIO_EXTERN rktio_ok_t rktio_set_file_or_directory_permissions(rktio_t *rktio, const char *filename, int new_bits);
|
||||
RKTIO_EXTERN rktio_ok_t rktio_set_file_or_directory_permissions(rktio_t *rktio, rktio_const_string_t filename, int new_bits);
|
||||
/* The `new_bits` format corresponds to `all_bits` for getting permissions.
|
||||
Can report `RKTIO_ERROR_BAD_PERMISSION` for bits that make no sense. */
|
||||
|
||||
|
@ -794,7 +812,7 @@ RKTIO_EXTERN rktio_ok_t rktio_set_file_or_directory_permissions(rktio_t *rktio,
|
|||
|
||||
typedef struct rktio_directory_list_t rktio_directory_list_t;
|
||||
|
||||
RKTIO_EXTERN rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, const char *dirname);
|
||||
RKTIO_EXTERN rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, rktio_const_string_t dirname);
|
||||
/* On Windows, the given `dirname` must be normalized and not have
|
||||
`.` or `..`: */
|
||||
|
||||
|
@ -816,7 +834,7 @@ RKTIO_EXTERN char **rktio_filesystem_roots(rktio_t *rktio);
|
|||
|
||||
typedef struct rktio_file_copy_t rktio_file_copy_t;
|
||||
|
||||
RKTIO_EXTERN_STEP rktio_file_copy_t *rktio_copy_file_start(rktio_t *rktio, const char *dest, const char *src,
|
||||
RKTIO_EXTERN_STEP rktio_file_copy_t *rktio_copy_file_start(rktio_t *rktio, rktio_const_string_t dest, rktio_const_string_t src,
|
||||
rktio_bool_t exists_ok);
|
||||
/* Starts a file copy. Depending on the OS, this step may perform the
|
||||
whole copy, or it may just get started. Can report
|
||||
|
@ -870,7 +888,7 @@ enum {
|
|||
RKTIO_PATH_INIT_FILE
|
||||
};
|
||||
|
||||
RKTIO_EXTERN char *rktio_expand_user_tilde(rktio_t *rktio, const char *filename);
|
||||
RKTIO_EXTERN char *rktio_expand_user_tilde(rktio_t *rktio, rktio_const_string_t filename);
|
||||
/* Path must start with tilde, otherwise `RKTIO_ERROR_NO_TILDE`.
|
||||
Other possible errors are `RKTIO_ERROR_ILL_FORMED_USER` and
|
||||
`RKTIO_ERROR_UNKNOWN_USER`. */
|
||||
|
@ -902,6 +920,23 @@ RKTIO_EXTERN void rktio_flush_signals_received(rktio_t *rktio);
|
|||
/* Clears any pending signal so that it doesn't interrupt the next
|
||||
`rktio_sleep`. */
|
||||
|
||||
RKTIO_EXTERN void rktio_install_os_signal_handler(rktio_t *rktio);
|
||||
/* Installs OS-level handlers for SIGINT, SIGTERM, and SIGHUP (or
|
||||
Ctl-C on Windows) to signal the handle of `rktio` and also record
|
||||
the signal for reporting via `rktio_poll_os_signal`. Only one
|
||||
`rktio` can be registered this way at a time. This function must
|
||||
not be called in two threads at the same time. */
|
||||
|
||||
RKTIO_EXTERN_NOERR int rktio_poll_os_signal(rktio_t *rktio);
|
||||
/* Returns one of the following, not counting the last one: */
|
||||
#define RKTIO_OS_SIGNAL_NONE (-1)
|
||||
enum {
|
||||
RKTIO_OS_SIGNAL_INT,
|
||||
RKTIO_OS_SIGNAL_TERM,
|
||||
RKTIO_OS_SIGNAL_HUP,
|
||||
RKTIO_NUM_OS_SIGNALS
|
||||
};
|
||||
|
||||
/*************************************************/
|
||||
/* Time and date */
|
||||
|
||||
|
@ -943,10 +978,10 @@ enum {
|
|||
};
|
||||
|
||||
RKTIO_EXTERN rktio_ok_t rktio_shell_execute(rktio_t *rktio,
|
||||
const char *verb,
|
||||
const char *target,
|
||||
const char *arg,
|
||||
const char *dir,
|
||||
rktio_const_string_t verb,
|
||||
rktio_const_string_t target,
|
||||
rktio_const_string_t arg,
|
||||
rktio_const_string_t dir,
|
||||
int show_mode);
|
||||
/* Supported only on Windows to run `ShellExecute`. The `dir` argument
|
||||
needs to have normalized path separators. */
|
||||
|
@ -954,7 +989,7 @@ RKTIO_EXTERN rktio_ok_t rktio_shell_execute(rktio_t *rktio,
|
|||
/*************************************************/
|
||||
/* Path conversion */
|
||||
|
||||
RKTIO_EXTERN rktio_char16_t *rktio_path_to_wide_path(rktio_t *rktio, const char *p);
|
||||
RKTIO_EXTERN rktio_char16_t *rktio_path_to_wide_path(rktio_t *rktio, rktio_const_string_t p);
|
||||
RKTIO_EXTERN_NOERR char *rktio_wide_path_to_path(rktio_t *rktio, const rktio_char16_t *wp);
|
||||
/* Convert to/from the OS's native path representation. These
|
||||
functions are useful only on Windows. The `rktio_path_to_wide_path`
|
||||
|
@ -963,8 +998,8 @@ RKTIO_EXTERN_NOERR char *rktio_wide_path_to_path(rktio_t *rktio, const rktio_cha
|
|||
/*************************************************/
|
||||
/* Logging */
|
||||
|
||||
RKTIO_EXTERN rktio_ok_t rktio_syslog(rktio_t *rktio, int level, const char *name, const char *msg,
|
||||
const char *exec_name);
|
||||
RKTIO_EXTERN rktio_ok_t rktio_syslog(rktio_t *rktio, int level, rktio_const_string_t name, rktio_const_string_t msg,
|
||||
rktio_const_string_t exec_name);
|
||||
/* Adds a message to the system log. The `name` argument can be NULL,
|
||||
and it is added to the front of the message with a separating ": "
|
||||
if non_NULL. The `exec_name` is the current executable name; it's
|
||||
|
@ -991,7 +1026,7 @@ RKTIO_EXTERN_NOERR int rktio_convert_properties(rktio_t *rktio);
|
|||
|
||||
typedef struct rktio_converter_t rktio_converter_t;
|
||||
|
||||
RKTIO_EXTERN rktio_converter_t *rktio_converter_open(rktio_t *rktio, const char *to_enc, const char *from_enc);
|
||||
RKTIO_EXTERN rktio_converter_t *rktio_converter_open(rktio_t *rktio, rktio_const_string_t to_enc, rktio_const_string_t from_enc);
|
||||
/* Creates an encoding converter. */
|
||||
|
||||
RKTIO_EXTERN void rktio_converter_close(rktio_t *rktio, rktio_converter_t *cvt);
|
||||
|
@ -1014,15 +1049,30 @@ intptr_t rktio_convert(rktio_t *rktio,
|
|||
|
||||
#define RKTIO_CONVERT_ERROR (-1)
|
||||
|
||||
RKTIO_EXTERN char *rktio_locale_recase(rktio_t *rktio,
|
||||
rktio_bool_t to_up,
|
||||
char *in);
|
||||
typedef struct rktio_convert_result_t {
|
||||
intptr_t in_consumed; /* input bytes converted */
|
||||
intptr_t out_produced; /* output bytes produced */
|
||||
intptr_t converted; /* characters converted, can be `RKTIO_CONVERT_ERROR` */
|
||||
} rktio_convert_result_t;
|
||||
|
||||
RKTIO_EXTERN rktio_convert_result_t *rktio_convert_in(rktio_t *rktio,
|
||||
rktio_converter_t *cvt,
|
||||
char *in, intptr_t in_start, intptr_t in_end,
|
||||
char *out, intptr_t out_start, intptr_t out_end);
|
||||
/* The same as rktio_convert`, but accepting start and end positions
|
||||
and returning results as an allocated struct. A conversion error
|
||||
doesn't return a NULL result; instead, `converted` in the result
|
||||
reports the error. */
|
||||
|
||||
RKTIO_EXTERN_NOERR char *rktio_locale_recase(rktio_t *rktio,
|
||||
rktio_bool_t to_up,
|
||||
rktio_const_string_t in);
|
||||
/* Upcases (of `to_up`) or downcases (if `!to_up`) the content of `in`
|
||||
using the current locale's encoding and case conversion. */
|
||||
|
||||
RKTIO_EXTERN rktio_char16_t *rktio_recase_utf16(rktio_t *rktio,
|
||||
rktio_bool_t to_up, rktio_char16_t *s1,
|
||||
intptr_t len, intptr_t *olen);
|
||||
RKTIO_EXTERN_NOERR rktio_char16_t *rktio_recase_utf16(rktio_t *rktio,
|
||||
rktio_bool_t to_up, rktio_char16_t *s1,
|
||||
intptr_t len, intptr_t *olen);
|
||||
/* Converts the case of a string encoded in UTF-16 for the system's
|
||||
default locale if the OS provided direct support for it. The
|
||||
`RKTIO_CONVERT_RECASE_UTF16 property from
|
||||
|
@ -1030,7 +1080,7 @@ RKTIO_EXTERN rktio_char16_t *rktio_recase_utf16(rktio_t *rktio,
|
|||
Takes and optionally returns a length (`olen` can be NULL), but the
|
||||
UTF-16 sequence is expected to have no nuls. */
|
||||
|
||||
RKTIO_EXTERN_NOERR int rktio_locale_strcoll(rktio_t *rktio, char *s1, char *s2);
|
||||
RKTIO_EXTERN_NOERR int rktio_locale_strcoll(rktio_t *rktio, rktio_const_string_t s1, rktio_const_string_t s2);
|
||||
/* Returns -1 if `s1` is less than `s2` by the current locale's
|
||||
comparison, positive is `s1` is greater, and 0 if the strings
|
||||
are equal. */
|
||||
|
@ -1049,7 +1099,7 @@ RKTIO_EXTERN_NOERR int rktio_strcoll_utf16(rktio_t *rktio,
|
|||
RKTIO_EXTERN char *rktio_locale_encoding(rktio_t *rktio);
|
||||
/* Returns the name of the current locale's encoding. */
|
||||
|
||||
RKTIO_EXTERN void rktio_set_locale(rktio_t *rktio, char *name);
|
||||
RKTIO_EXTERN void rktio_set_locale(rktio_t *rktio, rktio_const_string_t name);
|
||||
/* Sets the current locale, which affects string comparisons and
|
||||
conversions. It can also affect the C library's character-property
|
||||
predicates and number printing/parsing. The empty string
|
||||
|
@ -1065,6 +1115,38 @@ RKTIO_EXTERN char *rktio_system_language_country(rktio_t *rktio);
|
|||
/* Returns the current system's language in country in a 5-character
|
||||
format such as "en_US". */
|
||||
|
||||
/*************************************************/
|
||||
/* Dynamically loaded libraries */
|
||||
|
||||
typedef struct rktio_dll_t rktio_dll_t;
|
||||
|
||||
RKTIO_EXTERN rktio_dll_t *rktio_dll_open(rktio_t *rktio, rktio_const_string_t name, rktio_bool_t as_global);
|
||||
/* Loads a DLL using system-provided functions and search rules, such
|
||||
as dlopen() and its rules. If `as_global` is true, then the library
|
||||
is loaded in "global" mode, which has implications for other
|
||||
libraries trying to find bindings and for searching within the
|
||||
specific library for a binding. The `name` argument can be NULL
|
||||
to mean "the current executable".
|
||||
|
||||
Some system error-reporting protocols do not fit nicely into the
|
||||
normal rktio error model. If the `RKTIO_ERROR_DLL` error is
|
||||
reported, then rktio_dll_get_error() must be used before any other
|
||||
`rktio_dll_...` call to get an error string.
|
||||
|
||||
Currently, there's no way to close and unload a DLL. Even when the
|
||||
given `rktio` is closed with `rktio_destroy`, loaded libraries
|
||||
remain in the process. */
|
||||
|
||||
RKTIO_EXTERN void *rktio_dll_find_object(rktio_t *rktio, rktio_dll_t *dll, rktio_const_string_t name);
|
||||
/* Find an address within `dll` for the `name` export.
|
||||
|
||||
An error result can be `RKTIO_ERROR_DLL` as for `rktio_dll_open`. */
|
||||
|
||||
RKTIO_EXTERN char *rktio_dll_get_error(rktio_t *rktio);
|
||||
/* Returns an error for a previous `rktio_dll_...` call, or NULL
|
||||
if no error string is available or has already been returned.
|
||||
See `rktio_dll_open` for more information. */
|
||||
|
||||
/*************************************************/
|
||||
/* Errors */
|
||||
|
||||
|
@ -1113,6 +1195,7 @@ enum {
|
|||
RKTIO_ERROR_CONVERT_BAD_SEQUENCE,
|
||||
RKTIO_ERROR_CONVERT_PREMATURE_END,
|
||||
RKTIO_ERROR_CONVERT_OTHER,
|
||||
RKTIO_ERROR_DLL, /* use `rktio_dll_get_error` atomically to get error */
|
||||
};
|
||||
|
||||
RKTIO_EXTERN_NOERR int rktio_get_last_error_step(rktio_t *rktio);
|
||||
|
@ -1130,9 +1213,9 @@ RKTIO_EXTERN void rktio_remap_last_error(rktio_t *rktio);
|
|||
|
||||
RKTIO_EXTERN_NOERR const char *rktio_get_last_error_string(rktio_t *rktio);
|
||||
RKTIO_EXTERN_NOERR const char *rktio_get_error_string(rktio_t *rktio, int kind, int errid);
|
||||
/* The returned strings for `rktio_...error_string` should not be
|
||||
/* The returned string for `rktio_...error_string` should not be
|
||||
deallocated, but it only lasts reliably until the next call to
|
||||
either of the functions. */
|
||||
either of the functions. */
|
||||
|
||||
/*************************************************/
|
||||
|
||||
|
|
|
@ -205,7 +205,7 @@ int rktio_convert_properties(rktio_t *rktio)
|
|||
/* Current locale */
|
||||
/*============================================================*/
|
||||
|
||||
void rktio_set_locale(rktio_t *rktio, char *name)
|
||||
void rktio_set_locale(rktio_t *rktio, const char *name)
|
||||
{
|
||||
/* We only need CTYPE and COLLATE; two calls seem to be much
|
||||
faster than one call with ALL */
|
||||
|
@ -463,13 +463,36 @@ intptr_t rktio_convert(rktio_t *rktio,
|
|||
return (intptr_t)r;
|
||||
}
|
||||
|
||||
rktio_convert_result_t *rktio_convert_in(rktio_t *rktio,
|
||||
rktio_converter_t *cvt,
|
||||
char *in, intptr_t in_start, intptr_t in_end,
|
||||
char *out, intptr_t out_start, intptr_t out_end)
|
||||
{
|
||||
intptr_t converted;
|
||||
intptr_t in_left = in_end - in_start;
|
||||
intptr_t out_left = out_end - out_start;
|
||||
char *in_p = in + in_start;
|
||||
char *out_p = out + out_start;
|
||||
rktio_convert_result_t *r;
|
||||
|
||||
converted = rktio_convert(rktio, cvt, (in ? &in_p : NULL), &in_left, &out_p, &out_left);
|
||||
|
||||
r = malloc(sizeof(rktio_convert_result_t));
|
||||
|
||||
r->in_consumed = in_p - (in + in_start);
|
||||
r->out_produced = out_p - (out + out_start);
|
||||
r->converted = converted;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*============================================================*/
|
||||
/* Case conversion */
|
||||
/*============================================================*/
|
||||
|
||||
char *rktio_locale_recase(rktio_t *rktio,
|
||||
rktio_bool_t to_up,
|
||||
char *in)
|
||||
const char *in)
|
||||
{
|
||||
char *out;
|
||||
|
||||
|
@ -627,7 +650,7 @@ rktio_char16_t *rktio_recase_utf16(rktio_t *rktio, rktio_bool_t to_up, rktio_cha
|
|||
/* Native string comparison */
|
||||
/*============================================================*/
|
||||
|
||||
int rktio_locale_strcoll(rktio_t *rktio, char *s1, char *s2)
|
||||
int rktio_locale_strcoll(rktio_t *rktio, const char *s1, const char *s2)
|
||||
{
|
||||
return strcoll(s1, s2);
|
||||
}
|
||||
|
|
350
racket/src/rktio/rktio_dll.c
Normal file
350
racket/src/rktio/rktio_dll.c
Normal file
|
@ -0,0 +1,350 @@
|
|||
#include "rktio.h"
|
||||
#include "rktio_private.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct rktio_dll_object_t rktio_dll_object_t;
|
||||
|
||||
#ifdef RKTIO_SYSTEM_UNIX
|
||||
static void get_dl_error(rktio_t *rktio);
|
||||
#endif
|
||||
|
||||
/*========================================================================*/
|
||||
/* Opening a DLL */
|
||||
/*========================================================================*/
|
||||
|
||||
#ifdef RKTIO_SYSTEM_UNIX
|
||||
#include <dlfcn.h>
|
||||
typedef void *dll_handle_t;
|
||||
#endif
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
typedef HANDLE dll_handle_t;
|
||||
#endif
|
||||
|
||||
struct rktio_dll_t {
|
||||
void *handle;
|
||||
char *name;
|
||||
rktio_hash_t *objects_by_name;
|
||||
rktio_dll_object_t *all_objects;
|
||||
int search_exe;
|
||||
rktio_dll_t *all_next; /* chain for all DLLs */
|
||||
rktio_dll_t *hash_next; /* chain for hash collisions */
|
||||
};
|
||||
|
||||
rktio_dll_t *rktio_dll_open(rktio_t *rktio, rktio_const_string_t name, rktio_bool_t as_global)
|
||||
{
|
||||
rktio_dll_t *dll, *dlls;
|
||||
intptr_t key;
|
||||
dll_handle_t handle;
|
||||
int null_ok = 0;
|
||||
|
||||
if (!rktio->dlls_by_name)
|
||||
rktio->dlls_by_name = rktio_hash_new();
|
||||
|
||||
if (name)
|
||||
key = rktio_hash_string(name);
|
||||
else
|
||||
key = 0;
|
||||
|
||||
dll = dlls = rktio_hash_get(rktio->dlls_by_name, key);
|
||||
|
||||
while (dll) {
|
||||
if (!name) {
|
||||
if (!dll->name)
|
||||
break;
|
||||
} else if (!strcmp(dll->name, name)) {
|
||||
break;
|
||||
}
|
||||
dll = dll->hash_next;
|
||||
}
|
||||
|
||||
if (dll)
|
||||
return dll;
|
||||
|
||||
#ifdef RKTIO_SYSTEM_UNIX
|
||||
# if defined(__ANDROID__)
|
||||
if (!name) handle = RTLD_DEFAULT; else
|
||||
# elif defined(__CYGWIN32__)
|
||||
if (!name) { handle = RTLD_DEFAULT; null_ok = 1; } else
|
||||
# endif
|
||||
handle = dlopen(name, RTLD_NOW | (as_global ? RTLD_GLOBAL : RTLD_LOCAL));
|
||||
|
||||
if (!handle && !null_ok)
|
||||
get_dl_error(rktio);
|
||||
#endif
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
if (!name) {
|
||||
/* openning the executable is marked by a NULL handle */
|
||||
handle = NULL;
|
||||
null_ok = 1;
|
||||
} else {
|
||||
handle = LoadLibraryW(WIDE_PATH_temp(name));
|
||||
if (!handle)
|
||||
get_windows_error();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!handle && !null_ok)
|
||||
return NULL;
|
||||
|
||||
dll = malloc(sizeof(rktio_dll_t));
|
||||
dll->handle = handle;
|
||||
dll->name = (name ? MSC_IZE(strdup)(name) : NULL);
|
||||
dll->objects_by_name = rktio_hash_new();
|
||||
dll->all_objects = NULL;
|
||||
dll->search_exe = (name == NULL);
|
||||
|
||||
dll->all_next = rktio->all_dlls;
|
||||
rktio->all_dlls = dll;
|
||||
|
||||
dll->hash_next = dlls;
|
||||
rktio_hash_set(rktio->dlls_by_name, key, dll);
|
||||
|
||||
return dll;
|
||||
}
|
||||
|
||||
/*========================================================================*/
|
||||
/* Searching all DLLs on Windows */
|
||||
/*========================================================================*/
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
|
||||
/* We'd like to use EnumProcessModules to find all loaded DLLs, but it's
|
||||
only available in NT 4.0 and later. The alternative, Module32{First,Next},
|
||||
is available *except* for NT 4.0! So we try EnumProcessModules first. */
|
||||
|
||||
int epm_tried = 0;
|
||||
typedef BOOL (WINAPI *EnumProcessModules_t)(HANDLE hProcess,
|
||||
HMODULE* lphModule,
|
||||
DWORD cb,
|
||||
LPDWORD lpcbNeeded);
|
||||
EnumProcessModules_t _EnumProcessModules;
|
||||
#include <tlhelp32.h>
|
||||
|
||||
static BOOL do_EnumProcessModules(HANDLE hProcess, HMODULE* lphModule,
|
||||
DWORD cb, LPDWORD lpcbNeeded)
|
||||
{
|
||||
if (!epm_tried) {
|
||||
HMODULE hm;
|
||||
hm = LoadLibraryW(L"psapi.dll");
|
||||
if (hm)
|
||||
_EnumProcessModules = (EnumProcessModules_t)GetProcAddress(hm, "EnumProcessModules");
|
||||
if (!_EnumProcessModules) {
|
||||
hm = LoadLibraryW(L"kernel32.dll");
|
||||
if (hm)
|
||||
_EnumProcessModules = (EnumProcessModules_t)GetProcAddress(hm, "EnumProcessModules");
|
||||
}
|
||||
epm_tried = 1;
|
||||
}
|
||||
|
||||
if (_EnumProcessModules)
|
||||
return _EnumProcessModules(hProcess, lphModule, cb, lpcbNeeded);
|
||||
else {
|
||||
HANDLE snapshot;
|
||||
MODULEENTRY32 mod;
|
||||
int i, ok;
|
||||
|
||||
snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,
|
||||
GetCurrentProcessId());
|
||||
if (snapshot == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; 1; i++) {
|
||||
mod.dwSize = sizeof(mod);
|
||||
if (!i)
|
||||
ok = Module32First(snapshot, &mod);
|
||||
else
|
||||
ok = Module32Next(snapshot, &mod);
|
||||
if (!ok)
|
||||
break;
|
||||
if (cb >= sizeof(HMODULE)) {
|
||||
lphModule[i] = mod.hModule;
|
||||
cb -= sizeof(HMODULE);
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(snapshot);
|
||||
*lpcbNeeded = i * sizeof(HMODULE);
|
||||
return GetLastError() == ERROR_NO_MORE_FILES;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*========================================================================*/
|
||||
/* Searching for an object in a DLL */
|
||||
/*========================================================================*/
|
||||
|
||||
#ifdef __ANDROID__
|
||||
static int adjustment_set;
|
||||
static uintptr_t adjustment;
|
||||
#endif
|
||||
|
||||
struct rktio_dll_object_t {
|
||||
char *name;
|
||||
void *address;
|
||||
rktio_dll_object_t *all_next; /* chain for all object */
|
||||
rktio_dll_object_t *hash_next; /* chain for hash collisions */
|
||||
};
|
||||
|
||||
void *rktio_dll_find_object(rktio_t *rktio, rktio_dll_t *dll, rktio_const_string_t name)
|
||||
{
|
||||
rktio_dll_object_t *objs, *obj;
|
||||
intptr_t key;
|
||||
void *address;
|
||||
|
||||
key = rktio_hash_string(name);
|
||||
objs = rktio_hash_get(dll->objects_by_name, key);
|
||||
|
||||
for (obj = objs; obj; obj = obj->hash_next)
|
||||
if (!strcmp(name, obj->name))
|
||||
break;
|
||||
|
||||
if (obj)
|
||||
return obj->address;
|
||||
|
||||
#ifdef RKTIO_SYSTEM_UNIX
|
||||
address = dlsym(dll->handle, name);
|
||||
|
||||
# ifdef __ANDROID__
|
||||
if (address && (dll->handle == RTLD_DEFAULT)) {
|
||||
/* Compensate for a bug in dlsym() that gets the address wrong by
|
||||
an offset (incorrect use of `link_bias'?): */
|
||||
if (!adjustment_set) {
|
||||
adjustment = ((uintptr_t)scheme_start_atomic_no_break
|
||||
- (uintptr_t)dlsym(RTLD_DEFAULT, "rktio_dll_find_object"));
|
||||
adjustment_set = 1;
|
||||
}
|
||||
address = (char *)address + adjustment;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (!address && dll->search_exe) {
|
||||
/* Try every handle in the table of opened libraries. */
|
||||
for (dll = rktio->all_dlls; dll; dll = dll->all_next) {
|
||||
address = dlsym(dll->handle, name);
|
||||
if (address) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!address) {
|
||||
get_dl_error(rktio);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
if (dll->handle)
|
||||
address = GetProcAddress(dll->handle, name);
|
||||
else {
|
||||
/* this is for the executable-open case, which was marked by a NULL
|
||||
* handle; deal with it by searching all current modules */
|
||||
# define NUM_QUICK_MODS 16
|
||||
HMODULE *mods, me, quick_mods[NUM_QUICK_MODS];
|
||||
DWORD cnt = NUM_QUICK_MODS * sizeof(HMODULE), actual_cnt, i;
|
||||
me = GetCurrentProcess();
|
||||
mods = quick_mods;
|
||||
if (do_EnumProcessModules(me, mods, cnt, &actual_cnt)) {
|
||||
if (actual_cnt > cnt) {
|
||||
cnt = actual_cnt;
|
||||
mods = malloc(cnt);
|
||||
if (!do_EnumProcessModules(me, mods, cnt, &actual_cnt))
|
||||
mods = NULL;
|
||||
} else
|
||||
cnt = actual_cnt;
|
||||
} else
|
||||
mods = NULL;
|
||||
if (mods) {
|
||||
cnt /= sizeof(HMODULE);
|
||||
for (i = 0; i < cnt; i++) {
|
||||
address = GetProcAddress(mods[i], name);
|
||||
if (address) break;
|
||||
}
|
||||
} else
|
||||
address = NULL;
|
||||
if (mods != quick_mods)
|
||||
free(mods);
|
||||
}
|
||||
|
||||
if (!address) {
|
||||
get_windows_error();
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
obj = malloc(sizeof(rktio_dll_object_t));
|
||||
obj->name = MSC_IZE(strdup)(name);
|
||||
obj->address = address;
|
||||
|
||||
obj->hash_next = objs;
|
||||
rktio_hash_set(dll->objects_by_name, key, obj);
|
||||
|
||||
obj->all_next = dll->all_objects;
|
||||
dll->all_objects = obj;
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
/*========================================================================*/
|
||||
/* Errors */
|
||||
/*========================================================================*/
|
||||
|
||||
#ifdef RKTIO_SYSTEM_UNIX
|
||||
static void get_dl_error(rktio_t *rktio)
|
||||
{
|
||||
char *s = dlerror();
|
||||
|
||||
if (rktio->dll_error)
|
||||
free(rktio->dll_error);
|
||||
|
||||
if (s)
|
||||
rktio->dll_error = strdup(s);
|
||||
else
|
||||
rktio->dll_error = strdup("unknown error");
|
||||
}
|
||||
#endif
|
||||
|
||||
RKTIO_EXTERN char *rktio_dll_get_error(rktio_t *rktio)
|
||||
{
|
||||
#ifdef RKTIO_SYSTEM_UNIX
|
||||
char *s = rktio->dll_error;
|
||||
rktio->dll_error = NULL;
|
||||
return s;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*========================================================================*/
|
||||
/* Clean up */
|
||||
/*========================================================================*/
|
||||
|
||||
void rktio_dll_clean(rktio_t *rktio)
|
||||
{
|
||||
rktio_dll_t *dll, *next_dll;
|
||||
rktio_dll_object_t *obj, *next_obj;
|
||||
|
||||
for (dll = rktio->all_dlls; dll; dll = next_dll) {
|
||||
next_dll = dll->all_next;
|
||||
for (obj = dll->all_objects; obj; obj = next_obj) {
|
||||
next_obj = obj->all_next;
|
||||
free(obj->name);
|
||||
free(obj);
|
||||
}
|
||||
if (dll->name)
|
||||
free(dll->name);
|
||||
if (dll->objects_by_name)
|
||||
rktio_hash_free(dll->objects_by_name, 0);
|
||||
free(dll);
|
||||
}
|
||||
|
||||
if (rktio->dlls_by_name)
|
||||
rktio_hash_free(rktio->dlls_by_name, 0);
|
||||
|
||||
#ifdef RKTIO_SYSTEM_UNIX
|
||||
if (rktio->dll_error)
|
||||
free(rktio->dll_error);
|
||||
#endif
|
||||
}
|
|
@ -39,6 +39,7 @@ err_str_t err_strs[] = {
|
|||
{ RKTIO_ERROR_CONVERT_BAD_SEQUENCE, "ill-formed input encountered in encoding conversion" },
|
||||
{ RKTIO_ERROR_CONVERT_PREMATURE_END, "input encoding ended prematurely" },
|
||||
{ RKTIO_ERROR_CONVERT_OTHER, "encoding conversion encountered an error" },
|
||||
{ RKTIO_ERROR_DLL, "error is from dlopen" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
|
|
|
@ -444,7 +444,6 @@ static int UNC_stat(rktio_t *rktio, const char *dirname, int *flags, int *isdir,
|
|||
}
|
||||
|
||||
do {
|
||||
init_procs();
|
||||
if (dest) free(dest);
|
||||
dest_len = len + 1;
|
||||
dest = malloc(dest_len);
|
||||
|
|
|
@ -2,14 +2,16 @@
|
|||
#include "rktio_private.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
/* A hash key must be non-negative, and each value must be non-NULL */
|
||||
|
||||
struct rktio_hash_t {
|
||||
struct bucket_t *buckets;
|
||||
intptr_t size, count;
|
||||
};
|
||||
|
||||
typedef struct bucket_t {
|
||||
/* v is non-NULL => bucket is filled */
|
||||
/* v is NULL and fd is -1 => was removed */
|
||||
/* `v` is non-NULL => bucket is filled */
|
||||
/* `v` is NULL and `key` is -1 => was removed */
|
||||
intptr_t key;
|
||||
void *v;
|
||||
} bucket_t;
|
||||
|
@ -177,3 +179,26 @@ void rktio_hash_set(rktio_hash_t *ht, intptr_t key, void *v)
|
|||
do_rehash(ht, ht->size << 1);
|
||||
}
|
||||
}
|
||||
|
||||
intptr_t rktio_hash_string(const char *s)
|
||||
{
|
||||
intptr_t key;
|
||||
uintptr_t k = 0;
|
||||
int c;
|
||||
|
||||
while (1) {
|
||||
c = *((unsigned char *)s);
|
||||
if (!c)
|
||||
break;
|
||||
k += c;
|
||||
k += (k << 10);
|
||||
k ^= (k >> 6);
|
||||
s++;
|
||||
}
|
||||
|
||||
key = k;
|
||||
if (key < 0)
|
||||
key = (k >> 1);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ rktio_t *rktio_init(void)
|
|||
void rktio_destroy(rktio_t *rktio)
|
||||
{
|
||||
rktio_syslog_clean(rktio);
|
||||
rktio_dll_clean(rktio);
|
||||
rktio_error_clean(rktio);
|
||||
rktio_process_deinit(rktio);
|
||||
rktio_free_ghbn(rktio);
|
||||
|
|
|
@ -1823,6 +1823,12 @@ intptr_t rktio_udp_sendto(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *add
|
|||
return do_socket_write(rktio, rfd, buffer, len, addr);
|
||||
}
|
||||
|
||||
intptr_t rktio_udp_sendto_in(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr, const char *buffer,
|
||||
intptr_t start, intptr_t end)
|
||||
{
|
||||
return rktio_udp_sendto(rktio, rfd, addr, buffer + start, end - start);
|
||||
}
|
||||
|
||||
rktio_length_and_addrinfo_t *rktio_udp_recvfrom(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len)
|
||||
{
|
||||
rktio_socket_t s = rktio_fd_socket(rktio, rfd);
|
||||
|
@ -1874,6 +1880,12 @@ rktio_length_and_addrinfo_t *rktio_udp_recvfrom(rktio_t *rktio, rktio_fd_t *rfd,
|
|||
return r;
|
||||
}
|
||||
|
||||
rktio_length_and_addrinfo_t *rktio_udp_recvfrom_in(rktio_t *rktio, rktio_fd_t *rfd,
|
||||
char *buffer, intptr_t start, intptr_t end)
|
||||
{
|
||||
return rktio_udp_recvfrom(rktio, rfd, buffer + start, end - start);
|
||||
}
|
||||
|
||||
int rktio_udp_get_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd)
|
||||
{
|
||||
rktio_socket_t s = rktio_fd_socket(rktio, rfd);
|
||||
|
|
|
@ -99,6 +99,14 @@ struct rktio_t {
|
|||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
HANDLE hEventLog;
|
||||
#endif
|
||||
|
||||
int pending_os_signals[RKTIO_NUM_OS_SIGNALS];
|
||||
|
||||
struct rktio_dll_t *all_dlls;
|
||||
struct rktio_hash_t *dlls_by_name;
|
||||
#ifdef RKTIO_SYSTEM_UNIX
|
||||
char *dll_error;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*========================================================================*/
|
||||
|
@ -255,6 +263,8 @@ void rktio_hash_set(rktio_hash_t *ht, intptr_t key, void *v);
|
|||
intptr_t rktio_hash_size(rktio_hash_t *ht);
|
||||
intptr_t rktio_hash_get_key(rktio_hash_t *ht, intptr_t i);
|
||||
|
||||
intptr_t rktio_hash_string(const char *s);
|
||||
|
||||
/*========================================================================*/
|
||||
/* Misc */
|
||||
/*========================================================================*/
|
||||
|
@ -274,6 +284,8 @@ void rktio_set_windows_error(rktio_t *rktio, int errid);
|
|||
|
||||
void rktio_error_clean(rktio_t *rktio);
|
||||
|
||||
void rktio_dll_clean(rktio_t *rktio);
|
||||
|
||||
#if defined(USE_FNDELAY_O_NONBLOCK)
|
||||
# define RKTIO_NONBLOCKING FNDELAY
|
||||
#else
|
||||
|
@ -324,3 +336,8 @@ void rktio_syslog_clean(rktio_t* rktio);
|
|||
#endif
|
||||
|
||||
char *rktio_strndup(char *s, intptr_t len);
|
||||
|
||||
#ifdef RKTIO_SYSTEM_UNIX
|
||||
void rktio_set_signal_handler(int sig_id, void (*proc)(int));
|
||||
#endif
|
||||
void rktio_forget_os_signal_handler(rktio_t *rktio);
|
||||
|
|
|
@ -53,15 +53,6 @@ static int extract_child_status(int status)
|
|||
return status;
|
||||
}
|
||||
|
||||
static void set_signal_handler(int sig_id, void (*proc)(int))
|
||||
{
|
||||
struct sigaction sa;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sa.sa_handler = proc;
|
||||
sigaction(sig_id, &sa, NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*========================================================================*/
|
||||
|
@ -433,7 +424,7 @@ void centralized_starting_child()
|
|||
does not block SIGCHLD.
|
||||
Solaris, meanwhile, seems to unmask SIGCHLD as a result of
|
||||
setting a handler, so do this before masking the signal. */
|
||||
set_signal_handler(SIGCHLD, got_sigchld);
|
||||
rktio_set_signal_handler(SIGCHLD, got_sigchld);
|
||||
|
||||
/* Block SIGCLHD (again), because the worker thread will use sigwait(). */
|
||||
block_sigchld();
|
||||
|
@ -585,7 +576,7 @@ static void init_sigchld(rktio_t *rktio)
|
|||
{
|
||||
#if !defined(CENTRALIZED_SIGCHILD)
|
||||
if (!sigchld_installed) {
|
||||
set_signal_handler(SIGCHLD, child_done);
|
||||
rktio_set_signal_handler(SIGCHLD, child_done);
|
||||
sigchld_installed = 1;
|
||||
}
|
||||
|
||||
|
@ -1206,7 +1197,7 @@ int rktio_process_allowed_flags(rktio_t *rktio)
|
|||
/*========================================================================*/
|
||||
|
||||
rktio_process_result_t *rktio_process(rktio_t *rktio,
|
||||
const char *command, int argc, char **argv,
|
||||
const char *command, int argc, rktio_const_string_t *argv,
|
||||
rktio_fd_t *stdout_fd, rktio_fd_t *stdin_fd, rktio_fd_t *stderr_fd,
|
||||
const char *current_directory, rktio_envvars_t *envvars,
|
||||
int flags)
|
||||
|
@ -1471,7 +1462,7 @@ rktio_process_result_t *rktio_process(rktio_t *rktio,
|
|||
|
||||
{
|
||||
int err, i;
|
||||
char **new_argv;
|
||||
rktio_const_string_t *new_argv;
|
||||
|
||||
/* add a NULL terminator */
|
||||
new_argv = malloc(sizeof(char *) * (argc + 1));
|
||||
|
@ -1483,7 +1474,7 @@ rktio_process_result_t *rktio_process(rktio_t *rktio,
|
|||
if (!env)
|
||||
env = rktio_get_environ_array();
|
||||
|
||||
err = MSC_IZE(execve)(command, new_argv, (char **)env);
|
||||
err = MSC_IZE(execve)(command, (char **)new_argv, (char **)env);
|
||||
if (err)
|
||||
err = errno;
|
||||
|
||||
|
|
102
racket/src/rktio/rktio_signal.c
Normal file
102
racket/src/rktio/rktio_signal.c
Normal file
|
@ -0,0 +1,102 @@
|
|||
#include "rktio.h"
|
||||
#include "rktio_private.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#if defined(RKTIO_SYSTEM_UNIX)
|
||||
# include <signal.h>
|
||||
#endif
|
||||
|
||||
static int handlers_installed = 0;
|
||||
static rktio_t *signal_rktio = NULL;
|
||||
|
||||
/*========================================================================*/
|
||||
/* Signal handlers */
|
||||
/*========================================================================*/
|
||||
|
||||
/* Called by signal handlers: */
|
||||
static void signal_received(int i)
|
||||
{
|
||||
if (signal_rktio) {
|
||||
signal_rktio->pending_os_signals[i] = 1;
|
||||
rktio_signal_received(signal_rktio);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(RKTIO_SYSTEM_WINDOWS)
|
||||
static BOOL WINAPI ConsoleBreakHandler(DWORD op)
|
||||
{
|
||||
signal_received(RKTIO_OS_SIGNAL_INT);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(RKTIO_SYSTEM_UNIX)
|
||||
static void user_break_hit(int ignore) {
|
||||
signal_received(RKTIO_OS_SIGNAL_INT);
|
||||
}
|
||||
|
||||
static void term_hit(int ignore)
|
||||
{
|
||||
signal_received(RKTIO_OS_SIGNAL_TERM);
|
||||
}
|
||||
|
||||
static void hup_hit(int ignore)
|
||||
{
|
||||
signal_received(RKTIO_OS_SIGNAL_HUP);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*========================================================================*/
|
||||
/* Manage signal handlers */
|
||||
/*========================================================================*/
|
||||
|
||||
void rktio_install_os_signal_handler(rktio_t *rktio)
|
||||
{
|
||||
signal_rktio = rktio;
|
||||
if (handlers_installed)
|
||||
return;
|
||||
|
||||
handlers_installed = 1;
|
||||
|
||||
#if defined(RKTIO_SYSTEM_UNIX)
|
||||
rktio_set_signal_handler(SIGINT, user_break_hit);
|
||||
rktio_set_signal_handler(SIGTERM, term_hit);
|
||||
rktio_set_signal_handler(SIGHUP, hup_hit);
|
||||
#endif
|
||||
|
||||
#if defined(RKTIO_SYSTEM_WINDOWS)
|
||||
SetConsoleCtrlHandler(ConsoleBreakHandler, TRUE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void rktio_forget_os_signal_handler(rktio_t *rktio)
|
||||
{
|
||||
if (signal_rktio == rktio) {
|
||||
signal_rktio = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int rktio_poll_os_signal(rktio_t *rktio)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < RKTIO_NUM_OS_SIGNALS; i++) {
|
||||
if (rktio->pending_os_signals[i]) {
|
||||
rktio->pending_os_signals[i] = 0;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return RKTIO_OS_SIGNAL_NONE;
|
||||
}
|
||||
|
||||
#if defined(RKTIO_SYSTEM_UNIX)
|
||||
void rktio_set_signal_handler(int sig_id, void (*proc)(int))
|
||||
{
|
||||
struct sigaction sa;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sa.sa_handler = proc;
|
||||
sigaction(sig_id, &sa, NULL);
|
||||
}
|
||||
#endif
|
|
@ -142,6 +142,10 @@
|
|||
RelativePath="..\..\rktio\rktio_process.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\rktio\rktio_signal.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\rktio\rktio_envvars.c"
|
||||
>
|
||||
|
@ -170,6 +174,10 @@
|
|||
RelativePath="..\..\rktio\rktio_convert.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\rktio\rktio_dll.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\rktio\rktio_error.c"
|
||||
>
|
||||
|
|
|
@ -124,6 +124,7 @@
|
|||
<ClCompile Include="..\..\rktio\rktio_network.c" />
|
||||
<ClCompile Include="..\..\rktio\rktio_pipe.c" />
|
||||
<ClCompile Include="..\..\rktio\rktio_process.c" />
|
||||
<ClCompile Include="..\..\rktio\rktio_signal.c" />
|
||||
<ClCompile Include="..\..\rktio\rktio_envvars.c" />
|
||||
<ClCompile Include="..\..\rktio\rktio_fs_change.c" />
|
||||
<ClCompile Include="..\..\rktio\rktio_flock.c" />
|
||||
|
@ -131,6 +132,7 @@
|
|||
<ClCompile Include="..\..\rktio\rktio_time.c" />
|
||||
<ClCompile Include="..\..\rktio\rktio_syslog.c" />
|
||||
<ClCompile Include="..\..\rktio\rktio_convert.c" />
|
||||
<ClCompile Include="..\..\rktio\rktio_dll.c" />
|
||||
<ClCompile Include="..\..\rktio\rktio_error.c" />
|
||||
<ClCompile Include="..\..\rktio\rktio_hash.c" />
|
||||
<ClCompile Include="..\..\rktio\rktio_wide.c" />
|
||||
|
|
Loading…
Reference in New Issue
Block a user