PageRenderTime 48ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/src/c/load.d

https://gitlab.com/bhuroc/ecl
D | 304 lines | 240 code | 16 blank | 48 comment | 64 complexity | 84e070dbad5f38a474b1f2815aa9c5e3 MD5 | raw file
  1. /* -*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*- */
  2. /* vim: set filetype=c tabstop=8 shiftwidth=4 expandtab: */
  3. /*
  4. load.d -- Binary loader (contains also open_fasl_data).
  5. */
  6. /*
  7. Copyright (c) 1990, Giuseppe Attardi and William F. Schelter.
  8. Copyright (c) 2001, Juan Jose Garcia Ripoll.
  9. ECL is free software; you can redistribute it and/or
  10. modify it under the terms of the GNU Library General Public
  11. License as published by the Free Software Foundation; either
  12. version 2 of the License, or (at your option) any later version.
  13. See file '../Copyright' for full details.
  14. */
  15. #include <ecl/ecl.h>
  16. #include <ecl/ecl-inl.h>
  17. #include <ecl/internal.h>
  18. #ifdef ENABLE_DLOPEN
  19. cl_object
  20. si_load_binary(cl_object filename, cl_object verbose,
  21. cl_object print, cl_object external_format)
  22. {
  23. const cl_env_ptr the_env = ecl_process_env();
  24. cl_object block, map, array;
  25. cl_object basename;
  26. cl_object init_prefix, prefix;
  27. cl_object output;
  28. /* We need the full pathname */
  29. filename = cl_truename(filename);
  30. /* Try to load shared object file */
  31. block = ecl_library_open(filename, 1);
  32. if (block->cblock.handle == NULL) {
  33. output = ecl_library_error(block);
  34. goto OUTPUT;
  35. }
  36. /* Fist try to call "init_CODE()" */
  37. init_prefix = _ecl_library_default_entry();
  38. block->cblock.entry =
  39. ecl_library_symbol(block, (char *)init_prefix->base_string.self, 0);
  40. if (block->cblock.entry != NULL)
  41. goto GO_ON;
  42. /* Next try to call "init_FILE()" where FILE is the file name */
  43. prefix = ecl_symbol_value(@'si::*init-function-prefix*');
  44. init_prefix = _ecl_library_init_prefix();
  45. if (Null(prefix)) {
  46. prefix = init_prefix;
  47. } else {
  48. prefix = @si::base-string-concatenate(3,
  49. init_prefix,
  50. prefix,
  51. make_constant_base_string("_"));
  52. }
  53. basename = cl_pathname_name(1,filename);
  54. basename = @si::base-string-concatenate(2, prefix, @string-upcase(1, funcall(4, @'nsubstitute', ECL_CODE_CHAR('_'), ECL_CODE_CHAR('-'), basename)));
  55. block->cblock.entry = ecl_library_symbol(block, (char*)basename->base_string.self, 0);
  56. if (block->cblock.entry == NULL) {
  57. output = ecl_library_error(block);
  58. ecl_library_close(block);
  59. goto OUTPUT;
  60. }
  61. GO_ON:
  62. /* Finally, perform initialization */
  63. ecl_init_module(block, (void (*)(cl_object))(block->cblock.entry));
  64. output = ECL_NIL;
  65. OUTPUT:
  66. ecl_return1(the_env, output);
  67. }
  68. #endif /* !ENABLE_DLOPEN */
  69. cl_object
  70. si_load_source(cl_object source, cl_object verbose, cl_object print, cl_object external_format)
  71. {
  72. cl_env_ptr the_env = ecl_process_env();
  73. cl_object x, strm;
  74. /* Source may be either a stream or a filename */
  75. if (ecl_t_of(source) != t_pathname && ecl_t_of(source) != t_base_string) {
  76. /* INV: if "source" is not a valid stream, file.d will complain */
  77. strm = source;
  78. } else {
  79. strm = ecl_open_stream(source, ecl_smm_input, ECL_NIL, ECL_NIL, 8,
  80. ECL_STREAM_C_STREAM, external_format);
  81. if (Null(strm))
  82. @(return ECL_NIL)
  83. }
  84. ECL_UNWIND_PROTECT_BEGIN(the_env) {
  85. cl_object form_index = ecl_make_fixnum(0);
  86. cl_object pathname = ECL_SYM_VAL(the_env, @'*load-pathname*');
  87. cl_object location = CONS(pathname, form_index);
  88. ecl_bds_bind(the_env, @'ext::*source-location*', location);
  89. for (;;) {
  90. form_index = ecl_file_position(strm);
  91. ECL_RPLACD(location, form_index);
  92. x = si_read_object_or_ignore(strm, OBJNULL);
  93. if (x == OBJNULL)
  94. break;
  95. if (the_env->nvalues) {
  96. si_eval_with_env(1, x);
  97. if (print != ECL_NIL) {
  98. @write(1, x);
  99. @terpri(0);
  100. }
  101. }
  102. }
  103. ecl_bds_unwind1(the_env);
  104. } ECL_UNWIND_PROTECT_EXIT {
  105. /* We do not want to come back here if close_stream fails,
  106. therefore, first we frs_pop() current jump point, then
  107. try to close the stream, and then jump to next catch
  108. point */
  109. if (strm != source)
  110. cl_close(3, strm, @':abort', @'t');
  111. } ECL_UNWIND_PROTECT_END;
  112. @(return ECL_NIL)
  113. }
  114. cl_object
  115. si_load_bytecodes(cl_object source, cl_object verbose, cl_object print, cl_object external_format)
  116. {
  117. cl_env_ptr env = ecl_process_env();
  118. cl_object forms, strm;
  119. cl_object old_eptbc = env->packages_to_be_created;
  120. /* Source may be either a stream or a filename */
  121. if (ecl_t_of(source) != t_pathname && ecl_t_of(source) != t_base_string) {
  122. /* INV: if "source" is not a valid stream, file.d will complain */
  123. strm = source;
  124. } else {
  125. strm = ecl_open_stream(source, ecl_smm_input, ECL_NIL, ECL_NIL, 8,
  126. ECL_STREAM_C_STREAM, external_format);
  127. if (Null(strm))
  128. @(return ECL_NIL)
  129. }
  130. ECL_UNWIND_PROTECT_BEGIN(env) {
  131. {
  132. cl_object progv_list = ECL_SYM_VAL(env, @'si::+ecl-syntax-progv-list+');
  133. cl_index bds_ndx = ecl_progv(env, ECL_CONS_CAR(progv_list),
  134. ECL_CONS_CDR(progv_list));
  135. env->packages_to_be_created_p = ECL_T;
  136. forms = cl_read(1, strm);
  137. env->packages_to_be_created_p = ECL_NIL;
  138. ecl_bds_unwind(env, bds_ndx);
  139. }
  140. while (!Null(forms)) {
  141. if (ECL_LISTP(forms)) {
  142. cl_object x = ECL_CONS_CAR(forms);
  143. forms = ECL_CONS_CDR(forms);
  144. if (ecl_t_of(x) == t_bytecodes) {
  145. _ecl_funcall1(x);
  146. continue;
  147. }
  148. }
  149. FEerror("Corrupt bytecodes file ~S", 1, source);
  150. }
  151. {
  152. cl_object x;
  153. x = cl_set_difference(2, env->packages_to_be_created, old_eptbc);
  154. old_eptbc = env->packages_to_be_created;
  155. unlikely_if (!Null(x)) {
  156. CEerror(ECL_T,
  157. Null(ECL_CONS_CDR(x))?
  158. "Package ~A referenced in "
  159. "compiled file~& ~A~&but has not been created":
  160. "The packages~& ~A~&were referenced in "
  161. "compiled file~& ~A~&but have not been created",
  162. 2, x, source);
  163. }
  164. }
  165. } ECL_UNWIND_PROTECT_EXIT {
  166. /* We do not want to come back here if close_stream fails,
  167. therefore, first we frs_pop() current jump point, then
  168. try to close the stream, and then jump to next catch
  169. point */
  170. if (strm != source)
  171. cl_close(3, strm, @':abort', @'t');
  172. } ECL_UNWIND_PROTECT_END;
  173. @(return ECL_NIL)
  174. }
  175. @(defun load (source
  176. &key (verbose ecl_symbol_value(@'*load-verbose*'))
  177. (print ecl_symbol_value(@'*load-print*'))
  178. (if_does_not_exist @':error')
  179. (external_format @':default')
  180. (search_list ecl_symbol_value(@'si::*load-search-list*'))
  181. &aux pathname pntype hooks filename function ok)
  182. bool not_a_filename = 0;
  183. @
  184. /* If source is a stream, read conventional lisp code from it */
  185. if (ecl_t_of(source) != t_pathname && !ecl_stringp(source)) {
  186. /* INV: if "source" is not a valid stream, file.d will complain */
  187. filename = source;
  188. function = ECL_NIL;
  189. not_a_filename = 1;
  190. goto NOT_A_FILENAME;
  191. }
  192. /* INV: coerce_to_file_pathname() creates a fresh new pathname object */
  193. source = cl_merge_pathnames(1, source);
  194. pathname = coerce_to_file_pathname(source);
  195. pntype = pathname->pathname.type;
  196. filename = ECL_NIL;
  197. hooks = ecl_symbol_value(@'ext::*load-hooks*');
  198. if (Null(pathname->pathname.directory) &&
  199. Null(pathname->pathname.host) &&
  200. Null(pathname->pathname.device) &&
  201. !Null(search_list))
  202. {
  203. loop_for_in(search_list) {
  204. cl_object d = CAR(search_list);
  205. cl_object f = cl_merge_pathnames(2, pathname, d);
  206. cl_object ok = cl_load(11, f, @':verbose', verbose,
  207. @':print', print,
  208. @':if-does-not-exist', ECL_NIL,
  209. @':external-format', external_format,
  210. @':search-list', ECL_NIL);
  211. if (!Null(ok)) {
  212. @(return ok);
  213. }
  214. } end_loop_for_in;
  215. }
  216. if (!Null(pntype) && (pntype != @':wild')) {
  217. /* If filename already has an extension, make sure
  218. that the file exists */
  219. cl_object kind;
  220. filename = si_coerce_to_filename(pathname);
  221. kind = si_file_kind(filename, ECL_T);
  222. if (kind != @':file' && kind != @':special') {
  223. filename = ECL_NIL;
  224. } else {
  225. function = cl_cdr(ecl_assoc(pathname->pathname.type, hooks));
  226. }
  227. } else loop_for_in(hooks) {
  228. /* Otherwise try with known extensions until a matching
  229. file is found */
  230. cl_object kind;
  231. filename = pathname;
  232. filename->pathname.type = CAAR(hooks);
  233. function = CDAR(hooks);
  234. kind = si_file_kind(filename, ECL_T);
  235. if (kind == @':file' || kind == @':special')
  236. break;
  237. else
  238. filename = ECL_NIL;
  239. } end_loop_for_in;
  240. if (Null(filename)) {
  241. if (Null(if_does_not_exist))
  242. @(return ECL_NIL)
  243. else
  244. FEcannot_open(source);
  245. }
  246. NOT_A_FILENAME:
  247. if (verbose != ECL_NIL) {
  248. cl_format(3, ECL_T, make_constant_base_string("~&;;; Loading ~s~%"),
  249. filename);
  250. }
  251. ecl_bds_bind(the_env, @'*package*', ecl_symbol_value(@'*package*'));
  252. ecl_bds_bind(the_env, @'*readtable*', ecl_symbol_value(@'*readtable*'));
  253. ecl_bds_bind(the_env, @'*load-pathname*', not_a_filename? ECL_NIL : source);
  254. ecl_bds_bind(the_env, @'*load-truename*',
  255. not_a_filename? ECL_NIL : (filename = cl_truename(filename)));
  256. if (!Null(function)) {
  257. ok = funcall(5, function, filename, verbose, print, external_format);
  258. } else {
  259. #if 0 /* defined(ENABLE_DLOPEN) && !defined(ECL_MS_WINDOWS_HOST)*/
  260. /*
  261. * DISABLED BECAUSE OF SECURITY ISSUES!
  262. * In systems where we can do this, we try to load the file
  263. * as a binary. When it fails, we will revert to source
  264. * loading below. Is this safe? Well, it depends on whether
  265. * your op.sys. checks integrity of binary exectables or
  266. * just loads _anything_.
  267. */
  268. if (not_a_filename) {
  269. ok = ECL_T;
  270. } else {
  271. ok = si_load_binary(filename, verbose, print);
  272. }
  273. if (!Null(ok))
  274. #endif
  275. ok = si_load_source(filename, verbose, print, external_format);
  276. }
  277. ecl_bds_unwind_n(the_env, 4);
  278. if (!Null(ok))
  279. FEerror("LOAD: Could not load file ~S (Error: ~S)",
  280. 2, filename, ok);
  281. if (print != ECL_NIL) {
  282. cl_format(3, ECL_T, make_constant_base_string("~&;;; Loading ~s~%"),
  283. filename);
  284. }
  285. @(return filename)
  286. @)