PageRenderTime 32ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/erts/etc/common/erlexec.c

https://github.com/erlang/otp
C | 2379 lines | 2349 code | 7 blank | 23 comment | 5 complexity | 60111c559caea80bad62fe6a268e28b8 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, Unlicense, LGPL-2.1
  1. /*
  2. * %CopyrightBegin%
  3. *
  4. * Copyright Ericsson AB 1996-2021. All Rights Reserved.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. * %CopyrightEnd%
  19. */
  20. #include "etc_common.h"
  21. #include "erl_driver.h"
  22. #include "erl_misc_utils.h"
  23. #ifdef __WIN32__
  24. # include "erl_version.h"
  25. # include "init_file.h"
  26. # include <Shlobj.h>
  27. #endif
  28. #define NO 0
  29. #define YES 1
  30. #define DEFAULT_PROGNAME "erl"
  31. #ifdef __WIN32__
  32. #define INI_FILENAME L"erl.ini"
  33. #define INI_SECTION "erlang"
  34. #define DIRSEP "\\"
  35. #define PATHSEP ";"
  36. #define NULL_DEVICE "nul"
  37. #define BINARY_EXT ""
  38. #define DLL_EXT ".dll"
  39. #define EMULATOR_EXECUTABLE "beam.dll"
  40. #else
  41. #define PATHSEP ":"
  42. #define DIRSEP "/"
  43. #define NULL_DEVICE "/dev/null"
  44. #define BINARY_EXT ""
  45. #define EMULATOR_EXECUTABLE "beam"
  46. #endif
  47. #define QUOTE(s) s
  48. /* +M alloc_util allocators */
  49. static const char plusM_au_allocs[]= {
  50. 'u', /* all alloc_util allocators */
  51. 'B', /* binary_alloc */
  52. 'I', /* literal_alloc */
  53. 'D', /* std_alloc */
  54. 'E', /* ets_alloc */
  55. 'F', /* fix_alloc */
  56. 'H', /* eheap_alloc */
  57. 'L', /* ll_alloc */
  58. 'R', /* driver_alloc */
  59. 'S', /* sl_alloc */
  60. 'T', /* temp_alloc */
  61. 'Z', /* test_alloc */
  62. '\0'
  63. };
  64. /* +M alloc_util allocator specific arguments */
  65. static char *plusM_au_alloc_switches[] = {
  66. "as",
  67. "asbcst",
  68. "atags",
  69. "acul",
  70. "acnl",
  71. "acfml",
  72. "cp",
  73. "e",
  74. "t",
  75. "lmbcs",
  76. "mbcgs",
  77. "mbsd",
  78. "mmbcs",
  79. "mmmbc",
  80. "mmsbc",
  81. "msbclt",
  82. "ramv",
  83. "rmbcmt",
  84. "rsbcmt",
  85. "rsbcst",
  86. "sbct",
  87. "smbcs",
  88. NULL
  89. };
  90. /* +M other arguments */
  91. static char *plusM_other_switches[] = {
  92. "ea",
  93. "ummc",
  94. "uycs",
  95. "usac",
  96. "im",
  97. "is",
  98. "it",
  99. "lpm",
  100. "Mamcbf",
  101. "Mrmcbf",
  102. "Mmcs",
  103. "Mscs",
  104. "Mscrfsd",
  105. "Msco",
  106. "Mscrpm",
  107. "Ye",
  108. "Ym",
  109. "Ytp",
  110. "Ytt",
  111. "Iscs",
  112. "Xscs",
  113. NULL
  114. };
  115. /* +s arguments with values */
  116. static char *pluss_val_switches[] = {
  117. "bt",
  118. "bwtdcpu",
  119. "bwtdio",
  120. "bwt",
  121. "cl",
  122. "ct",
  123. "ecio",
  124. "fwi",
  125. "tbt",
  126. "wct",
  127. "wtdcpu",
  128. "wtdio",
  129. "wt",
  130. "ws",
  131. "ss",
  132. "ssdcpu",
  133. "ssdio",
  134. "pp",
  135. "ub",
  136. NULL
  137. };
  138. /* +h arguments with values */
  139. static char *plush_val_switches[] = {
  140. "ms",
  141. "mbs",
  142. "pds",
  143. "max",
  144. "maxk",
  145. "maxel",
  146. "mqd",
  147. "",
  148. NULL
  149. };
  150. /* +r arguments with values */
  151. static char *plusr_val_switches[] = {
  152. "g",
  153. NULL
  154. };
  155. /* +z arguments with values */
  156. static char *plusz_val_switches[] = {
  157. "dbbl",
  158. "dntgc",
  159. "ebwt",
  160. NULL
  161. };
  162. /*
  163. * Define sleep(seconds) in terms of Sleep() on Windows.
  164. */
  165. #ifdef __WIN32__
  166. #define sleep(seconds) Sleep(seconds*1000)
  167. #endif
  168. #define DEFAULT_SUFFIX "smp"
  169. void usage(const char *switchname);
  170. static void usage_format(char *format, ...);
  171. void start_epmd_daemon(char *epmd);
  172. void error(char* format, ...);
  173. /*
  174. * Local functions.
  175. */
  176. static void usage_notsup(const char *switchname, const char *alt);
  177. static char **build_args_from_env(char *env_var);
  178. static char **build_args_from_string(char *env_var, int allow_comments);
  179. static void initial_argv_massage(int *argc, char ***argv);
  180. static void get_parameters(int argc, char** argv);
  181. static void add_arg(char *new_arg);
  182. static void add_args(char *first_arg, ...);
  183. static void ensure_EargsSz(int sz);
  184. static void add_Eargs(char *new_arg);
  185. static void *emalloc(size_t size);
  186. static void *erealloc(void *p, size_t size);
  187. static void efree(void *p);
  188. static char* strsave(char* string);
  189. static int is_one_of_strings(char *str, char *strs[]);
  190. static char *write_str(char *to, const char *from);
  191. static void get_home(void);
  192. static void add_epmd_port(void);
  193. #ifdef __WIN32__
  194. static void get_start_erl_data(char *);
  195. static char* get_value(HKEY key, char* value_name, BOOL mustExit);
  196. static char* possibly_quote(char* arg);
  197. /*
  198. * Functions from win_erlexec.c
  199. */
  200. int start_win_emulator(char* emu, char *startprog,char** argv, int start_detached);
  201. int start_emulator(char* emu, char*start_prog, char** argv, int start_detached);
  202. #endif
  203. /*
  204. * Variables.
  205. */
  206. int nohup = 0;
  207. int keep_window = 0;
  208. static char **Eargsp = NULL; /* Emulator arguments (to appear first). */
  209. static int EargsSz = 0; /* Size of Eargsp */
  210. static int EargsCnt = 0; /* Number of emulator arguments. */
  211. static char **argsp = NULL; /* Common arguments. */
  212. static int argsCnt = 0; /* Number of common arguments */
  213. static int argsSz = 0; /* Size of argsp */
  214. static char tmpStr[10240]; /* Temporary string buffer. */
  215. static int verbose = 0; /* If non-zero, print some extra information. */
  216. static int start_detached = 0; /* If non-zero, the emulator should be
  217. * started detached (in the background).
  218. */
  219. static const char* emu_type = NULL; /* Type of emulator (lcnt, valgrind, etc) */
  220. static const char* emu_flavor = DEFAULT_SUFFIX; /* Flavor of emulator (smp, jit or emu) */
  221. #ifdef __WIN32__
  222. static char *start_emulator_program = NULL; /* For detached mode -
  223. erl.exe/werl.exe */
  224. static char* key_val_name = ERLANG_VERSION; /* Used by the registry
  225. * access functions.
  226. */
  227. static char* boot_script = NULL; /* used by option -start_erl and -boot */
  228. static char** config_scripts = NULL; /* used by option -start_erl and -config */
  229. static int config_script_cnt = 0;
  230. static int got_start_erl = 0;
  231. static HANDLE this_module_handle;
  232. static int run_werl;
  233. static WCHAR *utf8_to_utf16(unsigned char *bytes);
  234. static char *utf16_to_utf8(WCHAR *wstr);
  235. static WCHAR *latin1_to_utf16(char *str);
  236. #endif
  237. /*
  238. * Parameters to be fetched from the environment (Unix)
  239. * or the ini file (Win32).
  240. */
  241. static char* bindir; /* Location of executables. */
  242. static char* rootdir; /* Root location of Erlang installation. */
  243. static char* emu; /* Emulator to run. */
  244. static char* progname; /* Name of this program. */
  245. static char* home; /* Path of user's home directory, if any. */
  246. static void
  247. set_env(char *key, char *value)
  248. {
  249. #ifdef __WIN32__
  250. WCHAR *wkey = latin1_to_utf16(key);
  251. WCHAR *wvalue = utf8_to_utf16(value);
  252. if (!SetEnvironmentVariableW(wkey, wvalue))
  253. error("SetEnvironmentVariable(\"%s\", \"%s\") failed!", key, value);
  254. efree(wkey);
  255. efree(wvalue);
  256. #else
  257. size_t size = strlen(key) + 1 + strlen(value) + 1;
  258. char *str = emalloc(size);
  259. sprintf(str, "%s=%s", key, value);
  260. if (putenv(str) != 0)
  261. error("putenv(\"%s\") failed!", str);
  262. #ifdef HAVE_COPYING_PUTENV
  263. efree(str);
  264. #endif
  265. #endif
  266. }
  267. static char *
  268. get_env(char *key)
  269. {
  270. #ifdef __WIN32__
  271. DWORD size = 32;
  272. WCHAR *value = NULL;
  273. WCHAR *wkey = latin1_to_utf16(key);
  274. char *res;
  275. while (1) {
  276. DWORD nsz;
  277. if (value)
  278. efree(value);
  279. value = emalloc(size*sizeof(WCHAR));
  280. SetLastError(0);
  281. nsz = GetEnvironmentVariableW(wkey, value, size);
  282. if (nsz == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
  283. efree(value);
  284. efree(wkey);
  285. return NULL;
  286. }
  287. if (nsz <= size) {
  288. efree(wkey);
  289. res = utf16_to_utf8(value);
  290. efree(value);
  291. return res;
  292. }
  293. size = nsz;
  294. }
  295. #else
  296. return getenv(key);
  297. #endif
  298. }
  299. static void
  300. free_env_val(char *value)
  301. {
  302. #ifdef __WIN32__
  303. if (value)
  304. free(value);
  305. #endif
  306. }
  307. /*
  308. * Add the type and architecture suffix to the program name if needed.
  309. * On Windows, we insert it just before ".DLL".
  310. */
  311. static char*
  312. add_extra_suffixes(char *prog)
  313. {
  314. char *res;
  315. char *p;
  316. int len;
  317. #ifdef __WIN32__
  318. char *dll_p;
  319. int dll = 0;
  320. #endif
  321. len = strlen(prog);
  322. /* Allocate enough extra space for suffixes */
  323. p = emalloc(len + 100);
  324. res = p;
  325. p = write_str(p, prog);
  326. #ifdef __WIN32__
  327. dll_p = res + len - 4;
  328. if (dll_p >= res) {
  329. if (dll_p[0] == '.' &&
  330. (dll_p[1] == 'd' || dll_p[1] == 'D') &&
  331. (dll_p[2] == 'l' || dll_p[2] == 'L') &&
  332. (dll_p[3] == 'l' || dll_p[3] == 'L')) {
  333. p = dll_p;
  334. dll = 1;
  335. }
  336. }
  337. #endif
  338. if (emu_type && strcmp("opt",emu_type) != 0) {
  339. p = write_str(p, ".");
  340. p = write_str(p, emu_type);
  341. }
  342. p = write_str(p, ".");
  343. p = write_str(p, emu_flavor);
  344. #ifdef __WIN32__
  345. if (dll) {
  346. p = write_str(p, DLL_EXT);
  347. }
  348. #endif
  349. return res;
  350. }
  351. #ifdef __WIN32__
  352. static void add_boot_config(void)
  353. {
  354. int i;
  355. if (boot_script)
  356. add_args("-boot", boot_script, NULL);
  357. for (i = 0; i < config_script_cnt; i++) {
  358. add_args("-config", config_scripts[i], NULL);
  359. }
  360. }
  361. # define ADD_BOOT_CONFIG add_boot_config()
  362. #else
  363. # define ADD_BOOT_CONFIG
  364. #endif
  365. #define NEXT_ARG_CHECK_NAMED(Option) \
  366. do { \
  367. if (i+1 >= argc || strncmp(argv[i+1], "--", 3) == 0) \
  368. usage(Option); \
  369. } while(0)
  370. #define NEXT_ARG_CHECK() NEXT_ARG_CHECK_NAMED(argv[i])
  371. #ifdef __WIN32__
  372. __declspec(dllexport) int win_erlexec(int argc, char **argv, HANDLE module, int windowed)
  373. #else
  374. int main(int argc, char **argv)
  375. #endif
  376. {
  377. int haltAfterwards = 0; /* If true, put '-s erlang halt' at the end
  378. * of the arguments. */
  379. int isdistributed = 0;
  380. int no_epmd = 0;
  381. int proto_dist = 0;
  382. int start_epmd = 1; /* Whether epmd should be started */
  383. int i;
  384. char* s;
  385. char *epmd_prog = NULL;
  386. int process_args = 1;
  387. int print_args_exit = 0;
  388. int print_qouted_cmd_exit = 0;
  389. char* emu_name;
  390. #ifdef __WIN32__
  391. this_module_handle = module;
  392. run_werl = windowed;
  393. /* if we started this erl just to get a detached emulator,
  394. * the arguments are already prepared for beam, so we skip
  395. * directly to start_emulator */
  396. s = get_env("ERL_CONSOLE_MODE");
  397. if (s != NULL && strcmp(s, "detached")==0) {
  398. free_env_val(s);
  399. s = get_env("ERL_EMULATOR_DLL");
  400. if (s != NULL) {
  401. argv[0] = strsave(s);
  402. } else {
  403. argv[0] = strsave(EMULATOR_EXECUTABLE);
  404. }
  405. ensure_EargsSz(argc + 1);
  406. memcpy((void *) Eargsp, (void *) argv, argc * sizeof(char *));
  407. Eargsp[argc] = NULL;
  408. emu = argv[0];
  409. start_emulator_program = strsave(argv[0]);
  410. goto skip_arg_massage;
  411. }
  412. free_env_val(s);
  413. #else
  414. int reset_cerl_detached = 0;
  415. s = get_env("CERL_DETACHED_PROG");
  416. if (s && strcmp(s, "") != 0) {
  417. emu = s;
  418. start_detached = 1;
  419. reset_cerl_detached = 1;
  420. ensure_EargsSz(argc + 1);
  421. memcpy((void *) Eargsp, (void *) argv, argc * sizeof(char *));
  422. Eargsp[argc] = emu;
  423. Eargsp[argc] = NULL;
  424. goto skip_arg_massage;
  425. }
  426. free_env_val(s);
  427. #endif
  428. initial_argv_massage(&argc, &argv); /* Merge with env; expand -args_file */
  429. i = 1;
  430. #ifdef __WIN32__
  431. /* Not used? /rickard */
  432. if ((argc > 2) && (strcmp(argv[i], "-regkey") == 0)) {
  433. key_val_name = strsave(argv[i+1]);
  434. i = 3;
  435. }
  436. #endif
  437. get_parameters(argc, argv);
  438. /*
  439. * Construct the path of the executable.
  440. */
  441. #if defined(__WIN32__) && defined(WIN32_ALWAYS_DEBUG)
  442. emu_type = "debug";
  443. #endif
  444. /* We need to do this before the ordinary processing. */
  445. while (i < argc) {
  446. if (argv[i][0] == '-') {
  447. if (strcmp(argv[i], "-smp") == 0) {
  448. if (i + 1 >= argc)
  449. goto smp;
  450. if (strcmp(argv[i+1], "auto") == 0) {
  451. i++;
  452. } else if (strcmp(argv[i+1], "enable") == 0) {
  453. i++;
  454. smp_enable:
  455. ;
  456. } else if (strcmp(argv[i+1], "disable") == 0) {
  457. i++;
  458. smp_disable:
  459. usage_notsup("-smp disable", " Use \"+S 1\" instead.");
  460. } else {
  461. smp:
  462. ;
  463. }
  464. } else if (strcmp(argv[i], "-smpenable") == 0) {
  465. goto smp_enable;
  466. } else if (strcmp(argv[i], "-smpauto") == 0) {
  467. ;
  468. } else if (strcmp(argv[i], "-smpdisable") == 0) {
  469. goto smp_disable;
  470. } else if (strcmp(argv[i], "-extra") == 0) {
  471. break;
  472. } else if (strcmp(argv[i], "-emu_type") == 0) {
  473. NEXT_ARG_CHECK();
  474. emu_type = argv[i+1];
  475. i++;
  476. } else if (strcmp(argv[i], "-emu_flavor") == 0) {
  477. NEXT_ARG_CHECK();
  478. emu_flavor = argv[i+1];
  479. i++;
  480. }
  481. }
  482. i++;
  483. }
  484. emu = add_extra_suffixes(emu);
  485. emu_name = strsave(emu);
  486. erts_snprintf(tmpStr, sizeof(tmpStr), "%s" DIRSEP "%s" BINARY_EXT, bindir, emu);
  487. emu = strsave(tmpStr);
  488. s = get_env("ESCRIPT_NAME");
  489. if(s) {
  490. add_Eargs(s); /* argv[0] = scriptname*/
  491. } else {
  492. add_Eargs(emu); /* argv[0] = erl or cerl */
  493. }
  494. /* Add the bindir to the front of the PATH, and remove all subsequent
  495. * occurrences to avoid ballooning it on repeated up/downgrades. */
  496. s = get_env("PATH");
  497. if (s == NULL) {
  498. erts_snprintf(tmpStr, sizeof(tmpStr),
  499. "%s" PATHSEP "%s" DIRSEP "bin" PATHSEP, bindir, rootdir);
  500. } else if (strstr(s, rootdir) == NULL) {
  501. erts_snprintf(tmpStr, sizeof(tmpStr),
  502. "%s" PATHSEP "%s" DIRSEP "bin" PATHSEP "%s", bindir, rootdir, s);
  503. } else {
  504. const char *bindir_slug, *bindir_slug_index;
  505. int bindir_slug_length;
  506. const char *in_index;
  507. char *out_index;
  508. erts_snprintf(tmpStr, sizeof(tmpStr), "%s" PATHSEP, bindir);
  509. bindir_slug = strsave(tmpStr);
  510. bindir_slug_length = strlen(bindir_slug);
  511. out_index = &tmpStr[bindir_slug_length];
  512. in_index = s;
  513. while ((bindir_slug_index = strstr(in_index, bindir_slug))) {
  514. int block_length = (bindir_slug_index - in_index);
  515. memcpy(out_index, in_index, block_length);
  516. in_index = bindir_slug_index + bindir_slug_length;
  517. out_index += block_length;
  518. }
  519. efree((void*)bindir_slug);
  520. strcpy(out_index, in_index);
  521. }
  522. free_env_val(s);
  523. set_env("PATH", tmpStr);
  524. i = 1;
  525. get_home();
  526. /* Add the home parameter when available. This is optional to support
  527. systems that don't have the notion of a home directory and setups
  528. that don't have the HOME environment variable set (ERL-476). */
  529. if (home != NULL) {
  530. add_args("-home", home, NULL);
  531. }
  532. add_epmd_port();
  533. add_arg("--");
  534. while (i < argc) {
  535. if (!process_args) { /* Copy arguments after '-extra' */
  536. add_arg(argv[i]);
  537. i++;
  538. } else {
  539. switch (argv[i][0]) {
  540. case '-':
  541. switch (argv[i][1]) {
  542. #ifdef __WIN32__
  543. case 'b':
  544. if (strcmp(argv[i], "-boot") == 0) {
  545. if (boot_script)
  546. error("Conflicting -boot options");
  547. if (got_start_erl)
  548. error("Conflicting -start_erl and -boot options");
  549. NEXT_ARG_CHECK();
  550. boot_script = strsave(argv[i+1]);
  551. i++;
  552. }
  553. else {
  554. add_arg(argv[i]);
  555. }
  556. break;
  557. #endif
  558. case 'c':
  559. if (strcmp(argv[i], "-compile") == 0) {
  560. /*
  561. * Note that the shell script erl.exec does a recursive call
  562. * on itself here. We'll avoid doing that.
  563. */
  564. add_args("-noshell", "-noinput", "-s", "c", "lc_batch",
  565. NULL);
  566. add_Eargs("-B");
  567. haltAfterwards = 0;
  568. }
  569. #ifdef __WIN32__
  570. else if (strcmp(argv[i], "-config") == 0){
  571. if (got_start_erl)
  572. error("Conflicting -start_erl and -config options");
  573. NEXT_ARG_CHECK();
  574. do {
  575. config_script_cnt++;
  576. config_scripts = erealloc(config_scripts,
  577. config_script_cnt * sizeof(char*));
  578. config_scripts[config_script_cnt-1] = strsave(argv[i+1]);
  579. i++;
  580. } while ((i+1) < argc && argv[i+1][0] != '-' && argv[i+1][0] != '+');
  581. }
  582. #endif
  583. else if (strcmp(argv[i], "-configfd") == 0) {
  584. NEXT_ARG_CHECK();
  585. if ( strcmp(argv[i+1], "0") != 0 ) {
  586. add_arg(argv[i]);
  587. } else {
  588. add_args("-noshell", "-noinput", NULL);
  589. add_arg(argv[i]);
  590. }
  591. }
  592. else {
  593. add_arg(argv[i]);
  594. }
  595. break;
  596. case 'd':
  597. if (strcmp(argv[i], "-detached") != 0) {
  598. add_arg(argv[i]);
  599. } else {
  600. start_detached = 1;
  601. add_args("-noshell", "-noinput", NULL);
  602. }
  603. break;
  604. case 'e':
  605. if (strcmp(argv[i], "-extra") == 0) {
  606. process_args = 0;
  607. ADD_BOOT_CONFIG;
  608. add_arg(argv[i]);
  609. } else if (strcmp(argv[i], "-emu_args") == 0) { /* -emu_args */
  610. verbose = 1;
  611. } else if (strcmp(argv[i], "-emu_args_exit") == 0) {
  612. print_args_exit = 1;
  613. } else if (strcmp(argv[i], "-emu_name_exit") == 0) {
  614. printf("%s\n", emu_name);
  615. exit(0);
  616. } else if (strcmp(argv[i], "-emu_qouted_cmd_exit") == 0) {
  617. print_qouted_cmd_exit = 1;
  618. } else if (strcmp(argv[i], "-env") == 0) { /* -env VARNAME VARVALUE */
  619. NEXT_ARG_CHECK();
  620. i += 1;
  621. NEXT_ARG_CHECK_NAMED("-env");
  622. set_env(argv[i], argv[i+1]);
  623. i += 1;
  624. } else if (strcmp(argv[i], "-epmd") == 0) {
  625. NEXT_ARG_CHECK();
  626. epmd_prog = argv[i+1];
  627. ++i;
  628. } else {
  629. add_arg(argv[i]);
  630. }
  631. break;
  632. case 'k':
  633. if (strcmp(argv[i], "-keep_window") == 0) {
  634. keep_window = 1;
  635. } else
  636. add_arg(argv[i]);
  637. break;
  638. case 'm':
  639. /*
  640. * Note that the shell script erl.exec does a recursive call
  641. * on itself here. We'll avoid doing that.
  642. */
  643. if (strcmp(argv[i], "-make") == 0) {
  644. add_args("-noshell", "-noinput", "-s", "make", "all_or_nothing", NULL);
  645. add_Eargs("-B");
  646. haltAfterwards = 1;
  647. i = argc; /* Skip rest of command line */
  648. } else if (strcmp(argv[i], "-man") == 0) {
  649. #if defined(__WIN32__)
  650. error("-man not supported on Windows");
  651. #else
  652. argv[i] = "man";
  653. erts_snprintf(tmpStr, sizeof(tmpStr), "%s/man", rootdir);
  654. set_env("MANPATH", tmpStr);
  655. execvp("man", argv+i);
  656. error("Could not execute the 'man' command.");
  657. #endif
  658. } else
  659. add_arg(argv[i]);
  660. break;
  661. case 'n':
  662. if (strcmp(argv[i], "-name") == 0) { /* -name NAME */
  663. NEXT_ARG_CHECK();
  664. /*
  665. * Note: Cannot use add_args() here, due to non-defined
  666. * evaluation order.
  667. */
  668. add_arg(argv[i]);
  669. add_arg(argv[i+1]);
  670. isdistributed = 1;
  671. i++;
  672. } else if (strcmp(argv[i], "-noinput") == 0) {
  673. add_args("-noshell", "-noinput", NULL);
  674. } else if (strcmp(argv[i], "-nohup") == 0) {
  675. add_arg("-nohup");
  676. nohup = 1;
  677. } else if (strcmp(argv[i], "-no_epmd") == 0) {
  678. add_arg("-no_epmd");
  679. no_epmd = 1;
  680. start_epmd = 0;
  681. } else {
  682. add_arg(argv[i]);
  683. }
  684. break;
  685. case 'p':
  686. if (strcmp(argv[i], "-proto_dist") == 0) {
  687. NEXT_ARG_CHECK();
  688. add_arg(argv[i]);
  689. add_arg(argv[i+1]);
  690. proto_dist = 1;
  691. i++;
  692. } else {
  693. add_arg(argv[i]);
  694. }
  695. break;
  696. case 's': /* -sname NAME */
  697. if (strcmp(argv[i], "-sname") == 0) {
  698. NEXT_ARG_CHECK();
  699. add_arg(argv[i]);
  700. add_arg(argv[i+1]);
  701. isdistributed = 1;
  702. i++;
  703. }
  704. #ifdef __WIN32__
  705. else if (strcmp(argv[i], "-service_event") == 0) {
  706. NEXT_ARG_CHECK();
  707. add_arg(argv[i]);
  708. add_arg(argv[i+1]);
  709. i++;
  710. }
  711. else if (strcmp(argv[i], "-start_erl") == 0) {
  712. if (i+1 < argc && argv[i+1][0] != '-') {
  713. get_start_erl_data(argv[i+1]);
  714. i++;
  715. } else
  716. get_start_erl_data((char *) NULL);
  717. }
  718. #endif
  719. else if (strcmp(argv[i], "-start_epmd") == 0) {
  720. NEXT_ARG_CHECK();
  721. if (strcmp(argv[i+1], "true") == 0) {
  722. /* The default */
  723. start_epmd = 1;
  724. }
  725. else if (strcmp(argv[i+1], "false") == 0) {
  726. start_epmd = 0;
  727. }
  728. else
  729. usage_format("Expected boolean argument for \'-start_epmd\'.\n");
  730. add_arg(argv[i]);
  731. add_arg(argv[i+1]);
  732. i++;
  733. }
  734. else
  735. add_arg(argv[i]);
  736. break;
  737. case 'v': /* -version */
  738. if (strcmp(argv[i], "-version") == 0) {
  739. add_Eargs("-V");
  740. } else {
  741. add_arg(argv[i]);
  742. }
  743. break;
  744. default:
  745. add_arg(argv[i]);
  746. break;
  747. } /* switch(argv[i][1] */
  748. break;
  749. case '+':
  750. switch (argv[i][1]) {
  751. case 'a':
  752. case 'A':
  753. case 'C':
  754. case 'e':
  755. case 'i':
  756. case 'n':
  757. case 'P':
  758. case 'Q':
  759. case 't':
  760. case 'T':
  761. case 'R':
  762. case 'W':
  763. case 'K':
  764. if (argv[i][2] != '\0')
  765. goto the_default;
  766. NEXT_ARG_CHECK();
  767. argv[i][0] = '-';
  768. add_Eargs(argv[i]);
  769. add_Eargs(argv[i+1]);
  770. i++;
  771. break;
  772. case 'I':
  773. if (argv[i][2] == 'O' && (argv[i][3] == 't' || argv[i][3] == 'p')) {
  774. if (argv[i][4] != '\0')
  775. goto the_default;
  776. NEXT_ARG_CHECK();
  777. argv[i][0] = '-';
  778. add_Eargs(argv[i]);
  779. add_Eargs(argv[i+1]);
  780. i++;
  781. break;
  782. }
  783. if (argv[i][2] == 'O' && argv[i][3] == 'P' &&
  784. (argv[i][4] == 't' || argv[i][4] == 'p')) {
  785. if (argv[i][5] != '\0')
  786. goto the_default;
  787. NEXT_ARG_CHECK();
  788. argv[i][0] = '-';
  789. add_Eargs(argv[i]);
  790. add_Eargs(argv[i+1]);
  791. i++;
  792. break;
  793. }
  794. usage(argv[i]);
  795. break;
  796. case 'J':
  797. NEXT_ARG_CHECK();
  798. argv[i][0] = '-';
  799. add_Eargs(argv[i]);
  800. add_Eargs(argv[i+1]);
  801. i++;
  802. break;
  803. case 'S':
  804. if (argv[i][2] == 'P') {
  805. if (argv[i][3] != '\0')
  806. goto the_default;
  807. }
  808. else if (argv[i][2] == 'D') {
  809. char* type = argv[i]+3;
  810. if (strncmp(type, "cpu", 3) != 0 &&
  811. strncmp(type, "Pcpu", 4) != 0 &&
  812. strncmp(type, "io", 2) != 0)
  813. usage(argv[i]);
  814. if ((argv[i][3] == 'c' && argv[i][6] != '\0') ||
  815. (argv[i][3] == 'P' && argv[i][7] != '\0') ||
  816. (argv[i][3] == 'i' && argv[i][5] != '\0'))
  817. goto the_default;
  818. }
  819. else if (argv[i][2] != '\0')
  820. goto the_default;
  821. NEXT_ARG_CHECK();
  822. argv[i][0] = '-';
  823. add_Eargs(argv[i]);
  824. add_Eargs(argv[i+1]);
  825. i++;
  826. break;
  827. case 'B':
  828. argv[i][0] = '-';
  829. if (argv[i][2] != '\0') {
  830. if ((argv[i][2] != 'i') &&
  831. (argv[i][2] != 'c') &&
  832. (argv[i][2] != 'd')) {
  833. usage(argv[i]);
  834. } else {
  835. add_Eargs(argv[i]);
  836. break;
  837. }
  838. }
  839. if (i+1 < argc) {
  840. if (argv[i+1][1] == '\0') {
  841. if ((argv[i+1][0] == 'i') ||
  842. (argv[i+1][0] == 'c') ||
  843. (argv[i+1][0] == 'd')
  844. ) {
  845. add_Eargs(argv[i]);
  846. add_Eargs(argv[i+1]);
  847. i++;
  848. break;
  849. }
  850. }
  851. }
  852. add_Eargs(argv[i]);
  853. break;
  854. case 'c':
  855. argv[i][0] = '-';
  856. if (argv[i][2] == '\0' && i+1 < argc) {
  857. if (strcmp(argv[i+1], "true") == 0
  858. || strcmp(argv[i+1], "false") == 0) {
  859. add_Eargs(argv[i]);
  860. add_Eargs(argv[i+1]);
  861. i++;
  862. break;
  863. }
  864. }
  865. add_Eargs(argv[i]);
  866. break;
  867. case 'M': {
  868. int x;
  869. for (x = 0; plusM_au_allocs[x]; x++)
  870. if (plusM_au_allocs[x] == argv[i][2])
  871. break;
  872. if ((plusM_au_allocs[x]
  873. && is_one_of_strings(&argv[i][3],
  874. plusM_au_alloc_switches))
  875. || is_one_of_strings(&argv[i][2],
  876. plusM_other_switches)) {
  877. NEXT_ARG_CHECK();
  878. argv[i][0] = '-';
  879. add_Eargs(argv[i]);
  880. add_Eargs(argv[i+1]);
  881. i++;
  882. }
  883. else
  884. goto the_default;
  885. break;
  886. }
  887. case 'h':
  888. if (!is_one_of_strings(&argv[i][2], plush_val_switches)) {
  889. goto the_default;
  890. } else {
  891. NEXT_ARG_CHECK();
  892. argv[i][0] = '-';
  893. add_Eargs(argv[i]);
  894. add_Eargs(argv[i+1]);
  895. i++;
  896. }
  897. break;
  898. case 'r':
  899. if (!is_one_of_strings(&argv[i][2],
  900. plusr_val_switches))
  901. goto the_default;
  902. else {
  903. NEXT_ARG_CHECK();
  904. argv[i][0] = '-';
  905. add_Eargs(argv[i]);
  906. add_Eargs(argv[i+1]);
  907. i++;
  908. }
  909. break;
  910. case 's':
  911. if (!is_one_of_strings(&argv[i][2],
  912. pluss_val_switches))
  913. goto the_default;
  914. else {
  915. NEXT_ARG_CHECK();
  916. argv[i][0] = '-';
  917. add_Eargs(argv[i]);
  918. add_Eargs(argv[i+1]);
  919. i++;
  920. }
  921. break;
  922. case 'p':
  923. if (argv[i][2] != 'c' || argv[i][3] != '\0')
  924. goto the_default;
  925. NEXT_ARG_CHECK();
  926. argv[i][0] = '-';
  927. add_Eargs(argv[i]);
  928. add_Eargs(argv[i+1]);
  929. i++;
  930. break;
  931. case 'z':
  932. if (!is_one_of_strings(&argv[i][2], plusz_val_switches)) {
  933. goto the_default;
  934. } else {
  935. NEXT_ARG_CHECK();
  936. argv[i][0] = '-';
  937. add_Eargs(argv[i]);
  938. add_Eargs(argv[i+1]);
  939. i++;
  940. }
  941. break;
  942. default:
  943. the_default:
  944. argv[i][0] = '-'; /* Change +option to -option. */
  945. add_Eargs(argv[i]);
  946. }
  947. break;
  948. default:
  949. add_arg(argv[i]);
  950. } /* switch(argv[i][0] */
  951. i++;
  952. }
  953. }
  954. efree(emu_name);
  955. if (process_args) {
  956. ADD_BOOT_CONFIG;
  957. }
  958. #undef ADD_BOOT_CONFIG
  959. /* The default distribution protocol (inet_tcp) relies on epmd,
  960. so the -no_epmd option can only work when using an alternative
  961. protocol for Erlang distribution. */
  962. if (no_epmd && !proto_dist) {
  963. error("Missing -proto_dist option, expected when using -no_epmd.");
  964. }
  965. /* Doesn't conflict with -extra, since -make skips all the rest of
  966. the arguments. */
  967. if (haltAfterwards) {
  968. add_args("-s", "erlang", "halt", NULL);
  969. }
  970. if (isdistributed && start_epmd)
  971. start_epmd_daemon(epmd_prog);
  972. #if (! defined(__WIN32__)) && defined(DEBUG)
  973. if (start_detached && get_env("ERL_CONSOLE_MODE")) {
  974. /* Start the emulator within an xterm.
  975. * Move up all arguments and insert
  976. * "xterm -e " first.
  977. * The path must be searched for this
  978. * to work, i.e execvp() must be used.
  979. */
  980. ensure_EargsSz(EargsCnt+2);
  981. for (i = EargsCnt; i > 0; i--)
  982. Eargsp[i+1] = Eargsp[i-1]; /* Two args to insert */
  983. EargsCnt += 2; /* Two args to insert */
  984. Eargsp[0] = emu = "xterm";
  985. Eargsp[1] = "-e";
  986. }
  987. #endif
  988. add_Eargs("--");
  989. add_Eargs("-root");
  990. add_Eargs(rootdir);
  991. add_Eargs("-progname");
  992. add_Eargs(progname);
  993. add_Eargs("--");
  994. ensure_EargsSz(EargsCnt + argsCnt + 1);
  995. for (i = 0; i < argsCnt; i++)
  996. Eargsp[EargsCnt++] = argsp[i];
  997. Eargsp[EargsCnt] = NULL;
  998. if (print_qouted_cmd_exit) {
  999. printf("\"%s\" ", emu);
  1000. for (i = 1; i < EargsCnt; i++)
  1001. printf("\"%s\" ", Eargsp[i]);
  1002. printf("\n");
  1003. exit(0);
  1004. }
  1005. if (print_args_exit) {
  1006. for (i = 1; i < EargsCnt; i++)
  1007. printf("%s\n", Eargsp[i]);
  1008. exit(0);
  1009. }
  1010. if (verbose) {
  1011. printf("Executing: %s", emu);
  1012. for (i = 0; i < EargsCnt; i++)
  1013. printf(" %s", Eargsp[i]);
  1014. printf("\n\n");
  1015. }
  1016. #ifdef __WIN32__
  1017. if (EargsSz != EargsCnt + 1)
  1018. Eargsp = (char **) erealloc((void *) Eargsp, (EargsCnt + 1) *
  1019. sizeof(char *));
  1020. efree((void *) argsp);
  1021. skip_arg_massage:
  1022. /*DebugBreak();*/
  1023. if (run_werl) {
  1024. if (start_detached) {
  1025. char *p;
  1026. /* transform werl to erl */
  1027. p = start_emulator_program+strlen(start_emulator_program);
  1028. while (--p >= start_emulator_program && *p != '/' && *p != '\\' &&
  1029. *p != 'W' && *p != 'w')
  1030. ;
  1031. if (p >= start_emulator_program && (*p == 'W' || *p == 'w') &&
  1032. (p[1] == 'E' || p[1] == 'e') && (p[2] == 'R' || p[2] == 'r') &&
  1033. (p[3] == 'L' || p[3] == 'l')) {
  1034. memmove(p,p+1,strlen(p));
  1035. }
  1036. }
  1037. return start_win_emulator(emu, start_emulator_program, Eargsp, start_detached);
  1038. } else {
  1039. return start_emulator(emu, start_emulator_program, Eargsp, start_detached);
  1040. }
  1041. #else
  1042. skip_arg_massage:
  1043. if (start_detached) {
  1044. int status = fork();
  1045. if (status != 0) /* Parent */
  1046. return 0;
  1047. if (reset_cerl_detached)
  1048. putenv("CERL_DETACHED_PROG=");
  1049. /* Detach from controlling terminal */
  1050. #ifdef HAVE_SETSID
  1051. setsid();
  1052. #elif defined(TIOCNOTTY)
  1053. {
  1054. int fd = open("/dev/tty", O_RDWR);
  1055. if (fd >= 0) {
  1056. ioctl(fd, TIOCNOTTY, NULL);
  1057. close(fd);
  1058. }
  1059. }
  1060. #endif
  1061. status = fork();
  1062. if (status != 0) /* Parent */
  1063. return 0;
  1064. /*
  1065. * Grandchild.
  1066. */
  1067. close(0);
  1068. open("/dev/null", O_RDONLY);
  1069. close(1);
  1070. open("/dev/null", O_WRONLY);
  1071. close(2);
  1072. open("/dev/null", O_WRONLY);
  1073. #ifdef DEBUG
  1074. execvp(emu, Eargsp); /* "xterm ..." needs to search the path */
  1075. #endif
  1076. }
  1077. #ifdef DEBUG
  1078. else
  1079. #endif
  1080. {
  1081. execv(emu, Eargsp);
  1082. }
  1083. if (errno == ENOENT) {
  1084. if (strcmp(emu_flavor,DEFAULT_SUFFIX) || emu_type) {
  1085. /* The executable did not exist and a flavor/type flags was given.
  1086. * We collect the possible combinations and print that in the error
  1087. * in order to help the user.
  1088. */
  1089. char buff[255], *currbuff = buff;
  1090. DIR *dp = opendir(bindir);
  1091. if (dp) {
  1092. struct dirent *ep;
  1093. while ((ep = readdir(dp)) != NULL) {
  1094. if (strncmp("beam",ep->d_name,4) == 0) {
  1095. char *type = strstr(ep->d_name,".") + 1;
  1096. char *flavor = strstr(type,".");
  1097. currbuff += sprintf(currbuff,"\n ");
  1098. if (flavor == NULL) {
  1099. flavor = type;
  1100. } else {
  1101. char* emu_type = strndup(type,flavor - type);
  1102. currbuff += sprintf(currbuff,"-emu_type %s ", emu_type);
  1103. free(emu_type);
  1104. flavor++;
  1105. }
  1106. currbuff += sprintf(currbuff,"-emu_flavor %s", flavor);
  1107. }
  1108. }
  1109. closedir(dp);
  1110. }
  1111. error("Invalid emulator type or flavor. Available combinations are: %s\n",buff);
  1112. } else {
  1113. error("The emulator \'%s\' does not exist.");
  1114. }
  1115. } else {
  1116. error("Error %d executing \'%s\'.", errno, emu);
  1117. }
  1118. return 1;
  1119. #endif
  1120. }
  1121. static void
  1122. usage_aux(void)
  1123. {
  1124. fprintf(stderr,
  1125. "Usage: erl [-version] [-sname NAME | -name NAME] "
  1126. "[-noshell] [-noinput] [-env VAR VALUE] [-compile file ...] "
  1127. #ifdef __WIN32__
  1128. "[-start_erl [datafile]] "
  1129. #endif
  1130. "[-make] [-man [manopts] MANPAGE] [-x] [-emu_args] [-start_epmd BOOLEAN] "
  1131. "[-emu_type TYPE] [-emu_flavor FLAVOR] "
  1132. "[-args_file FILENAME] [+A THREADS] [+a SIZE] [+B[c|d|i]] [+c [BOOLEAN]] "
  1133. "[+C MODE] [+dcg DECENTRALIZED_COUNTER_GROUPS_LIMIT] [+h HEAP_SIZE_OPTION] "
  1134. "[+J[Pperf] JIT_OPTION] "
  1135. "[+M<SUBSWITCH> <ARGUMENT>] [+P MAX_PROCS] [+Q MAX_PORTS] "
  1136. "[+R COMPAT_REL] "
  1137. "[+r] [+rg READER_GROUPS_LIMIT] [+s<SUBSWITCH> SCHEDULER_OPTION] "
  1138. "[+S NO_SCHEDULERS:NO_SCHEDULERS_ONLINE] "
  1139. "[+SP PERCENTAGE_SCHEDULERS:PERCENTAGE_SCHEDULERS_ONLINE] "
  1140. "[+T LEVEL] [+V] [+v] "
  1141. "[+W<i|w|e>] [+z MISC_OPTION] [args ...]\n");
  1142. exit(1);
  1143. }
  1144. void
  1145. usage(const char *switchname)
  1146. {
  1147. fprintf(stderr, "Missing argument(s) for \'%s\'.\n", switchname);
  1148. usage_aux();
  1149. }
  1150. static void
  1151. usage_notsup(const char *switchname, const char *alt)
  1152. {
  1153. fprintf(stderr, "Argument \'%s\' not supported.%s\n", switchname, alt);
  1154. usage_aux();
  1155. }
  1156. static void
  1157. usage_format(char *format, ...)
  1158. {
  1159. va_list args;
  1160. va_start(args, format);
  1161. vfprintf(stderr, format, args);
  1162. va_end(args);
  1163. usage_aux();
  1164. }
  1165. void
  1166. start_epmd_daemon(char *epmd)
  1167. {
  1168. char epmd_cmd[MAXPATHLEN+100];
  1169. #ifdef __WIN32__
  1170. char* arg1 = NULL;
  1171. #endif
  1172. int result;
  1173. if (!epmd) {
  1174. epmd = epmd_cmd;
  1175. #ifdef __WIN32__
  1176. erts_snprintf(epmd_cmd, sizeof(epmd_cmd), "\"%s" DIRSEP "epmd\"", bindir);
  1177. arg1 = "-daemon";
  1178. #else
  1179. erts_snprintf(epmd_cmd, sizeof(epmd_cmd), "\"%s" DIRSEP "epmd\" -daemon", bindir);
  1180. #endif
  1181. }
  1182. #ifdef __WIN32__
  1183. if (arg1 != NULL) {
  1184. strcat(epmd, " ");
  1185. strcat(epmd, arg1);
  1186. }
  1187. {
  1188. wchar_t wcepmd[MAXPATHLEN+100];
  1189. STARTUPINFOW start;
  1190. PROCESS_INFORMATION pi;
  1191. memset(&start, 0, sizeof (start));
  1192. start.cb = sizeof (start);
  1193. MultiByteToWideChar(CP_UTF8, 0, epmd, -1, wcepmd, MAXPATHLEN+100);
  1194. if (!CreateProcessW(NULL, wcepmd, NULL, NULL, FALSE,
  1195. CREATE_DEFAULT_ERROR_MODE | DETACHED_PROCESS,
  1196. NULL, NULL, &start, &pi))
  1197. result = -1;
  1198. else
  1199. result = 0;
  1200. }
  1201. #else
  1202. result = system(epmd);
  1203. #endif
  1204. if (result == -1) {
  1205. fprintf(stderr, "Error spawning %s (error %d)\n", epmd_cmd,errno);
  1206. exit(1);
  1207. }
  1208. }
  1209. static void
  1210. add_arg(char *new_arg)
  1211. {
  1212. if (argsCnt >= argsSz)
  1213. argsp = (char **) erealloc((void *) argsp,
  1214. sizeof(char *) * (argsSz += 20));
  1215. argsp[argsCnt++] = QUOTE(new_arg);
  1216. }
  1217. static void
  1218. add_args(char *first_arg, ...)
  1219. {
  1220. va_list ap;
  1221. char* arg;
  1222. add_arg(first_arg);
  1223. va_start(ap, first_arg);
  1224. while ((arg = va_arg(ap, char *)) != NULL) {
  1225. add_arg(arg);
  1226. }
  1227. va_end(ap);
  1228. }
  1229. static void
  1230. ensure_EargsSz(int sz)
  1231. {
  1232. if (EargsSz < sz)
  1233. Eargsp = (char **) erealloc((void *) Eargsp,
  1234. sizeof(char *) * (EargsSz = sz));
  1235. ASSERT(Eargsp);
  1236. }
  1237. static void
  1238. add_Eargs(char *new_arg)
  1239. {
  1240. if (EargsCnt >= EargsSz)
  1241. Eargsp = (char **) erealloc((void *) Eargsp,
  1242. sizeof(char *) * (EargsSz += 20));
  1243. Eargsp[EargsCnt++] = QUOTE(new_arg);
  1244. }
  1245. #if !defined(__WIN32__)
  1246. void error(char* format, ...)
  1247. {
  1248. char sbuf[1024];
  1249. va_list ap;
  1250. va_start(ap, format);
  1251. erts_vsnprintf(sbuf, sizeof(sbuf), format, ap);
  1252. va_end(ap);
  1253. fprintf(stderr, "erlexec: %s\n", sbuf);
  1254. exit(1);
  1255. }
  1256. #endif
  1257. static void *
  1258. emalloc(size_t size)
  1259. {
  1260. void *p = malloc(size);
  1261. if (p == NULL)
  1262. error("Insufficient memory");
  1263. return p;
  1264. }
  1265. static void *
  1266. erealloc(void *p, size_t size)
  1267. {
  1268. void *res = realloc(p, size);
  1269. if (res == NULL)
  1270. error("Insufficient memory");
  1271. return res;
  1272. }
  1273. static void
  1274. efree(void *p)
  1275. {
  1276. free(p);
  1277. }
  1278. static int
  1279. is_one_of_strings(char *str, char *strs[])
  1280. {
  1281. int i, j;
  1282. for (i = 0; strs[i]; i++) {
  1283. for (j = 0; str[j] && strs[i][j] && str[j] == strs[i][j]; j++);
  1284. if (!str[j] && !strs[i][j])
  1285. return 1;
  1286. }
  1287. return 0;
  1288. }
  1289. static char *write_str(char *to, const char *from)
  1290. {
  1291. while (*from)
  1292. *(to++) = *(from++);
  1293. *to = '\0';
  1294. return to;
  1295. }
  1296. char*
  1297. strsave(char* string)
  1298. {
  1299. char* p = emalloc(strlen(string)+1);
  1300. strcpy(p, string);
  1301. return p;
  1302. }
  1303. #if defined(__WIN32__)
  1304. static void get_start_erl_data(char *file)
  1305. {
  1306. static char* a_config_script;
  1307. int fp;
  1308. char tmpbuffer[512];
  1309. char start_erl_data[512];
  1310. int bytesread;
  1311. char* env;
  1312. char* reldir;
  1313. char* otpstring;
  1314. char* tprogname;
  1315. if (boot_script)
  1316. error("Conflicting -start_erl and -boot options");
  1317. if (config_scripts)
  1318. error("Conflicting -start_erl and -config options");
  1319. env = get_env("RELDIR");
  1320. if (env)
  1321. reldir = strsave(env);
  1322. else {
  1323. erts_snprintf(tmpbuffer, sizeof(tmpbuffer), "%s/releases", rootdir);
  1324. reldir = strsave(tmpbuffer);
  1325. }
  1326. free_env_val(env);
  1327. if (file == NULL)
  1328. erts_snprintf(start_erl_data, sizeof(start_erl_data), "%s/start_erl.data", reldir);
  1329. else
  1330. erts_snprintf(start_erl_data, sizeof(start_erl_data), "%s", file);
  1331. fp = _open(start_erl_data, _O_RDONLY );
  1332. if( fp == -1 )
  1333. error( "open failed on %s",start_erl_data );
  1334. else {
  1335. if( ( bytesread = _read( fp, tmpbuffer, 512 ) ) <= 0 )
  1336. error( "Problem reading file %s", start_erl_data );
  1337. else {
  1338. tmpbuffer[bytesread]='\0';
  1339. if ((otpstring = strchr(tmpbuffer,' ')) != NULL) {
  1340. *otpstring = '\0';
  1341. otpstring++;
  1342. /*
  1343. * otpstring is the otpversion
  1344. * tmpbuffer is the emuversion
  1345. */
  1346. }
  1347. }
  1348. }
  1349. tprogname = otpstring;
  1350. while (*tprogname) {
  1351. if (*tprogname <= ' ') {
  1352. *tprogname='\0';
  1353. break;
  1354. }
  1355. tprogname++;
  1356. }
  1357. bindir = emalloc(512);
  1358. erts_snprintf(bindir,512,"%s/erts-%s/bin",rootdir,tmpbuffer);
  1359. /* BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin */
  1360. tprogname = progname;
  1361. progname = emalloc(strlen(tprogname) + 20);
  1362. erts_snprintf(progname,strlen(tprogname) + 20,"%s -start_erl",tprogname);
  1363. boot_script = emalloc(512);
  1364. a_config_script = emalloc(512);
  1365. erts_snprintf(boot_script, 512, "%s/%s/start", reldir, otpstring);
  1366. erts_snprintf(a_config_script, 512, "%s/%s/sys", reldir, otpstring);
  1367. config_scripts = &a_config_script;
  1368. config_script_cnt = 1;
  1369. got_start_erl = 1;
  1370. }
  1371. static wchar_t *replace_filename(wchar_t *path, wchar_t *new_base)
  1372. {
  1373. int plen = wcslen(path);
  1374. wchar_t *res = (wchar_t *) emalloc((plen+wcslen(new_base)+1)*sizeof(wchar_t));
  1375. wchar_t *p;
  1376. wcscpy(res,path);
  1377. for (p = res+plen-1 ;p >= res && *p != L'\\'; --p)
  1378. ;
  1379. *(p+1) =L'\0';
  1380. wcscat(res,new_base);
  1381. return res;
  1382. }
  1383. static char *path_massage(wchar_t *long_path)
  1384. {
  1385. char *p;
  1386. int len;
  1387. len = WideCharToMultiByte(CP_UTF8, 0, long_path, -1, NULL, 0, NULL, NULL);
  1388. p = emalloc(len*sizeof(char));
  1389. WideCharToMultiByte(CP_UTF8, 0, long_path, -1, p, len, NULL, NULL);
  1390. return p;
  1391. }
  1392. static char *do_lookup_in_section(InitSection *inis, char *name,
  1393. char *section, wchar_t *filename, int is_path)
  1394. {
  1395. char *p = lookup_init_entry(inis, name);
  1396. if (p == NULL) {
  1397. error("Could not find key %s in section %s of file %S",
  1398. name,section,filename);
  1399. }
  1400. return strsave(p);
  1401. }
  1402. // Setup bindir, rootdir and progname as utf8 buffers
  1403. static void get_parameters(int argc, char** argv)
  1404. {
  1405. wchar_t *p;
  1406. wchar_t buffer[MAX_PATH];
  1407. wchar_t *ini_filename;
  1408. HANDLE module = GetModuleHandle(NULL); /* This might look strange, but we want the erl.ini
  1409. that resides in the same dir as erl.exe, not
  1410. an erl.ini in our directory */
  1411. InitFile *inif;
  1412. InitSection *inis;
  1413. if (module == NULL) {
  1414. error("Cannot GetModuleHandle()");
  1415. }
  1416. if (GetModuleFileNameW(module,buffer,MAX_PATH) == 0) {
  1417. error("Could not GetModuleFileName");
  1418. }
  1419. ini_filename = replace_filename(buffer,INI_FILENAME);
  1420. if ((inif = load_init_file(ini_filename)) == NULL) {
  1421. wchar_t wbindir[MAX_PATH];
  1422. wchar_t wrootdir[MAX_PATH];
  1423. /* Assume that the path is absolute and that
  1424. it does not contain any symbolic link */
  1425. /* Determine bindir */
  1426. if (GetEnvironmentVariableW(L"ERLEXEC_DIR", buffer, MAX_PATH) == 0) {
  1427. wcscpy(buffer, ini_filename);
  1428. for (p = buffer+wcslen(buffer)-1; p >= buffer && *p != L'\\'; --p)
  1429. ;
  1430. *p = L'\0';
  1431. }
  1432. bindir = path_massage(buffer);
  1433. /* Determine rootdir */
  1434. for (p = buffer+wcslen(buffer)-1; p >= buffer && *p != L'\\'; --p)
  1435. ;
  1436. p--;
  1437. for (;p >= buffer && *p != L'\\'; --p)
  1438. ;
  1439. *p =L'\0';
  1440. rootdir = path_massage(buffer);
  1441. /* Hardcoded progname */
  1442. progname = strsave(DEFAULT_PROGNAME);
  1443. } else {
  1444. if ((inis = lookup_init_section(inif,INI_SECTION)) == NULL) {
  1445. error("Could not find section %s in init file %s",
  1446. INI_SECTION, ini_filename);
  1447. }
  1448. bindir = do_lookup_in_section(inis, "Bindir", INI_SECTION, ini_filename,1);
  1449. rootdir = do_lookup_in_section(inis, "Rootdir", INI_SECTION,
  1450. ini_filename,1);
  1451. progname = do_lookup_in_section(inis, "Progname", INI_SECTION,
  1452. ini_filename,0);
  1453. free_init_file(inif);
  1454. }
  1455. emu = EMULATOR_EXECUTABLE;
  1456. start_emulator_program = strsave(argv[0]);
  1457. free(ini_filename);
  1458. }
  1459. static void
  1460. get_home(void)
  1461. {
  1462. wchar_t *profile;
  1463. char* homedrive;
  1464. char* homepath;
  1465. homedrive = get_env("HOMEDRIVE");
  1466. homepath = get_env("HOMEPATH");
  1467. if (!homedrive || !homepath) {
  1468. if (SHGetKnownFolderPath(&FOLDERID_Profile, 0, NULL, &profile) == S_OK) {
  1469. home = utf16_to_utf8(profile);
  1470. /* CoTaskMemFree(profile); */
  1471. } else
  1472. error("HOMEDRIVE or HOMEPATH not set and getting USERPROFILE failed");
  1473. } else {
  1474. home = emalloc(strlen(homedrive)+strlen(homepath)+1);
  1475. strcpy(home, homedrive);
  1476. strcat(home, homepath);
  1477. }
  1478. free_env_val(homedrive);
  1479. free_env_val(homepath);
  1480. }
  1481. #else
  1482. static void
  1483. get_parameters(int argc, char** argv)
  1484. {
  1485. progname = get_env("PROGNAME");
  1486. if (!progname) {
  1487. progname = strsave(DEFAULT_PROGNAME);
  1488. }
  1489. emu = get_env("EMU");
  1490. if (!emu) {
  1491. emu = strsave(EMULATOR_EXECUTABLE);
  1492. }
  1493. bindir = get_env("BINDIR");
  1494. if (!bindir) {
  1495. /* Determine bindir from absolute path to executable */
  1496. char *p;
  1497. char buffer[PATH_MAX];
  1498. strncpy(buffer, argv[0], sizeof(buffer));
  1499. buffer[sizeof(buffer)-1] = '\0';
  1500. for (p = buffer+strlen(buffer)-1 ; p >= buffer && *p != '/'; --p)
  1501. ;
  1502. *p ='\0';
  1503. bindir = strsave(buffer);
  1504. }
  1505. rootdir = get_env("ROOTDIR");
  1506. if (!rootdir) {
  1507. /* Determine rootdir from absolute path to bindir */
  1508. char *p;
  1509. char buffer[PATH_MAX];
  1510. strncpy(buffer, bindir, sizeof(buffer));
  1511. buffer[sizeof(buffer)-1] = '\0';
  1512. for (p = buffer+strlen(buffer)-1; p >= buffer && *p != '/'; --p)
  1513. ;
  1514. p--;
  1515. for (; p >= buffer && *p != '/'; --p)
  1516. ;
  1517. *p ='\0';
  1518. rootdir = strsave(buffer);
  1519. }
  1520. if (!progname || !emu || !rootdir || !bindir) {
  1521. error("PROGNAME, EMU, ROOTDIR and BINDIR must be set");
  1522. }
  1523. }
  1524. static void
  1525. get_home(void)
  1526. {
  1527. home = get_env("HOME");
  1528. }
  1529. #endif
  1530. static void add_epmd_port(void)
  1531. {
  1532. char* port = get_env("ERL_EPMD_PORT");
  1533. if (port != NULL) {
  1534. add_args("-epmd_port", port, NULL);
  1535. }
  1536. }
  1537. static char **build_args_from_env(char *env_var)
  1538. {
  1539. char *value = get_env(env_var);
  1540. char **res = build_args_from_string(value, 0);
  1541. free_env_val(value);
  1542. return res;
  1543. }
  1544. static char **build_args_from_string(char *string, int allow_comments)
  1545. {
  1546. int argc = 0;
  1547. char **argv = NULL;
  1548. int alloced = 0;
  1549. char **cur_s = NULL; /* Initialized to avoid warning. */
  1550. int s_alloced = 0;
  1551. int s_pos = 0;
  1552. char *p = string;
  1553. enum {Start, Build, Build0, BuildSQuoted, BuildDQuoted, AcceptNext, BuildComment} state;
  1554. #define ENSURE() \
  1555. if (s_pos >= s_alloced) { \
  1556. if (!*cur_s) { \
  1557. *cur_s = emalloc(s_alloced = 20); \
  1558. } else { \
  1559. *cur_s = erealloc(*cur_s, s_alloced += 20); \
  1560. } \
  1561. }
  1562. if (!p)
  1563. return NULL;
  1564. argv = emalloc(sizeof(char *) * (alloced = 10));
  1565. state = Start;
  1566. for(;;) {
  1567. switch (state) {
  1568. case Start:
  1569. if (!*p)
  1570. goto done;
  1571. if (argc >= alloced - 2) { /* Make room for extra NULL and "--" */
  1572. argv = erealloc(argv, (alloced += 10) * sizeof(char *));
  1573. }
  1574. cur_s = argc + argv;
  1575. *cur_s = NULL;
  1576. s_pos = 0;
  1577. s_alloced = 0;
  1578. state = Build0;
  1579. break;
  1580. case Build0:
  1581. switch (*p) {
  1582. case '\n':
  1583. case '\f':
  1584. case '\r':
  1585. case '\t':
  1586. case '\v':
  1587. case ' ':
  1588. ++p;
  1589. break;
  1590. case '\0':
  1591. state = Start;
  1592. break;
  1593. case '#':
  1594. if (allow_comments) {
  1595. ++p;
  1596. state = BuildComment;
  1597. break;
  1598. }
  1599. /* fall-through */
  1600. default:
  1601. state = Build;
  1602. break;
  1603. }
  1604. break;
  1605. case Build:
  1606. switch (*p) {
  1607. case '#':
  1608. if (!allow_comments)
  1609. goto build_default;
  1610. /* fall-through */
  1611. case '\n':
  1612. case '\f':
  1613. case '\r':
  1614. case '\t':
  1615. case '\v':
  1616. case ' ':
  1617. case '\0':
  1618. ENSURE();
  1619. (*cur_s)[s_pos] = '\0';
  1620. ++argc;
  1621. state = Start;
  1622. break;
  1623. case '"':
  1624. ++p;
  1625. state = BuildDQuoted;
  1626. break;
  1627. case '\'':
  1628. ++p;
  1629. state = BuildSQuoted;
  1630. break;
  1631. case '\\':
  1632. ++p;
  1633. state = AcceptNext;
  1634. break;
  1635. default:
  1636. build_default:
  1637. ENSURE();
  1638. (*cur_s)[s_pos++] = *p++;
  1639. break;
  1640. }
  1641. break;
  1642. case BuildDQuoted:
  1643. switch (*p) {
  1644. case '"':
  1645. ++p;
  1646. /* fall through */
  1647. case '\0':
  1648. state = Build;
  1649. break;
  1650. default:
  1651. ENSURE();
  1652. (*cur_s)[s_pos++] = *p++;
  1653. break;
  1654. }
  1655. break;
  1656. case BuildSQuoted:
  1657. switch (*p) {
  1658. case '\'':
  1659. ++p;
  1660. /* fall through */
  1661. case '\0':
  1662. state = Build;
  1663. break;
  1664. default:
  1665. ENSURE();
  1666. (*cur_s)[s_pos++] = *p++;
  1667. break;
  1668. }
  1669. break;
  1670. case AcceptNext:
  1671. if (*p) {
  1672. ENSURE();
  1673. (*cur_s)[s_pos++] = *p++;
  1674. }
  1675. state = Build;
  1676. break;
  1677. case BuildComment:
  1678. if (*p == '\n' || *p == '\0') {
  1679. state = Build0;
  1680. } else {
  1681. p++;
  1682. }
  1683. break;
  1684. }
  1685. }
  1686. done:
  1687. if (!argc) {
  1688. efree(argv);
  1689. return NULL;
  1690. }
  1691. argv[argc++] = "--"; /* Add a -- separator in order
  1692. for flags from different environments
  1693. to not effect each other */
  1694. argv[argc++] = NULL; /* Sure to be large enough */
  1695. return argv;
  1696. #undef ENSURE
  1697. }
  1698. static const char *
  1699. errno_string(void)
  1700. {
  1701. const char *str = strerror(errno);
  1702. if (!str)
  1703. return "unknown error";
  1704. return str;
  1705. }
  1706. #define FILE_BUFF_SIZE 1024
  1707. static char **
  1708. read_args_file(char *filename)
  1709. {
  1710. FILE *file;
  1711. char buff[FILE_BUFF_SIZE+1];
  1712. size_t astr_sz = 0, sz;
  1713. char *astr = buff;
  1714. char **res;
  1715. do {
  1716. errno = 0;
  1717. file = fopen(filename, "r");
  1718. } while (!file && errno == EINTR);
  1719. if (!file) {
  1720. #ifdef __WIN32__
  1721. char cwd[MAX_PATH];
  1722. if (_getcwd(cwd, sizeof(cwd)) == NULL) {
  1723. #else
  1724. char cwd[PATH_MAX];
  1725. if (getcwd(cwd, sizeof(cwd)) == NULL) {
  1726. #endif
  1727. cwd[0] = '\0';
  1728. }
  1729. usage_format("Failed to open arguments file \"%s\" at \"%s\": %s\n",
  1730. filename,
  1731. cwd,
  1732. errno_string());
  1733. }
  1734. sz = fread(astr, 1, FILE_BUFF_SIZE, file);
  1735. while (!feof(file) && sz == FILE_BUFF_SIZE) {
  1736. if (astr == buff) {
  1737. astr = emalloc(FILE_BUFF_SIZE*2+1);
  1738. astr_sz = FILE_BUFF_SIZE;
  1739. memcpy(astr, buff, sizeof(buff));
  1740. } else {
  1741. astr_sz += FILE_BUFF_SIZE;
  1742. astr = erealloc(astr,astr_sz+FILE_BUFF_SIZE+1);
  1743. }
  1744. sz = fread(astr+astr_sz, 1, FILE_BUFF_SIZE, file);
  1745. }
  1746. if (ferror(file)) {
  1747. usage_format("Failed to read arguments file \"%s\": %s\n",
  1748. filename,
  1749. errno_string());
  1750. }
  1751. astr[astr_sz + sz] = '\0';
  1752. fclose(file);
  1753. if (astr[0] == '\0')
  1754. res = NULL;
  1755. else
  1756. res = build_args_from_string(astr, !0);
  1757. if (astr != buff)
  1758. efree(astr);
  1759. return res;
  1760. #undef FILE_BUFF_SIZE
  1761. }
  1762. typedef struct {
  1763. char **argv;
  1764. int argc;
  1765. int size;
  1766. } argv_buf;
  1767. static void
  1768. trim_argv_buf(argv_buf *abp)
  1769. {
  1770. abp->argv = erealloc(abp->argv, sizeof(char *)*(abp->size = abp->argc));
  1771. }
  1772. static void
  1773. save_arg(argv_buf *abp, char *arg)
  1774. {
  1775. if (abp->size <= abp->argc) {
  1776. if (!abp->argv)
  1777. abp->argv = emalloc(sizeof(char *)*(abp->size = 100));
  1778. else
  1779. abp->argv = erealloc(abp->argv, sizeof(char *)*(abp->size += 100));
  1780. }
  1781. abp->argv[abp->argc++] = arg;
  1782. }
  1783. #define DEF_ARGV_STACK_SIZE 10
  1784. #define ARGV_STACK_SIZE_INCR 50
  1785. typedef struct {
  1786. char **argv;
  1787. int ix;
  1788. } argv_stack_element;
  1789. typedef struct {
  1790. int top_ix;
  1791. int size;
  1792. argv_stack_element *base;
  1793. argv_stack_element def_buf[DEF_ARGV_STACK_SIZE];
  1794. } argv_stack;
  1795. #define ARGV_STACK_INIT(S) \
  1796. do { \
  1797. (S)->top_ix = 0; \
  1798. (S)->size = DEF_ARGV_STACK_SIZE; \
  1799. (S)->base = &(S)->def_buf[0]; \
  1800. } while (0)
  1801. static void
  1802. push_argv(argv_stack *stck, char **argv, int ix)
  1803. {
  1804. if (stck->top_ix == stck->size) {
  1805. if (stck->base != &stck->def_buf[0]) {
  1806. stck->size += ARGV_STACK_SIZE_INCR;
  1807. stck->base = erealloc(stck->base,
  1808. sizeof(argv_stack_element)*stck->size);
  1809. }
  1810. else {
  1811. argv_stack_element *base;
  1812. base = emalloc(sizeof(argv_stack_element)
  1813. *(stck->size + ARGV_STACK_SIZE_INCR));
  1814. memcpy((void *) base,
  1815. (void *) stck->base,
  1816. sizeof(argv_stack_element)*stck->size);
  1817. stck->base = base;
  1818. stck->size += ARGV_STACK_SIZE_INCR;
  1819. }
  1820. }
  1821. stck->base[stck->top_ix].argv = argv;
  1822. stck->base[stck->top_ix++].ix = ix;
  1823. }
  1824. static void
  1825. pop_argv(argv_stack *stck, char ***argvp, int *ixp)
  1826. {
  1827. if (stck->top_ix == 0) {
  1828. *argvp = NULL;
  1829. *ixp = 0;
  1830. }
  1831. else {
  1832. *argvp = stck->base[--stck->top_ix].argv;
  1833. *ixp = stck->base[stck->top_ix].ix;
  1834. if (stck->top_ix == 0 && stck->base != &stck->def_buf[0]) {
  1835. efree(stck->base);
  1836. stck->base = &stck->def_buf[0];
  1837. stck->size = DEF_ARGV_STACK_SIZE;
  1838. }
  1839. }
  1840. }
  1841. static void
  1842. get_file_args(char *filename, argv_buf *abp, argv_buf *xabp)
  1843. {
  1844. argv_stack stck;
  1845. int i;
  1846. char **argv;
  1847. ARGV_STACK_INIT(&stck);
  1848. i = 0;
  1849. argv = read_args_file(filename);
  1850. while (argv) {
  1851. while (argv[i]) {
  1852. if (strcmp(argv[i], "-args_file") == 0) {
  1853. char **new_argv;
  1854. char *fname;
  1855. if (!argv[++i])
  1856. usage("-args_file");
  1857. fname = argv[i++];
  1858. new_argv = read_args_file(fname);
  1859. if (new_argv) {
  1860. if (argv[i])
  1861. push_argv(&stck, argv, i);
  1862. else
  1863. efree(argv);
  1864. i = 0;
  1865. argv = new_argv;
  1866. }
  1867. }
  1868. else {
  1869. if (strcmp(argv[i], "-extra") == 0) {
  1870. i++;
  1871. while (argv[i])
  1872. save_arg(xabp, argv[i++]);
  1873. break;
  1874. }
  1875. save_arg(abp, argv[i++]);
  1876. }
  1877. }
  1878. efree(argv);
  1879. pop_argv(&stck, &argv, &i);
  1880. }
  1881. }
  1882. static void
  1883. initial_argv_massage(int *argc, char ***argv)
  1884. {
  1885. argv_buf ab = {0}, xab = {0};
  1886. int ix, vix, ac;
  1887. char **av;
  1888. char *sep = "--";
  1889. struct {
  1890. int argc;
  1891. char **argv;
  1892. } avv[] = {{INT_MAX, NULL}, {INT_MAX, NULL}, {INT_MAX, NULL},
  1893. {INT_MAX, NULL}, {INT_MAX, NULL},
  1894. {INT_MAX, NULL}, {INT_MAX, NULL}};
  1895. /*
  1896. * The environment flag containing OTP release is intentionally
  1897. * undocumented and intended for OTP internal use only.
  1898. */
  1899. vix = 0;
  1900. av = build_args_from_env("ERL_OTP" OTP_SYSTEM_VERSION "_FLAGS");
  1901. if (av)
  1902. avv[vix++].argv = av;
  1903. av = build_args_from_env("ERL_AFLAGS");
  1904. if (av)
  1905. avv[vix++].argv = av;
  1906. /* command line */
  1907. if (*argc > 1) {
  1908. avv[vix].argc = *argc - 1;
  1909. avv[vix++].argv = &(*argv)[1];
  1910. avv[vix].argc = 1;
  1911. avv[vix++].argv = &sep;
  1912. }
  1913. av = build_args_from_env("ERL_FLAGS");
  1914. if (av)
  1915. avv[vix++].argv = av;
  1916. av = build_args_from_env("ERL_ZFLAGS");
  1917. if (av)
  1918. avv[vix++].argv = av;
  1919. if (vix == (*argc > 1 ? 2 : 0)) {
  1920. /* Only command line argv; check if we can use argv as it is... */
  1921. ac = *argc;
  1922. av = *argv;
  1923. for (ix = 1; ix < ac; ix++) {
  1924. if (strcmp(av[ix], "-args_file") == 0) {
  1925. /* ... no; we need to expand arguments from
  1926. file into argument list */
  1927. goto build_new_argv;
  1928. }
  1929. if (strcmp(av[ix], "-extra") == 0) {
  1930. break;
  1931. }
  1932. }
  1933. /* ... yes; we can use argv as it is. */
  1934. return;
  1935. }
  1936. build_new_argv:
  1937. save_arg(&ab, (*argv)[0]);
  1938. vix = 0;
  1939. while (avv[vix].argv) {
  1940. ac = avv[vix].argc;
  1941. av = avv[vix].argv;
  1942. ix = 0;
  1943. while (ix < ac && av[ix]) {
  1944. if (strcmp(av[ix], "-args_file") == 0) {
  1945. if (++ix == ac)
  1946. usage("-args_file");
  1947. get_file_args(av[ix++], &ab, &xab);
  1948. }
  1949. else {
  1950. if (strcmp(av[ix], "-extra") == 0) {
  1951. ix++;
  1952. while (ix < ac && av[ix])
  1953. save_arg(&xab, av[ix++]);
  1954. break;
  1955. }
  1956. save_arg(&ab, av[ix++]);
  1957. }
  1958. }
  1959. vix++;
  1960. }
  1961. vix = 0;
  1962. while (avv[vix].argv) {
  1963. if (avv[vix].argc == INT_MAX) /* not command line */
  1964. efree(avv[vix].argv);
  1965. vix++;
  1966. }
  1967. if (xab.argc) {
  1968. save_arg(&ab, "-extra");
  1969. for (ix = 0; ix < xab.argc; ix++)
  1970. save_arg(&ab, xab.argv[ix]);
  1971. efree(xab.argv);
  1972. }
  1973. save_arg(&ab, NULL);
  1974. trim_argv_buf(&ab);
  1975. *argv = ab.argv;
  1976. *argc = ab.argc - 1;
  1977. }
  1978. #ifdef __WIN32__
  1979. static char*
  1980. possibly_quote(char* arg)
  1981. {
  1982. int mustQuote = NO;
  1983. int n = 0;
  1984. char* s;
  1985. char* narg;
  1986. /*
  1987. * Scan the string to find out if it needs quoting and return
  1988. * the original argument if not.
  1989. */
  1990. for (s = arg; *s; s++, n++) {
  1991. if (*s == ' ' || *s == '"') {
  1992. mustQuote = YES;
  1993. n++;
  1994. }
  1995. }
  1996. if (!mustQuote) {
  1997. return arg;
  1998. }
  1999. /*
  2000. * Insert the quotes and put a backslash in front of every quote
  2001. * inside the string.
  2002. */
  2003. s = narg = emalloc(n+2+1);
  2004. for (*s++ = '"'; *arg; arg++, s++) {
  2005. if (*s == '"') {
  2006. *s++ = '\\';
  2007. }
  2008. *s = *arg;
  2009. }
  2010. *s++ = '"';
  2011. *s = '\0';
  2012. return narg;
  2013. }
  2014. /*
  2015. * Unicode helpers to handle environment and command line parameters on
  2016. * Windows. We internally handle all environment variables in UTF8,
  2017. * but put and get the environment using the WCHAR (limited UTF16) interface
  2018. *
  2019. * These are simplified to only handle Unicode characters that can fit in
  2020. * Windows simplified UTF16, i.e. characters that fit in 16 bits.
  2021. */
  2022. static int utf8_len(unsigned char first)
  2023. {
  2024. if ((first & ((unsigned char) 0x80)) == 0) {
  2025. return 1;
  2026. } else if ((first & ((unsigned char) 0xE0)) == 0xC0) {
  2027. return 2;
  2028. } else if ((first & ((unsigned char) 0xF0)) == 0xE0) {
  2029. return 3;
  2030. } else if ((first & ((unsigned char) 0xF8)) == 0xF0) {
  2031. return 4;
  2032. }
  2033. return 1; /* will be a '?' */
  2034. }
  2035. static WCHAR *utf8_to_utf16(unsigned char *bytes)
  2036. {
  2037. unsigned int unipoint;
  2038. unsigned char *tmp = bytes;
  2039. WCHAR *target, *res;
  2040. int num = 0;
  2041. while (*tmp) {
  2042. num++;
  2043. tmp += utf8_len(*tmp);
  2044. }
  2045. res = target = emalloc((num + 1) * sizeof(WCHAR));
  2046. while (*bytes) {
  2047. if (((*bytes) & ((unsigned char) 0x80)) == 0) {
  2048. unipoint = (unsigned int) *bytes;
  2049. ++bytes;
  2050. } else if (((*bytes) & ((unsigned char) 0xE0)) == 0xC0) {
  2051. unipoint =
  2052. (((unsigned int) ((*bytes) & ((unsigned char) 0x1F))) << 6) |
  2053. ((unsigned int) (bytes[1] & ((unsigned char) 0x3F)));
  2054. bytes += 2;
  2055. } else if (((*bytes) & ((unsigned char) 0xF0)) == 0xE0) {
  2056. unipoint =
  2057. (((unsigned int) ((*bytes) & ((unsigned char) 0xF))) << 12) |
  2058. (((unsigned int) (bytes[1] & ((unsigned char) 0x3F))) << 6) |
  2059. ((unsigned int) (bytes[2] & ((unsigned char) 0x3F)));
  2060. if (unipoint > 0xFFFF) {
  2061. unipoint = (unsigned int) '?';
  2062. }
  2063. bytes +=3;
  2064. } else if (((*bytes) & ((unsigned char) 0xF8)) == 0xF0) {
  2065. unipoint = (unsigned int) '?'; /* Cannot put in a wchar */
  2066. bytes += 4;
  2067. } else {
  2068. unipoint = (unsigned int) '?';
  2069. }
  2070. *target++ = (WCHAR) unipoint;
  2071. }
  2072. *target = L'\0';
  2073. return res;
  2074. }
  2075. static int put_utf8(WCHAR ch, unsigned char *target, int sz, int *pos)
  2076. {
  2077. unsigned int x = (unsigned int) ch;
  2078. if (x < 0x80) {
  2079. if (*pos >= sz) {
  2080. return -1;
  2081. }
  2082. target[(*pos)++] = (unsigned char) x;
  2083. }
  2084. else if (x < 0x800) {
  2085. if (((*pos) + 1) >= sz) {
  2086. return -1;
  2087. }
  2088. target[(*pos)++] = (((unsigned char) (x >> 6)) |
  2089. ((unsigned char) 0xC0));
  2090. target[(*pos)++] = (((unsigned char) (x & 0x3F)) |
  2091. ((unsigned char) 0x80));
  2092. } else {
  2093. if ((x >= 0xD800 && x <= 0xDFFF) ||
  2094. (x == 0xFFFE) ||
  2095. (x == 0xFFFF)) { /* Invalid unicode range */
  2096. return -1;
  2097. }
  2098. if (((*pos) + 2) >= sz) {
  2099. return -1;
  2100. }
  2101. target[(*pos)++] = (((unsigned char) (x >> 12)) |
  2102. ((unsigned char) 0xE0));
  2103. target[(*pos)++] = ((((unsigned char) (x >> 6)) & 0x3F) |
  2104. ((unsigned char) 0x80));
  2105. target[(*pos)++] = (((unsigned char) (x & 0x3F)) |
  2106. ((unsigned char) 0x80));
  2107. }
  2108. return 0;
  2109. }
  2110. static int need_bytes_for_utf8(WCHAR x)
  2111. {
  2112. if (x < 0x80)
  2113. return 1;
  2114. else if (x < 0x800)
  2115. return 2;
  2116. else
  2117. return 3;
  2118. }
  2119. static WCHAR *latin1_to_utf16(char *str)
  2120. {
  2121. int len = strlen(str);
  2122. int i;
  2123. WCHAR *wstr = emalloc((len+1) * sizeof(WCHAR));
  2124. for(i=0;i<len;++i)
  2125. wstr[i] = (WCHAR) str[i];
  2126. wstr[len] = L'\0';
  2127. return wstr;
  2128. }
  2129. static char *utf16_to_utf8(WCHAR *wstr)
  2130. {
  2131. int len = wcslen(wstr);
  2132. char *result;
  2133. int i,pos;
  2134. int reslen = 0;
  2135. for(i=0;i<len;++i) {
  2136. reslen += need_bytes_for_utf8(wstr[i]);
  2137. }
  2138. result = emalloc(reslen+1);
  2139. pos = 0;
  2140. for(i=0;i<len;++i) {
  2141. if (put_utf8((int) wstr[i], result, reslen, &pos) < 0) {
  2142. break;
  2143. }
  2144. }
  2145. result[pos] = '\0';
  2146. return result;
  2147. }
  2148. #endif