jerry_module.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <rtthread.h>
  5. #include <finsh.h>
  6. #include "jerry_util.h"
  7. #include "jerry_module.h"
  8. #include <jerryscript-ext/module.h>
  9. #include <ecma-globals.h>
  10. #ifndef PATH_MAX
  11. #define PATH_MAX 256
  12. #endif
  13. char *getcwd(char *buf, size_t size);
  14. typedef jerry_value_t (*module_init_func_t)(void);
  15. #ifdef RT_USING_DFS
  16. char *js_module_dirname(char *path)
  17. {
  18. size_t i;
  19. char *s = NULL;
  20. if (!path || !*path) return NULL;
  21. s = rt_strdup(path);
  22. if (!s) return NULL;
  23. i = strlen(s)-1;
  24. for (; s[i]=='/'; i--) if (!i)
  25. {
  26. s[0] = '/';
  27. goto __exit;
  28. }
  29. for (; s[i]!='/'; i--) if (!i)
  30. {
  31. s[0] = '.';
  32. goto __exit;
  33. }
  34. for (; s[i]=='/'; i--) if (!i)
  35. {
  36. s[0] = '/';
  37. goto __exit;
  38. }
  39. __exit:
  40. s[i+1] = 0;
  41. return s;
  42. }
  43. char *js_module_normalize_path(const char *directory, const char *filename)
  44. {
  45. char *fullpath;
  46. char *dst0, *dst, *src;
  47. char *cwd = NULL;
  48. /* check parameters */
  49. if (filename == NULL) return NULL;
  50. if (directory == NULL && filename[0] != '/')
  51. {
  52. cwd = (char*) malloc (PATH_MAX);
  53. if (cwd == NULL) return NULL;
  54. /* get current working directory */
  55. getcwd(cwd, PATH_MAX);
  56. directory = cwd;
  57. }
  58. if (filename[0] != '/') /* it's a absolute path, use it directly */
  59. {
  60. fullpath = malloc(strlen(directory) + strlen(filename) + 2);
  61. if (fullpath == NULL)
  62. {
  63. free(cwd);
  64. return NULL;
  65. }
  66. /* join path and file name */
  67. snprintf(fullpath, strlen(directory) + strlen(filename) + 2,
  68. "%s/%s", directory, filename);
  69. }
  70. else
  71. {
  72. fullpath = rt_strdup(filename); /* copy string */
  73. if (fullpath == NULL)
  74. return NULL;
  75. }
  76. src = fullpath;
  77. dst = fullpath;
  78. dst0 = dst;
  79. while (1)
  80. {
  81. char c = *src;
  82. if (c == '.')
  83. {
  84. if (!src[1]) src ++; /* '.' and ends */
  85. else if (src[1] == '/')
  86. {
  87. /* './' case */
  88. src += 2;
  89. while ((*src == '/') && (*src != '\0'))
  90. src ++;
  91. continue;
  92. }
  93. else if (src[1] == '.')
  94. {
  95. if (!src[2])
  96. {
  97. /* '..' and ends case */
  98. src += 2;
  99. goto up_one;
  100. }
  101. else if (src[2] == '/')
  102. {
  103. /* '../' case */
  104. src += 3;
  105. while ((*src == '/') && (*src != '\0'))
  106. src ++;
  107. goto up_one;
  108. }
  109. }
  110. }
  111. /* copy up the next '/' and erase all '/' */
  112. while ((c = *src++) != '\0' && c != '/')
  113. *dst ++ = c;
  114. if (c == '/')
  115. {
  116. *dst ++ = '/';
  117. while (c == '/')
  118. c = *src++;
  119. src --;
  120. }
  121. else if (!c)
  122. break;
  123. continue;
  124. up_one:
  125. dst --;
  126. if (dst < dst0)
  127. {
  128. free(cwd);
  129. free(fullpath);
  130. return NULL;
  131. }
  132. while (dst0 < dst && dst[-1] != '/')
  133. dst --;
  134. }
  135. *dst = '\0';
  136. /* remove '/' in the end of path if exist */
  137. dst --;
  138. if ((dst != fullpath) && (*dst == '/'))
  139. *dst = '\0';
  140. /* final check fullpath is not empty, for the special path of lwext "/.." */
  141. if ('\0' == fullpath[0])
  142. {
  143. fullpath[0] = '/';
  144. fullpath[1] = '\0';
  145. }
  146. free(cwd);
  147. return fullpath;
  148. }
  149. /* load module from file system */
  150. static bool load_module_from_filesystem(const jerry_value_t module_name, jerry_value_t *result)
  151. {
  152. bool ret = false;
  153. char *str = NULL;
  154. char *module = js_value_to_string(module_name);
  155. char *dirname = NULL;
  156. jerry_value_t dirname_value = ECMA_VALUE_UNDEFINED;
  157. jerry_value_t filename_value = ECMA_VALUE_UNDEFINED;
  158. jerry_value_t global_obj = ECMA_VALUE_UNDEFINED;
  159. char *full_path = NULL;
  160. char *full_dir = NULL;
  161. global_obj = jerry_get_global_object();
  162. dirname_value = js_get_property(global_obj, "__dirname");
  163. if (jerry_value_is_string(dirname_value))
  164. {
  165. dirname = js_value_to_string(dirname_value);
  166. }
  167. else
  168. {
  169. dirname = NULL;
  170. }
  171. if (module[0] != '/') /* is a relative path */
  172. {
  173. full_path = js_module_normalize_path(dirname, module);
  174. }
  175. else
  176. {
  177. full_path = js_module_normalize_path(NULL, module);
  178. }
  179. free(dirname);
  180. uint32_t len = js_read_file(full_path, &str);
  181. if (len == 0) goto __exit;
  182. filename_value = js_get_property(global_obj, "__filename");
  183. /* set new __filename and __dirname */
  184. full_dir = js_module_dirname(full_path);
  185. js_set_string_property(global_obj, "__dirname", full_dir);
  186. js_set_string_property(global_obj, "__filename", full_path);
  187. (*result) = jerry_eval((jerry_char_t *)str, len, false);
  188. if (jerry_value_is_error(*result))
  189. printf("failed to evaluate JS\n");
  190. else
  191. ret = true;
  192. /* restore __filename and __dirname */
  193. js_set_property(global_obj, "__dirname", dirname_value);
  194. js_set_property(global_obj, "__filename", filename_value);
  195. __exit:
  196. if (full_dir) free(full_dir);
  197. if (full_path) free(full_path);
  198. jerry_release_value(global_obj);
  199. jerry_release_value(dirname_value);
  200. jerry_release_value(filename_value);
  201. free(module);
  202. free(str);
  203. return ret;
  204. }
  205. #endif
  206. /* load builtin module */
  207. static bool load_module_from_builtin(const jerry_value_t module_name,
  208. jerry_value_t *result)
  209. {
  210. bool ret = false;
  211. module_init_func_t module_init;
  212. char *module = js_value_to_string(module_name);
  213. #ifdef HOST_BUILD
  214. {
  215. extern jerry_value_t js_module_rtthread_init(void);
  216. if (strcmp(module, "os") == 0)
  217. {
  218. module_init = js_module_rtthread_init;
  219. *result = module_init();
  220. ret = true;
  221. }
  222. }
  223. #elif defined(RT_USING_FINSH)
  224. int len = strlen(module) + 7;
  225. char module_fullname[len];
  226. snprintf(module_fullname, len, "__jsm_%s", module);
  227. module_fullname[len - 1] = '\0';
  228. /* find syscall in shell symbol section */
  229. struct finsh_syscall* syscall;
  230. for (syscall = _syscall_table_begin; syscall < _syscall_table_end; FINSH_NEXT_SYSCALL(syscall))
  231. {
  232. if (strcmp(syscall->name, module_fullname) == 0)
  233. break;
  234. }
  235. if (syscall < _syscall_table_end)
  236. {
  237. module_init = (module_init_func_t)syscall->func;
  238. *result = module_init();
  239. ret = true;
  240. }
  241. #endif
  242. free(module);
  243. return ret;
  244. }
  245. #ifdef RT_USING_DFS
  246. static jerryx_module_resolver_t load_filesystem_resolver =
  247. {
  248. NULL,
  249. load_module_from_filesystem
  250. };
  251. #endif
  252. static jerryx_module_resolver_t load_builtin_resolver =
  253. {
  254. NULL,
  255. load_module_from_builtin
  256. };
  257. static const jerryx_module_resolver_t *resolvers[] =
  258. {
  259. &load_builtin_resolver,
  260. #ifdef RT_USING_DFS
  261. &load_filesystem_resolver
  262. #endif
  263. };
  264. DECLARE_HANDLER(require)
  265. {
  266. if (args_cnt == 0)
  267. {
  268. printf("No module name supplied\n");
  269. return jerry_create_null();
  270. }
  271. if (jerry_value_is_string(args[0]) == 0)
  272. {
  273. printf("No module name supplied as string\n");
  274. return jerry_create_null();
  275. }
  276. /* make new module.exports */
  277. jerry_value_t global_obj = jerry_get_global_object();
  278. jerry_value_t modules_obj = ECMA_VALUE_UNDEFINED;
  279. jerry_value_t exports_obj = ECMA_VALUE_UNDEFINED;
  280. modules_obj = js_get_property(global_obj, "module");
  281. exports_obj = js_get_property(modules_obj, "exports");
  282. jerry_value_t module_exports_obj = jerry_create_object();
  283. js_set_property(modules_obj, "exports", module_exports_obj);
  284. jerry_release_value(module_exports_obj);
  285. /* Try each of the resolvers to see if we can find the requested module */
  286. char *module = js_value_to_string(args[0]);
  287. jerry_value_t result = jerryx_module_resolve(args[0], resolvers, sizeof(resolvers)/sizeof(resolvers[0]));
  288. if (jerry_value_is_error(result))
  289. {
  290. printf("Couldn't load module %s\n", module);
  291. jerry_release_value(result);
  292. /* create result with error */
  293. result = jerry_create_error(JERRY_ERROR_TYPE,
  294. (const jerry_char_t *) "Module not found");
  295. }
  296. /* restore the parent module.exports */
  297. js_set_property(modules_obj, "exports", exports_obj);
  298. jerry_release_value(global_obj);
  299. jerry_release_value(modules_obj);
  300. jerry_release_value(exports_obj);
  301. free(module);
  302. return result;
  303. }
  304. int js_module_init(void)
  305. {
  306. jerry_value_t global_obj = jerry_get_global_object();
  307. jerry_value_t modules_obj = jerry_create_object();
  308. jerry_value_t exports_obj = jerry_create_object();
  309. js_set_property(modules_obj, "exports", exports_obj);
  310. js_set_property(global_obj, "module", modules_obj);
  311. REGISTER_HANDLER(require);
  312. jerry_release_value(global_obj);
  313. jerry_release_value(modules_obj);
  314. jerry_release_value(exports_obj);
  315. return 0;
  316. }