[t][cage] Remove PGE-dependence from t/op/inf_nan.t since it is part of 'make coretest'
[parrot.git] / src / library.c
blobc291ef5893900f7d21344ddad6e402b187e1fbb3
1 /*
2 Copyright (C) 2004-2009, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/library.c - Interface to Parrot's bytecode library
9 =head1 DESCRIPTION
11 This file contains C functions to access Parrot's bytecode library functions,
12 for include files (via C<.include>), library files (via C<load_bytecode>), and
13 dynext files (via C<loadlib>).
15 =head2 Functions
17 =over 4
19 =cut
23 #include "parrot/parrot.h"
24 #include "parrot/dynext.h"
25 #include "library.str"
27 /* HEADERIZER HFILE: include/parrot/library.h */
29 /* HEADERIZER BEGIN: static */
30 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
32 static void cnv_to_win32_filesep(ARGMOD(STRING *path))
33 __attribute__nonnull__(1)
34 FUNC_MODIFIES(*path);
36 PARROT_WARN_UNUSED_RESULT
37 PARROT_CANNOT_RETURN_NULL
38 static PMC* get_search_paths(PARROT_INTERP, enum_lib_paths which)
39 __attribute__nonnull__(1);
41 PARROT_PURE_FUNCTION
42 static int is_abs_path(ARGIN(const STRING *file))
43 __attribute__nonnull__(1);
45 PARROT_WARN_UNUSED_RESULT
46 PARROT_CANNOT_RETURN_NULL
47 static STRING* path_append(PARROT_INTERP,
48 ARGMOD(STRING *l_path),
49 ARGMOD(STRING *r_path))
50 __attribute__nonnull__(1)
51 __attribute__nonnull__(2)
52 __attribute__nonnull__(3)
53 FUNC_MODIFIES(*l_path)
54 FUNC_MODIFIES(*r_path);
56 PARROT_WARN_UNUSED_RESULT
57 PARROT_CANNOT_RETURN_NULL
58 static STRING* path_concat(PARROT_INTERP,
59 ARGMOD(STRING *l_path),
60 ARGMOD(STRING *r_path))
61 __attribute__nonnull__(1)
62 __attribute__nonnull__(2)
63 __attribute__nonnull__(3)
64 FUNC_MODIFIES(*l_path)
65 FUNC_MODIFIES(*r_path);
67 PARROT_WARN_UNUSED_RESULT
68 PARROT_CANNOT_RETURN_NULL
69 static STRING* path_finalize(PARROT_INTERP, ARGMOD(STRING *path))
70 __attribute__nonnull__(1)
71 __attribute__nonnull__(2)
72 FUNC_MODIFIES(*path);
74 PARROT_WARN_UNUSED_RESULT
75 PARROT_CANNOT_RETURN_NULL
76 static STRING* path_guarantee_trailing_separator(PARROT_INTERP,
77 ARGMOD(STRING *path))
78 __attribute__nonnull__(1)
79 __attribute__nonnull__(2)
80 FUNC_MODIFIES(*path);
82 PARROT_WARN_UNUSED_RESULT
83 PARROT_CAN_RETURN_NULL
84 static STRING* try_bytecode_extensions(PARROT_INTERP, ARGMOD(STRING* path))
85 __attribute__nonnull__(1)
86 __attribute__nonnull__(2)
87 FUNC_MODIFIES(* path);
89 PARROT_WARN_UNUSED_RESULT
90 PARROT_CAN_RETURN_NULL
91 static STRING* try_load_path(PARROT_INTERP, ARGMOD(STRING* path))
92 __attribute__nonnull__(1)
93 __attribute__nonnull__(2)
94 FUNC_MODIFIES(* path);
96 #define ASSERT_ARGS_cnv_to_win32_filesep __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
97 PARROT_ASSERT_ARG(path))
98 #define ASSERT_ARGS_get_search_paths __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
99 PARROT_ASSERT_ARG(interp))
100 #define ASSERT_ARGS_is_abs_path __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
101 PARROT_ASSERT_ARG(file))
102 #define ASSERT_ARGS_path_append __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
103 PARROT_ASSERT_ARG(interp) \
104 , PARROT_ASSERT_ARG(l_path) \
105 , PARROT_ASSERT_ARG(r_path))
106 #define ASSERT_ARGS_path_concat __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
107 PARROT_ASSERT_ARG(interp) \
108 , PARROT_ASSERT_ARG(l_path) \
109 , PARROT_ASSERT_ARG(r_path))
110 #define ASSERT_ARGS_path_finalize __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
111 PARROT_ASSERT_ARG(interp) \
112 , PARROT_ASSERT_ARG(path))
113 #define ASSERT_ARGS_path_guarantee_trailing_separator \
114 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
115 PARROT_ASSERT_ARG(interp) \
116 , PARROT_ASSERT_ARG(path))
117 #define ASSERT_ARGS_try_bytecode_extensions __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
118 PARROT_ASSERT_ARG(interp) \
119 , PARROT_ASSERT_ARG(path))
120 #define ASSERT_ARGS_try_load_path __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
121 PARROT_ASSERT_ARG(interp) \
122 , PARROT_ASSERT_ARG(path))
123 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
124 /* HEADERIZER END: static */
129 =item C<void parrot_init_library_paths(PARROT_INTERP)>
131 Create an array of StringArrays with library searchpaths and shared
132 extension used for loading various files at runtime. The created
133 structures looks like this:
135 lib_paths = [
136 [ "runtime/parrot/include", ... ], # paths for .include 'file'
137 [ "runtime/parrot/library", ... ], # paths for load_bytecode
138 [ "runtime/parrot/dynext", ... ], # paths for loadlib
139 [ "languages", ... ], # paths for languages
140 [ ".so", ... ] # list of shared extensions
143 If the platform defines
145 #define PARROT_PLATFORM_LIB_PATH_INIT_HOOK the_init_hook
147 it will be called as a function with this prototype:
149 void the_init_hook(PARROT_INTERP, PMC *lib_paths);
151 Platform code may add, delete, or replace search path entries as needed. See
152 also F<include/parrot/library.h> for C<enum_lib_paths>.
154 =cut
158 void
159 parrot_init_library_paths(PARROT_INTERP)
161 ASSERT_ARGS(parrot_init_library_paths)
162 PMC *paths;
163 STRING *entry;
164 STRING *versionlib = NULL;
165 STRING *builddir = NULL;
166 PMC * const iglobals = interp->iglobals;
167 PMC * const config_hash = VTABLE_get_pmc_keyed_int(interp, iglobals,
168 (INTVAL)IGLOBALS_CONFIG_HASH);
170 /* create the lib_paths array */
171 PMC * const lib_paths = pmc_new(interp, enum_class_FixedPMCArray);
173 VTABLE_set_integer_native(interp, lib_paths, PARROT_LIB_PATH_SIZE);
174 VTABLE_set_pmc_keyed_int(interp, iglobals,
175 IGLOBALS_LIB_PATHS, lib_paths);
177 if (VTABLE_elements(interp, config_hash)) {
178 STRING * const libkey = CONST_STRING(interp, "libdir");
179 STRING * const verkey = CONST_STRING(interp, "versiondir");
180 STRING * const builddirkey = CONST_STRING(interp, "build_dir");
181 STRING * const installed = CONST_STRING(interp, "installed");
183 versionlib = VTABLE_get_string_keyed_str(interp, config_hash, libkey);
184 entry = VTABLE_get_string_keyed_str(interp, config_hash, verkey);
185 versionlib = Parrot_str_append(interp, versionlib, entry);
187 if (!VTABLE_get_integer_keyed_str(interp, config_hash, installed))
188 builddir = VTABLE_get_string_keyed_str(interp,
189 config_hash, builddirkey);
192 /* each is an array of strings */
193 /* define include paths */
194 paths = pmc_new(interp, enum_class_ResizableStringArray);
195 VTABLE_set_pmc_keyed_int(interp, lib_paths,
196 PARROT_LIB_PATH_INCLUDE, paths);
197 if (!STRING_IS_NULL(builddir)) {
198 entry = Parrot_str_concat(interp, builddir, CONST_STRING(interp, "/"), 0);
199 VTABLE_push_string(interp, paths, entry);
200 entry = Parrot_str_concat(interp, builddir, CONST_STRING(interp, "/runtime/parrot/include/"), 0);
201 VTABLE_push_string(interp, paths, entry);
203 entry = CONST_STRING(interp, "./");
204 VTABLE_push_string(interp, paths, entry);
205 if (!STRING_IS_NULL(versionlib)) {
206 entry = Parrot_str_concat(interp, versionlib, CONST_STRING(interp, "/include/"), 0);
207 VTABLE_push_string(interp, paths, entry);
211 /* define library paths */
212 paths = pmc_new(interp, enum_class_ResizableStringArray);
213 VTABLE_set_pmc_keyed_int(interp, lib_paths,
214 PARROT_LIB_PATH_LIBRARY, paths);
215 if (!STRING_IS_NULL(builddir)) {
216 entry = Parrot_str_concat(interp, builddir, CONST_STRING(interp, "/runtime/parrot/library/"), 0);
217 VTABLE_push_string(interp, paths, entry);
219 entry = CONST_STRING(interp, "./");
220 VTABLE_push_string(interp, paths, entry);
221 if (!STRING_IS_NULL(versionlib)) {
222 entry = Parrot_str_concat(interp, versionlib, CONST_STRING(interp, "/library/"), 0);
223 VTABLE_push_string(interp, paths, entry);
226 /* define languages paths */
227 paths = pmc_new(interp, enum_class_ResizableStringArray);
228 VTABLE_set_pmc_keyed_int(interp, lib_paths,
229 PARROT_LIB_PATH_LANG, paths);
230 if (!STRING_IS_NULL(builddir)) {
231 entry = Parrot_str_concat(interp, builddir, CONST_STRING(interp, "/runtime/parrot/languages/"), 0);
232 VTABLE_push_string(interp, paths, entry);
234 entry = CONST_STRING(interp, "./");
235 VTABLE_push_string(interp, paths, entry);
236 if (!STRING_IS_NULL(versionlib)) {
237 entry = Parrot_str_concat(interp, versionlib, CONST_STRING(interp, "/languages/"), 0);
238 VTABLE_push_string(interp, paths, entry);
241 /* define dynext paths */
242 paths = pmc_new(interp, enum_class_ResizableStringArray);
243 VTABLE_set_pmc_keyed_int(interp, lib_paths,
244 PARROT_LIB_PATH_DYNEXT, paths);
245 if (!STRING_IS_NULL(builddir)) {
246 entry = Parrot_str_concat(interp, builddir, CONST_STRING(interp, "/runtime/parrot/dynext/"), 0);
247 VTABLE_push_string(interp, paths, entry);
249 entry = CONST_STRING(interp, "dynext/");
250 VTABLE_push_string(interp, paths, entry);
251 if (!STRING_IS_NULL(versionlib)) {
252 entry = Parrot_str_concat(interp, versionlib, CONST_STRING(interp, "/dynext/"), 0);
253 VTABLE_push_string(interp, paths, entry);
256 /* shared exts */
257 paths = pmc_new(interp, enum_class_ResizableStringArray);
258 VTABLE_set_pmc_keyed_int(interp, lib_paths,
259 PARROT_LIB_DYN_EXTS, paths);
260 /* no CONST_STRING here - the c2str.pl preprocessor needs "real strs" */
261 entry = Parrot_str_new_constant(interp, PARROT_LOAD_EXT);
262 VTABLE_push_string(interp, paths, entry);
263 /* OS/X has .dylib and .bundle */
264 if (!STREQ(PARROT_LOAD_EXT, PARROT_SHARE_EXT)) {
265 entry = Parrot_str_new_constant(interp, PARROT_SHARE_EXT);
266 VTABLE_push_string(interp, paths, entry);
269 #ifdef PARROT_PLATFORM_LIB_PATH_INIT_HOOK
270 PARROT_PLATFORM_LIB_PATH_INIT_HOOK(interp, lib_paths);
271 #endif
276 =item C<static PMC* get_search_paths(PARROT_INTERP, enum_lib_paths which)>
278 Return lib_paths as array of StringArrays with library searchpaths and shared
279 extension used for loading various files at runtime.
280 The structure looks like this:
282 lib_paths = [
283 [ "runtime/parrot/include", ... ], # paths for .include 'file'
284 [ "runtime/parrot/library", ... ], # paths for load_bytecode
285 [ "runtime/parrot/dynext", ... ], # paths for loadlib
286 [ "languages", ... ], # paths for languages
287 [ ".so", ... ] # list of shared extensions
290 =cut
294 PARROT_WARN_UNUSED_RESULT
295 PARROT_CANNOT_RETURN_NULL
296 static PMC*
297 get_search_paths(PARROT_INTERP, enum_lib_paths which)
299 ASSERT_ARGS(get_search_paths)
300 PMC * const iglobals = interp->iglobals;
301 PMC * const lib_paths = VTABLE_get_pmc_keyed_int(interp, iglobals,
302 IGLOBALS_LIB_PATHS);
303 return VTABLE_get_pmc_keyed_int(interp, lib_paths, which);
306 static const char path_separator = '/';
308 #ifdef WIN32
310 static const char win32_path_separator = '\\';
312 #endif
316 =item C<static int is_abs_path(const STRING *file)>
318 Determines whether a file name given by a fixed-8 or utf8 C<STRING> is an
319 absolute file name. Returns C<1> if the filename is absolute, returns C<0>
320 otherwise.
322 =cut
326 PARROT_PURE_FUNCTION
327 static int
328 is_abs_path(ARGIN(const STRING *file))
330 ASSERT_ARGS(is_abs_path)
331 const char * const file_name = file->strstart;
332 if (file->strlen <= 1)
333 return 0;
334 PARROT_ASSERT(file->encoding == Parrot_fixed_8_encoding_ptr ||
335 file->encoding == Parrot_utf8_encoding_ptr);
337 /* XXX ../foo, ./bar */
338 if (file_name[0] == path_separator
339 #ifdef WIN32
340 || (file_name[0] == win32_path_separator ||
341 (isalpha((unsigned char)file_name[0]) && file->strlen > 2 &&
342 (strncmp(file_name+1, ":\\", 2) == 0 ||
343 strncmp(file_name+1, ":/", 2) == 0)))
344 #endif
345 /* no space before closing paren */)
347 return 1;
349 return 0;
353 #ifdef WIN32
357 =item C<static void cnv_to_win32_filesep(STRING *path)>
359 Converts a path with forward slashes to one with backward slashes.
361 =cut
365 static void
366 cnv_to_win32_filesep(ARGMOD(STRING *path))
368 ASSERT_ARGS(cnv_to_win32_filesep)
369 char* cnv;
371 PARROT_ASSERT(path->encoding == Parrot_fixed_8_encoding_ptr ||
372 path->encoding == Parrot_utf8_encoding_ptr);
374 cnv = path->strstart;
375 while ((cnv = strchr(cnv, path_separator)) != NULL)
376 *cnv = win32_path_separator;
379 #endif
383 =item C<static STRING* path_finalize(PARROT_INTERP, STRING *path)>
385 Ensures the given STRING C<path> has a C-style NULL character at the end. The
386 length of the string is not increased to account for this NULL, however. In
387 WIN32 systems, the path separator is switched from the unix-style "/" to the
388 Windows-style "\".
390 =cut
394 PARROT_WARN_UNUSED_RESULT
395 PARROT_CANNOT_RETURN_NULL
396 static STRING*
397 path_finalize(PARROT_INTERP, ARGMOD(STRING *path))
399 ASSERT_ARGS(path_finalize)
401 /* TODO create a string API that just does that
402 * a lot of ICU lib functions also need 0-terminated strings
403 * the goal is just to have for sure an invisible 0 at end
406 STRING * const nul = string_chr(interp, '\0');
408 path = Parrot_str_append(interp, path, nul);
409 path->bufused--;
410 path->strlen--;
412 #ifdef WIN32
413 cnv_to_win32_filesep(path);
414 #endif
416 return path;
421 =item C<static STRING* path_guarantee_trailing_separator(PARROT_INTERP, STRING
422 *path)>
424 unary path argument. the path string will have a
425 trailing path-separator appended if it is not
426 there already.
428 =cut
432 PARROT_WARN_UNUSED_RESULT
433 PARROT_CANNOT_RETURN_NULL
434 static STRING*
435 path_guarantee_trailing_separator(PARROT_INTERP, ARGMOD(STRING *path))
437 ASSERT_ARGS(path_guarantee_trailing_separator)
438 STRING * const path_separator_string = string_chr(interp, path_separator);
440 /* make sure the path has a trailing slash before appending the file */
441 if (Parrot_str_indexed(interp, path , path->strlen - 1)
442 != Parrot_str_indexed(interp, path_separator_string, 0))
443 path = Parrot_str_append(interp, path , path_separator_string);
445 return path;
450 =item C<static STRING* path_append(PARROT_INTERP, STRING *l_path, STRING
451 *r_path)>
453 binary path arguments, the left arg is modified.
454 a trailing separator is guaranteed for the left
455 argument and the right argument is appended
457 =cut
461 PARROT_WARN_UNUSED_RESULT
462 PARROT_CANNOT_RETURN_NULL
463 static STRING*
464 path_append(PARROT_INTERP, ARGMOD(STRING *l_path), ARGMOD(STRING *r_path))
466 ASSERT_ARGS(path_append)
467 l_path = path_guarantee_trailing_separator(interp, l_path);
468 l_path = Parrot_str_append(interp, l_path, r_path);
470 return l_path;
475 =item C<static STRING* path_concat(PARROT_INTERP, STRING *l_path, STRING
476 *r_path)>
478 binary path arguments. A new string is created
479 that is the concatenation of the two path components
480 with a path-separator.
482 =cut
486 PARROT_WARN_UNUSED_RESULT
487 PARROT_CANNOT_RETURN_NULL
488 static STRING*
489 path_concat(PARROT_INTERP, ARGMOD(STRING *l_path), ARGMOD(STRING *r_path))
491 ASSERT_ARGS(path_concat)
492 STRING* join;
494 join = Parrot_str_copy(interp, l_path);
495 join = path_guarantee_trailing_separator(interp, join);
496 join = Parrot_str_append(interp, join, r_path);
498 return join;
503 =item C<static STRING* try_load_path(PARROT_INTERP, STRING* path)>
505 Attempts to load a file with name C<path>. If the file is successfully located,
506 the finalized name of the file is returned as a STRING. Otherwise, returns
507 NULL.
509 =cut
513 PARROT_WARN_UNUSED_RESULT
514 PARROT_CAN_RETURN_NULL
515 static STRING*
516 try_load_path(PARROT_INTERP, ARGMOD(STRING* path))
518 ASSERT_ARGS(try_load_path)
519 STRING *final;
521 final = Parrot_str_copy(interp, path);
523 final = path_finalize(interp, final);
525 if (Parrot_stat_info_intval(interp, final, STAT_EXISTS)) {
526 return final;
529 return NULL;
534 =item C<static STRING* try_bytecode_extensions(PARROT_INTERP, STRING* path)>
536 Guess extensions, so that the user can drop the extensions
537 leaving it up to the build process/install whether or not
538 a .pbc, .pasm or a .pir file is used.
540 =cut
544 PARROT_WARN_UNUSED_RESULT
545 PARROT_CAN_RETURN_NULL
546 static STRING*
547 try_bytecode_extensions(PARROT_INTERP, ARGMOD(STRING* path))
549 ASSERT_ARGS(try_bytecode_extensions)
550 STRING *test_path, *result;
551 STRING * const bytecode_extension = CONST_STRING(interp, ".pbc");
552 STRING * const pir_extension = CONST_STRING(interp, ".pir");
553 STRING * const pasm_extension = CONST_STRING(interp, ".pasm");
555 test_path = Parrot_str_copy(interp, path);
557 /* First try the path as given. */
558 result = try_load_path(interp, test_path);
559 if (result)
560 return result;
563 If the original requested file doesn't exist, try it with a
564 different extension. A requested PIR or PASM file will check for a
565 corresponding bytecode file. A requested bytecode file will check
566 first for a corresponding PIR file, then for a PASM file.
569 if (!STRING_IS_NULL(test_path)) {
570 if (Parrot_str_byte_length(interp, test_path) > 4) {
571 STRING *orig_ext = Parrot_str_substr(interp, test_path, -4, 4, NULL, 0);
572 /* First try substituting .pbc for the .pir extension */
573 if (Parrot_str_equal(interp, orig_ext, pir_extension)) {
574 STRING * const without_ext = Parrot_str_chopn(interp, test_path, 4);
575 test_path = Parrot_str_append(interp, without_ext, bytecode_extension);
576 result = try_load_path(interp, test_path);
577 if (result)
578 return result;
580 /* Next try substituting .pir, then .pasm for the .pbc extension */
581 else if (Parrot_str_equal(interp, orig_ext, bytecode_extension)) {
582 STRING * const without_ext = Parrot_str_chopn(interp, test_path, 4);
583 test_path = Parrot_str_append(interp, without_ext, pir_extension);
584 result = try_load_path(interp, test_path);
585 if (result)
586 return result;
588 test_path = Parrot_str_append(interp, without_ext, pasm_extension);
589 result = try_load_path(interp, test_path);
590 if (result)
591 return result;
596 /* Finally, try substituting .pbc for the .pasm extension. */
597 if (Parrot_str_byte_length(interp, test_path) > 5) {
598 STRING * const orig_ext = Parrot_str_substr(interp, test_path, -5, 5, NULL, 0);
599 if (Parrot_str_equal(interp, orig_ext, pasm_extension)) {
600 STRING * const without_ext = Parrot_str_chopn(interp, test_path, 5);
601 test_path = Parrot_str_append(interp, without_ext, bytecode_extension);
602 result = try_load_path(interp, test_path);
603 if (result)
604 return result;
609 return NULL;
614 =item C<void Parrot_lib_add_path(PARROT_INTERP, STRING *path_str, enum_lib_paths
615 which)>
617 Add a path to the library searchpath of the given type (passing in a STRING).
619 =cut
623 PARROT_EXPORT
624 void
625 Parrot_lib_add_path(PARROT_INTERP,
626 ARGIN(STRING *path_str),
627 enum_lib_paths which)
629 ASSERT_ARGS(Parrot_lib_add_path)
630 PMC * const iglobals = interp->iglobals;
631 PMC * const lib_paths = VTABLE_get_pmc_keyed_int(interp, iglobals,
632 IGLOBALS_LIB_PATHS);
633 PMC * const paths = VTABLE_get_pmc_keyed_int(interp, lib_paths, which);
634 VTABLE_unshift_string(interp, paths, path_str);
639 =item C<void Parrot_lib_add_path_from_cstring(PARROT_INTERP, const char *path,
640 enum_lib_paths which)>
642 Add a path to the library searchpath of the given type (passing in a C string).
644 =cut
648 PARROT_EXPORT
649 void
650 Parrot_lib_add_path_from_cstring(PARROT_INTERP,
651 ARGIN(const char *path),
652 enum_lib_paths which)
654 ASSERT_ARGS(Parrot_lib_add_path_from_cstring)
655 STRING * const path_str = Parrot_str_new(interp, path, 0);
656 Parrot_lib_add_path(interp, path_str, which);
661 =item C<STRING* Parrot_locate_runtime_file_str(PARROT_INTERP, STRING *file,
662 enum_runtime_ft type)>
664 Locate the full path for C<file_name> and the given file type(s).
666 The C<enum_runtime_ft type> is one or more of the types defined in
667 F<include/parrot/library.h>.
669 =cut
673 PARROT_EXPORT
674 PARROT_WARN_UNUSED_RESULT
675 PARROT_CAN_RETURN_NULL
676 STRING*
677 Parrot_locate_runtime_file_str(PARROT_INTERP, ARGMOD(STRING *file),
678 enum_runtime_ft type)
680 ASSERT_ARGS(Parrot_locate_runtime_file_str)
681 STRING *prefix;
682 STRING *full_name;
683 PMC *paths;
684 INTVAL i, n;
686 /* if this is an absolute path return it as is */
687 if (is_abs_path(file))
688 return file;
690 if (type & PARROT_RUNTIME_FT_LANG)
691 paths = get_search_paths(interp, PARROT_LIB_PATH_LANG);
692 else if (type & PARROT_RUNTIME_FT_DYNEXT)
693 paths = get_search_paths(interp, PARROT_LIB_PATH_DYNEXT);
694 else if (type & (PARROT_RUNTIME_FT_PBC | PARROT_RUNTIME_FT_SOURCE))
695 paths = get_search_paths(interp, PARROT_LIB_PATH_LIBRARY);
696 else
697 paths = get_search_paths(interp, PARROT_LIB_PATH_INCLUDE);
699 prefix = Parrot_get_runtime_path(interp);
700 n = VTABLE_elements(interp, paths);
702 for (i = 0; i < n; ++i) {
703 STRING * const path = VTABLE_get_string_keyed_int(interp, paths, i);
704 STRING *found_name;
706 full_name = Parrot_str_copy(interp, path);
707 full_name = path_append(interp, full_name, file);
709 found_name =
710 (type & PARROT_RUNTIME_FT_DYNEXT)
711 ? try_load_path(interp, full_name)
712 : try_bytecode_extensions(interp, full_name);
714 if (found_name)
715 return found_name;
717 if (Parrot_str_byte_length(interp, prefix) && !is_abs_path(path)) {
718 full_name = path_concat(interp, prefix, full_name);
720 found_name =
721 (type & PARROT_RUNTIME_FT_DYNEXT)
722 ? try_load_path(interp, full_name)
723 : try_bytecode_extensions(interp, full_name);
725 if (found_name)
726 return found_name;
730 full_name =
731 (type & PARROT_RUNTIME_FT_DYNEXT)
732 ? try_load_path(interp, file)
733 : try_bytecode_extensions(interp, file);
735 return full_name;
740 =item C<char* Parrot_locate_runtime_file(PARROT_INTERP, const char *file_name,
741 enum_runtime_ft type)>
743 Locate the full path for C<file_name> and the given file type(s). If
744 successful, returns a C-string allocated with C<Parrot_str_to_cstring> or
745 NULL otherwise. Remember to free the string with C<Parrot_str_free_cstring()>.
747 If successful, the returned STRING is 0-terminated so that
748 C<result-E<gt>strstart> is usable as B<const char*> c-string for C library
749 functions like fopen(3). This is the preferred API function.
751 The C<enum_runtime_ft type> is one or more of the types defined in
752 F<include/parrot/library.h>.
754 =cut
759 PARROT_EXPORT
760 PARROT_WARN_UNUSED_RESULT
761 PARROT_CAN_RETURN_NULL
762 PARROT_MALLOC
763 char*
764 Parrot_locate_runtime_file(PARROT_INTERP, ARGIN(const char *file_name),
765 enum_runtime_ft type)
767 ASSERT_ARGS(Parrot_locate_runtime_file)
768 STRING * const file = Parrot_str_new(interp, file_name, 0);
769 STRING * const result = Parrot_locate_runtime_file_str(interp, file, type);
771 * XXX valgrind shows e.g.
772 * invalid read of size 8 inside a string of length 69
773 * at position 64
774 * it seems that dlopen accesses words beyond the string end
776 * see also the log at #37814
778 return result ? Parrot_str_to_cstring(interp, result) : NULL;
783 =item C<char* Parrot_get_runtime_prefix(PARROT_INTERP)>
785 Return a malloced C-string for the runtime prefix. The calling function
786 must free it.
788 This function is deprecated, use Parrot_get_runtime_path instead.
789 See TT #1191
791 =cut
795 PARROT_EXPORT
796 PARROT_MALLOC
797 PARROT_CANNOT_RETURN_NULL
798 char*
799 Parrot_get_runtime_prefix(PARROT_INTERP)
801 ASSERT_ARGS(Parrot_get_runtime_prefix)
802 char * const env = Parrot_getenv(interp, CONST_STRING(interp, "PARROT_RUNTIME"));
804 if (env)
805 return env;
806 else {
807 PMC * const config_hash =
808 VTABLE_get_pmc_keyed_int(interp, interp->iglobals, (INTVAL) IGLOBALS_CONFIG_HASH);
810 if (VTABLE_elements(interp, config_hash)) {
811 STRING * const key = CONST_STRING(interp, "prefix");
812 STRING * const s = VTABLE_get_string_keyed_str(interp, config_hash, key);
813 return Parrot_str_to_cstring(interp, s);
815 else
816 return mem_sys_strdup(".");
822 =item C<STRING * Parrot_get_runtime_path(PARROT_INTERP)>
824 Return a string for the runtime prefix.
826 =cut
830 PARROT_EXPORT
831 PARROT_CANNOT_RETURN_NULL
832 STRING *
833 Parrot_get_runtime_path(PARROT_INTERP)
835 ASSERT_ARGS(Parrot_get_runtime_path)
836 char * const env = Parrot_getenv(interp, CONST_STRING(interp, "PARROT_RUNTIME"));
837 STRING *result;
839 if (env)
841 result = Parrot_str_new(interp, env, 0);
843 else {
844 PMC * const config_hash =
845 VTABLE_get_pmc_keyed_int(interp, interp->iglobals, (INTVAL) IGLOBALS_CONFIG_HASH);
847 if (VTABLE_elements(interp, config_hash)) {
848 STRING * const key = CONST_STRING(interp, "prefix");
849 result = VTABLE_get_string_keyed_str(interp, config_hash, key);
851 else
852 result = CONST_STRING(interp, ".");
854 return result;
859 =item C<STRING * parrot_split_path_ext(PARROT_INTERP, STRING *in, STRING
860 **wo_ext, STRING **ext)>
862 Split the pathstring C<in> into <path><filestem><ext>. Return the
863 C<filestem> of the pathstring. Set C<wo_ext> to the part without
864 extension and C<ext> to the extension or NULL.
866 =cut
870 PARROT_IGNORABLE_RESULT
871 PARROT_CANNOT_RETURN_NULL
872 STRING *
873 parrot_split_path_ext(PARROT_INTERP, ARGMOD(STRING *in),
874 ARGOUT(STRING **wo_ext), ARGOUT(STRING **ext))
876 ASSERT_ARGS(parrot_split_path_ext)
878 /* This is a quick fix for TT #65
879 * TODO: redo it with the string reimplementation
881 const char * charset = Parrot_charset_c_name(interp,
882 Parrot_charset_number_of_str(interp, in));
883 STRING * const slash1 = string_make(interp, "/", 1, charset,
884 PObj_external_FLAG|PObj_constant_FLAG);
885 STRING * const slash2 = string_make(interp, "\\", 1, charset,
886 PObj_external_FLAG|PObj_constant_FLAG);
887 STRING * const dot = string_make(interp, ".", 1, charset,
888 PObj_external_FLAG|PObj_constant_FLAG);
890 const INTVAL len = Parrot_str_byte_length(interp, in);
891 STRING *stem;
892 INTVAL pos_sl, pos_dot;
894 pos_sl = CHARSET_RINDEX(interp, in, slash1, len);
895 if (pos_sl == -1)
896 pos_sl = CHARSET_RINDEX(interp, in, slash2, len);
897 pos_dot = CHARSET_RINDEX(interp, in, dot, len);
899 /* ignore dot in directory name */
900 if (pos_dot != -1 && pos_dot < pos_sl)
901 pos_dot = -1;
903 ++pos_dot;
904 ++pos_sl;
905 if (pos_sl && pos_dot) {
906 stem = Parrot_str_substr(interp, in, pos_sl, pos_dot - pos_sl - 1,
907 NULL, 0);
908 *wo_ext = Parrot_str_substr(interp, in, 0, pos_dot - 1, NULL, 0);
909 *ext = Parrot_str_substr(interp, in, pos_dot, len - pos_dot, NULL, 0);
911 else if (pos_dot) {
912 stem = Parrot_str_substr(interp, in, 0, pos_dot - 1, NULL, 0);
913 *wo_ext = stem;
914 *ext = Parrot_str_substr(interp, in, pos_dot, len - pos_dot, NULL, 0);
916 else if (pos_sl) {
917 stem = Parrot_str_substr(interp, in, pos_sl, len - pos_sl, NULL, 0);
918 *wo_ext = Parrot_str_copy(interp, in);
919 *ext = NULL;
921 else {
922 stem = Parrot_str_copy(interp, in);
923 *wo_ext = stem;
924 *ext = NULL;
926 return stem;
931 =back
933 =head1 SEE ALSO
935 F<include/parrot/library.h>
937 =cut
943 * Local variables:
944 * c-file-style: "parrot"
945 * End:
946 * vim: expandtab shiftwidth=4: