Index: src/call_list.txt =================================================================== --- src/call_list.txt (revision 9297) +++ src/call_list.txt (working copy) @@ -319,3 +319,7 @@ # crypt t tt + +v ip +v pt +i ptpPPi Index: src/dynext.c =================================================================== --- src/dynext.c (revision 9297) +++ src/dynext.c (working copy) @@ -122,147 +122,202 @@ /* -=item C +=item C -Return path and handle of a dynamic lib, setting lib_name to just the filestem -(i.e. without path or extension) as a freshly-allocated C string. +Returns the file stem, no path and no ext of the parameter full_name. stem is a +freshly allocated c string. =cut */ -static STRING * -get_path(Interp *interpreter, STRING *lib, void **handle, char **lib_name) +static char * +filestem(char * full_name) { - STRING *path; - char *full_name, *file_name, *file_w_ext = NULL; - char *tmp_lib_name, *path_end, *ext_start; - const char *err; + char * stem; + char * path_end; + char * extension_loc; - /* Find the pure library name, without path or extension. */ - file_name = string_to_cstring(interpreter, lib); - tmp_lib_name = file_name; - path_end = strrchr(tmp_lib_name, '/'); + /* if there's path, remove it */ + path_end = strrchr(full_name, '/'); if (! path_end) - path_end = strrchr(tmp_lib_name, '\\'); - if (path_end) - tmp_lib_name = path_end+1; - *lib_name = malloc(strlen(tmp_lib_name)+1); - strcpy(*lib_name, tmp_lib_name); - ext_start = strrchr(*lib_name, '.'); - if (ext_start) - *ext_start = '\0'; + path_end = strrchr(full_name, '\\'); + if (! path_end) + path_end = full_name; + else + path_end++; + /* path_end now points at the first part of full_name that isn't path */ - /* - * first, try to add an extension to the file if it has none. - */ - if (! ext_start) { - file_w_ext = malloc(strlen(file_name) + - strlen(PARROT_LOAD_EXT) + 1); - strcpy(file_w_ext, file_name); - strcat(file_w_ext, PARROT_LOAD_EXT); - full_name = Parrot_locate_runtime_file(interpreter, file_w_ext, + stem = strdup(path_end); + + /* remove extension if there is one */ + extension_loc = strrchr(stem, '.'); + if (extension_loc) + *extension_loc = '\0'; + + return stem; +} + +/* + +=item C + +Try loading a the library in clib out of library path or Parrot's runtime +paths. Returns a pointer to err on failure, except not found and path is passed +by reference and used to return path. Otherwise behavior is the same as +get_path + +=cut + +*/ + +static const char * +try_load(Interp *interpreter, char *clib, void **handle, STRING ** path, char **lib_name) +{ + char *runtime; + + *handle = Parrot_dlopen(clib); + if (*handle) { + *path = string_from_cstring(interpreter, clib, 0); + *lib_name = filestem(clib); + } + else + { + const char *err = Parrot_dlerror(); + /* FIXME rm: need better way to ignore not found errors */ + if (err && !strstr(err, "No such file or directory")) + return err; + + runtime = Parrot_locate_runtime_file(interpreter, clib, PARROT_RUNTIME_FT_DYNEXT); - if (full_name) { - *handle = Parrot_dlopen(full_name); + if (runtime) + { + *handle = Parrot_dlopen(runtime); if (*handle) { - path = string_from_cstring(interpreter, full_name, 0); - string_cstring_free(file_name); - string_cstring_free(full_name); - string_cstring_free(file_w_ext); - return path; + *path = string_from_cstring(interpreter, runtime, 0); + *lib_name = filestem(runtime); } - err = Parrot_dlerror(); - fprintf(stderr, "Couldn't load '%s': %s\n", - full_name, err ? err : "unknown reason"); - string_cstring_free(file_name); - string_cstring_free(full_name); - string_cstring_free(file_w_ext); - return NULL; - } - /* - * then file.extension w/o prefix - */ - *handle = Parrot_dlopen(file_w_ext); - if (*handle) { - path = string_from_cstring(interpreter, file_w_ext, 0); - string_cstring_free(file_name); - string_cstring_free(file_w_ext); - return path; - } - string_cstring_free(file_w_ext); - if (strcmp(PARROT_LOAD_EXT, PARROT_SHARE_EXT)) { - file_w_ext = malloc(strlen(file_name) + - strlen(PARROT_SHARE_EXT) + 1); - strcpy(file_w_ext, file_name); - strcat(file_w_ext, PARROT_SHARE_EXT); - full_name = Parrot_locate_runtime_file(interpreter, file_w_ext, - PARROT_RUNTIME_FT_DYNEXT); - if (full_name) { - *handle = Parrot_dlopen(full_name); - if (*handle) { - path = string_from_cstring(interpreter, full_name, 0); - string_cstring_free(file_name); - string_cstring_free(file_w_ext); - return path; - } + else + { err = Parrot_dlerror(); - fprintf(stderr, "Couldn't load '%s': %s\n", - full_name, err ? err : "unknown reason"); - string_cstring_free(file_name); - string_cstring_free(file_w_ext); - return NULL; + /* FIXME rm: need better way to ignore not found errors */ + if (err && !strstr(err, "No such file or directory")) + return err; } - /* - * then file.extension w/o prefix - */ - *handle = Parrot_dlopen(file_w_ext); - if (*handle) { - path = string_from_cstring(interpreter, file_w_ext, 0); - string_cstring_free(file_name); - string_cstring_free(file_w_ext); - return path; - } - string_cstring_free(file_w_ext); } + string_cstring_free(runtime); } - /* - * finally, try the given file name as is. we still use - * Parrot_locate_runtime_file so that (a) relative pathnames are searched in - * the standard locations, and (b) the angle of the slashes are adjusted as - * required for non-Unix systems. - */ - full_name = Parrot_locate_runtime_file(interpreter, file_name, - PARROT_RUNTIME_FT_DYNEXT); - if (full_name) { - *handle = Parrot_dlopen(full_name); - if (*handle) { - path = string_from_cstring(interpreter, full_name, 0); - string_cstring_free(file_name); - string_cstring_free(full_name); - return path; + + return NULL; +} + +/* + +=item C + +Return path and handle of a dynamic lib, setting lib_name to just the filestem +(i.e. without path or extension) as a freshly-allocated C string. + +=cut + +*/ + +static STRING * +get_path(Interp *interpreter, STRING *lib, void **handle, char **lib_name) +{ + STRING *path = NULL; + char *clib = NULL; + char *clib_mod = NULL; + char *clib_no_ext = NULL; + unsigned int i; + const char * err; + + clib = string_to_cstring(interpreter, lib); + + /* clear out dlerror in case it hasn't been */ + Parrot_dlerror(); + + /* swap slashes if they're backwards */ + for (i = 0; i < strlen(clib); i++) +#ifdef WIN32 + if (clib[i] == '/') + clib[i] = '\\'; +#else + if (clib[i] == '\\') + clib[i] = '/'; +#endif + + /* try to load unmodified */ + err = try_load(interpreter, clib, handle, &path, lib_name); + if (err) + { + fprintf(stderr, "Couldn't load '%s': %s\n", clib, err); + goto done; + } + if (path) + goto done; + + /* FIXME rm: check for mem_sys_allocate failures and handle them the parrot + * way */ + + /* try to add extension */ + clib_mod = mem_sys_allocate(strlen(clib) + strlen(PARROT_LOAD_EXT) + 1); + strcpy(clib_mod, clib); + strcat(clib_mod, PARROT_LOAD_EXT); + err = try_load(interpreter, clib_mod, handle, &path, lib_name); + if (err) + { + fprintf(stderr, "Couldn't load '%s': %s\n", clib_mod, err); + goto done; + } + if (path) + goto done; + + /* if ext, remove it (since it's apparently wrong) and put right one on */ + string_cstring_free(clib_mod); + clib_mod = NULL; + clib_no_ext = strdup(clib); + char *ext_loc = strrchr(clib_no_ext, '.'); + if (ext_loc) { + *ext_loc = '\0'; + clib_mod = mem_sys_allocate(strlen(clib_no_ext) + + strlen(PARROT_LOAD_EXT) + 1); + strcpy(clib_mod, clib_no_ext); + strcat(clib_mod, PARROT_LOAD_EXT); + err = try_load(interpreter, clib_mod, handle, &path, lib_name); + if (err) + { + fprintf(stderr, "Couldn't load '%s': %s\n", clib_mod, err); + goto done; } + if (path) + goto done; } - /* - * and on windows strip a leading "lib" - * [shouldn't this happen in Parrot_locate_runtime_file instead?] - */ -#ifdef WIN32 - if (memcmp(file_name, "lib", 3) == 0) { - *handle = Parrot_dlopen(file_name + 3); - if (*handle) { - path = string_from_cstring(interpreter, file_name + 3, 0); - string_cstring_free(file_name); - return path; + + /* this doesn't work for lib's with path info or the wrong ext, but it's + * just duplicating old behavior. it used to be wrapped in win32 ifdef's + * but it doesn't hurt to try it */ + if (memcmp(clib, "lib", 3) == 0) { + err = try_load(interpreter, clib + 3, handle, &path, lib_name); + if (err) + { + fprintf(stderr, "Couldn't load '%s': %s\n", clib + 3, err); + goto done; } + if (path) + goto done; } -#endif - err = Parrot_dlerror(); - fprintf(stderr, "Couldn't load '%s': %s\n", - file_name, err ? err : "unknown reason"); - string_cstring_free(file_name); - return NULL; + + fprintf(stderr, "Couldn't load '%s': No such file or directory\n", clib); + +done: + string_cstring_free(clib); + string_cstring_free(clib_mod); + string_cstring_free(clib_no_ext); + return path; } /* Index: t/pmc/nci_loadlib.t =================================================================== --- t/pmc/nci_loadlib.t (revision 0) +++ t/pmc/nci_loadlib.t (revision 0) @@ -0,0 +1,125 @@ +#! perl -w +# Copyright: 2005 The Perl Foundation. All Rights Reserved. +# $Id: foo.t 8254 2005-06-02 14:20:39Z leo $ + +=head1 NAME + +t/pmc/nci_loadlib.t - Test loadlib ability to load a library specified in +various maners (name, file, w/extension, w/wrong extension, ...) + +=head1 SYNOPSIS + + % perl -Ilib t/pmc/nci_loadlib.t + +=head1 DESCRIPTION + +Tests loadlib library loading + +=cut + +use Parrot::Test; +use Parrot::Config; + +# known exts +my @exts = qw/.so .dll .dynlib .nothing/; +# no ext +push @exts, ''; + +my @perms = (); + +# foo out of runtime and with rel win/unix paths (always runs) +foreach (@exts) +{ + push @perms, 'foo'.$_, 'runtime/parrot/dynext/foo'.$_, + "runtime\\parrot\\dynext\\foo".$_; +}; + +# if libm is around use it from path and with full win/unix paths +if (-e '/usr/lib/libm.so') +{ + foreach (@exts) + { + push @perms, 'libm'.$_, '/usr/lib/libm'.$_, "\\usr\\lib\\libm".$_; + }; +} + +# if gtk's lib happens to be around go ahead and test with it for the '.' tests +# path and full win/unix +if (-e '/usr/lib/libgtk-x11-2.0.so') +{ + foreach (@exts) + { + push @perms, 'libgtk-x11-2.0'.$_, '/usr/lib/libgtk-x11-2.0'.$_, + "\\usr\\lib\\libgtk-x11-2.0".$_; + }; +} + +# +2 for the lib removal test, below +plan tests => scalar (@perms) + 2; + +# run each of the above permutations constrcuted above +foreach (@perms) +{ +pir_output_is(" + +.sub main + .local pmc dynlib + dynlib = loadlib '$_' + unless dynlib goto FAILED + print '42' + goto DONE +FAILED: + print 'failed to load $_' +DONE: + end +.end + +", '42', 'load '.$_); +} + +# test out leading lib removal, special b/c we have to have the correct ext +pir_output_is(" + +.sub main + .local pmc dynlib + .local pmc interp + .local pmc conf + .local string ext + .local string libname + + .include 'iglobals.pasm' + interp = getinterp + conf = interp[.IGLOBALS_CONFIG_HASH] + ext = conf['load_ext'] + + libname = concat 'libfoo', ext + dynlib = loadlib libname + unless dynlib goto FAILED + print '42' + goto DONE +FAILED: + print 'failed to load ' + print libname +DONE: + end +.end + +", '42', 'load libfoo, lib removal'); + +pir_output_is(" + +.sub main + .local pmc dynlib + dynlib = loadlib 'something_that_should_never_exist' + unless dynlib goto FAILED + print '42' + goto DONE +FAILED: + print 'failed to load something_that_should_never_exist' +DONE: + end +.end + +", "Couldn't load 'something_that_should_never_exist': No such file or directory +failed to load something_that_should_never_exist", +'fail to load non-existent');