PageRenderTime 13ms CodeModel.GetById 22ms app.highlight 126ms RepoModel.GetById 1ms app.codeStats 0ms

/erts/etc/common/erlexec.c

https://github.com/erlang/otp
C | 2301 lines | 2266 code | 8 blank | 27 comment | 4 complexity | de15036ba32655b00a600a758997eb56 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file