PageRenderTime 900ms CodeModel.GetById 141ms app.highlight 548ms RepoModel.GetById 136ms app.codeStats 1ms

/erts/etc/common/erlexec.c

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