aboutsummaryrefslogtreecommitdiffstats
path: root/erts/etc/win32
diff options
context:
space:
mode:
Diffstat (limited to 'erts/etc/win32')
-rw-r--r--erts/etc/win32/Install.c229
-rw-r--r--erts/etc/win32/Install.src4
-rw-r--r--erts/etc/win32/Makefile72
-rw-r--r--erts/etc/win32/Nmakefile.start_erl33
-rw-r--r--erts/etc/win32/beam.rc102
-rw-r--r--erts/etc/win32/beam_icon.icobin0 -> 766 bytes
-rwxr-xr-xerts/etc/win32/cygwin_tools/erl48
-rwxr-xr-xerts/etc/win32/cygwin_tools/erlc61
-rwxr-xr-xerts/etc/win32/cygwin_tools/javac.sh53
-rwxr-xr-xerts/etc/win32/cygwin_tools/make_bootstrap_ini.sh44
-rwxr-xr-xerts/etc/win32/cygwin_tools/make_local_ini.sh41
-rwxr-xr-xerts/etc/win32/cygwin_tools/mingw/ar.sh55
-rwxr-xr-xerts/etc/win32/cygwin_tools/mingw/cc.sh293
-rw-r--r--erts/etc/win32/cygwin_tools/mingw/coffix.c161
-rwxr-xr-xerts/etc/win32/cygwin_tools/mingw/emu_cc.sh90
-rwxr-xr-xerts/etc/win32/cygwin_tools/mingw/ld.sh147
-rwxr-xr-xerts/etc/win32/cygwin_tools/mingw/mc.sh89
-rwxr-xr-xerts/etc/win32/cygwin_tools/mingw/rc.sh94
-rwxr-xr-xerts/etc/win32/cygwin_tools/vc/ar.sh47
-rwxr-xr-xerts/etc/win32/cygwin_tools/vc/cc.sh321
-rw-r--r--erts/etc/win32/cygwin_tools/vc/cc_wrap.c864
-rw-r--r--erts/etc/win32/cygwin_tools/vc/coffix.c161
-rwxr-xr-xerts/etc/win32/cygwin_tools/vc/emu_cc.sh90
-rwxr-xr-xerts/etc/win32/cygwin_tools/vc/ld.sh192
-rw-r--r--erts/etc/win32/cygwin_tools/vc/ld_wrap.c796
-rwxr-xr-xerts/etc/win32/cygwin_tools/vc/mc.sh87
-rwxr-xr-xerts/etc/win32/cygwin_tools/vc/rc.sh86
-rw-r--r--erts/etc/win32/erl.c283
-rw-r--r--erts/etc/win32/erl.rc31
-rw-r--r--erts/etc/win32/erl_icon.icobin0 -> 766 bytes
-rw-r--r--erts/etc/win32/erl_log.c73
-rw-r--r--erts/etc/win32/erlang.icobin0 -> 1398 bytes
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_global.h37
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_interactive.c1163
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_interactive.h24
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_logmess.mc33
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_main.c44
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_registry.c404
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_registry.h76
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_service.c966
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_service.h32
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_util.c154
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_util.h50
-rw-r--r--erts/etc/win32/hrl_icon.icobin0 -> 766 bytes
-rw-r--r--erts/etc/win32/init_file.c565
-rw-r--r--erts/etc/win32/init_file.h93
-rw-r--r--erts/etc/win32/nsis/Makefile88
-rwxr-xr-xerts/etc/win32/nsis/custom_modern.exebin0 -> 6144 bytes
-rwxr-xr-xerts/etc/win32/nsis/dll_version_helper.sh49
-rw-r--r--erts/etc/win32/nsis/erlang.nsi386
-rw-r--r--erts/etc/win32/nsis/erlang20.nsi440
-rw-r--r--erts/etc/win32/nsis/erlang_inst.icobin0 -> 766 bytes
-rwxr-xr-xerts/etc/win32/nsis/erlang_uninst.icobin0 -> 766 bytes
-rwxr-xr-xerts/etc/win32/nsis/find_redist.sh122
-rw-r--r--erts/etc/win32/port_entry.c75
-rw-r--r--erts/etc/win32/resource.h33
-rw-r--r--erts/etc/win32/start_erl.c677
-rw-r--r--erts/etc/win32/toolbar.bmpbin0 -> 598 bytes
-rw-r--r--erts/etc/win32/win_erlexec.c405
59 files changed, 10563 insertions, 0 deletions
diff --git a/erts/etc/win32/Install.c b/erts/etc/win32/Install.c
new file mode 100644
index 0000000000..4a559cd8a2
--- /dev/null
+++ b/erts/etc/win32/Install.c
@@ -0,0 +1,229 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2003-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+/*
+ * Some code just simply does not deserve functions :-)
+ * Dead simple installation program to set up init files etc after erlang is
+ * copied to its destination. Also to be used after a patch is applied.
+ */
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "init_file.h"
+
+int main(int argc, char **argv)
+{
+ int silent = 0;
+ int start_sasl = 0;
+ char *root = NULL;
+ int i;
+ char buffer[MAX_PATH];
+ char erts_dir[MAX_PATH];
+ char release_dir[MAX_PATH];
+ char bin_dir[MAX_PATH];
+ char *tmp;
+ char my_ini_filename[MAX_PATH];
+ InitFile *my_ini_file;
+ InitSection *my_ini_section;
+ char version_string[MAX_PATH];
+ InitFile *ini_file;
+ InitSection *ini_section;
+ HANDLE module = GetModuleHandle(NULL);
+ char *binaries[] = { "erl.exe", "werl.exe", "erlc.exe",
+ "dialyzer.exe", "typer.exe",
+ "escript.exe", NULL };
+ char *scripts[] = { "start_clean.boot", "start_sasl.boot", NULL };
+ char fromname[MAX_PATH];
+ char toname[MAX_PATH];
+
+
+ for (i = 1; i < argc; ++i) {
+ switch(argv[i][0]) {
+ case '-' :
+ switch(argv[i][1]) {
+ case 's' :
+ silent = 1;
+ break;
+ default:
+ fprintf(stderr, "Unknown command switch %s\n",
+ argv[i]);
+ exit(1);
+ }
+ break;
+ default:
+ if (root != NULL) {
+ fprintf(stderr, "Only one root directory can be specified, "
+ "parameter %s is illegal\n",
+ argv[i]);
+ exit(1);
+ }
+ root = argv[i];
+ break;
+ }
+ }
+ if (root == NULL) {
+ if (module = NULL) {
+ fprintf(stderr, "Cannot GetModuleHandle()\n");
+ exit(1);
+ }
+
+ if (GetModuleFileName(module,buffer,MAX_PATH) == 0) {
+ fprintf(stderr,"Could not GetModuleFileName()\n");
+ exit(1);
+ }
+ i = strlen(buffer) - 1;
+ while ( i >= 0 && buffer[i] != '\\') {
+ --i;
+ }
+ if (i < 0) {
+ fprintf(stderr,"GetModuleFileName returned broken path\n");
+ exit(1);
+ }
+ buffer[i] = '\0';
+ root = buffer;
+ }
+
+ if (!silent) {
+ char answer[100];
+ char *eol;
+ start_sasl = 1;
+ printf("Do you want a minimal startup instead of sasl [No]: ");
+ fflush(stdout);
+ if (fgets(answer,100,stdin) == NULL) {
+ fprintf(stderr, "Could not read answer from user.\n");
+ exit(1);
+ }
+ eol = strchr(answer,'\n');
+ if (eol == NULL) {
+ while (getchar() != '\n')
+ ;
+ } else {
+ *eol = '\0';
+ }
+ if ((eol = strchr(answer, '\r')) != NULL) {
+ *eol = '\0';
+ }
+ if (_stricmp(answer,"yes") == 0 || _stricmp(answer,"y") == 0) {
+ start_sasl = 0;
+ }
+ }
+ sprintf(my_ini_filename,"%s\\Install.ini",root);
+ my_ini_file = load_init_file(my_ini_filename);
+ if (my_ini_file == NULL) {
+ fprintf(stderr,"Cannot open init file %s\n",my_ini_filename);
+ exit(1);
+ }
+
+ if ((my_ini_section = lookup_init_section(my_ini_file,"Install"))
+ == NULL) {
+ fprintf(stderr,"No [Install] section in init file %s\n",
+ my_ini_filename);
+ exit(1);
+ }
+
+ if ((tmp = lookup_init_entry(my_ini_section, "VSN")) == NULL) {
+ fprintf(stderr,"No key VSN in init file %s\n",
+ my_ini_filename);
+ exit(1);
+ }
+
+ strcpy(version_string,tmp);
+
+ sprintf(erts_dir,"%s\\erts-%s\\bin",root,tmp);
+ if ((tmp = lookup_init_entry(my_ini_section, "SYSTEM_VSN")) == NULL) {
+ fprintf(stderr,"No key SYSTEM_VSN in init file %s\n",
+ my_ini_filename);
+ exit(1);
+ }
+ sprintf(release_dir,"%s\\releases\\%s",root,tmp);
+
+ sprintf(bin_dir,"%s\\bin",root);
+ CreateDirectory(bin_dir,NULL);
+
+ free_init_file(my_ini_file);
+
+ for (i = 0; binaries[i] != NULL; ++i) {
+ sprintf(fromname,"%s\\%s",erts_dir,binaries[i]);
+ sprintf(toname,"%s\\%s",bin_dir,binaries[i]);
+ if (GetFileAttributes(fromname) == 0xFFFFFFFF) {
+ fprintf(stderr,"Could not find file %s\n",
+ fromname);
+ exit(1);
+ }
+ if (!CopyFile(fromname,toname,FALSE)) {
+ fprintf(stderr,"Could not copy file %s to %s\n",
+ fromname,toname);
+ fprintf(stderr,"Continuing installation anyway...\n");
+ }
+ }
+
+ for (i = 0; scripts[i] != NULL; ++i) {
+ sprintf(fromname,"%s\\%s",release_dir,scripts[i]);
+ sprintf(toname,"%s\\%s",bin_dir,scripts[i]);
+ if (GetFileAttributes(fromname) == 0xFFFFFFFF) {
+ fprintf(stderr,"Could not find file %s\n",
+ fromname);
+ exit(1);
+ }
+ if (!CopyFile(fromname,toname,FALSE)) {
+ fprintf(stderr,"Could not copy file %s to %s\n",
+ fromname,toname);
+ fprintf(stderr,"Cannot continue installation, bailing out.\n");
+ exit(1);
+ }
+ }
+ if (start_sasl) {
+ sprintf(fromname,"%s\\start_sasl.boot",bin_dir);
+ } else {
+ sprintf(fromname,"%s\\start_clean.boot",bin_dir);
+ }
+ sprintf(toname,"%s\\start.boot",bin_dir);
+ if (!CopyFile(fromname,toname,FALSE)) {
+ fprintf(stderr,"Could not copy file %s to %s\n",
+ fromname,toname);
+ fprintf(stderr,"Cannot continue installation, bailing out.\n");
+ exit(1);
+ }
+ ini_file = create_init_file();
+ ini_section = create_init_section("erlang");
+ add_init_section(ini_file,ini_section);
+ add_init_entry(ini_section,"Bindir",erts_dir);
+ add_init_entry(ini_section,"Progname","erl");
+ add_init_entry(ini_section,"Rootdir",root);
+ sprintf(fromname,"%s\\erl.ini",erts_dir);
+ sprintf(toname,"%s\\erl.ini",bin_dir);
+ if (store_init_file(ini_file,fromname) != 0) {
+ fprintf(stderr,"Could not create file %s\n",
+ fromname);
+ fprintf(stderr,"Cannot continue installation, bailing out.\n");
+ exit(1);
+ }
+ if (!CopyFile(fromname,toname,FALSE)) {
+ fprintf(stderr,"Could not copy file %s to %s\n",
+ fromname,toname);
+ fprintf(stderr,"Cannot continue installation, bailing out.\n");
+ exit(1);
+ }
+ if (!silent) {
+ printf("Erlang %s installed successfully\n", version_string);
+ }
+ return 0;
+}
+
+
+
diff --git a/erts/etc/win32/Install.src b/erts/etc/win32/Install.src
new file mode 100644
index 0000000000..4aaa171ce0
--- /dev/null
+++ b/erts/etc/win32/Install.src
@@ -0,0 +1,4 @@
+[Install]
+VSN=%I_VSN%
+SYSTEM_VSN=%I_SYSTEM_VSN%
+
diff --git a/erts/etc/win32/Makefile b/erts/etc/win32/Makefile
new file mode 100644
index 0000000000..400e5c5bba
--- /dev/null
+++ b/erts/etc/win32/Makefile
@@ -0,0 +1,72 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1996-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+include ../../vsn.mk
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELEASE_PATH= ../../release/$(TARGET)
+RELSYSDIR = $(RELEASE_PATH)/erts-$(VSN)
+ROOTSYSDIR = $(RELEASE_PATH)
+
+BINDIR = $(ERL_TOP)/bin/$(TARGET)
+RUNTIME = $(ERL_TOP)/erts/emulator/beam
+SYS = $(ERL_TOP)/erts/emulator/sys/win32
+OBJ = $(ERL_TOP)/erts/obj/$(TARGET)
+ROOTDIR = $(ERL_TOP)/erts
+
+INSTALL_PROGS = \
+ $(BINDIR)/inet_gethost.exe \
+ $(BINDIR)/erl.exe \
+ $(BINDIR)/werl.exe \
+ $(BINDIR)/heart.exe \
+ $(BINDIR)/erlc.exe \
+ $(BINDIR)/erlsrv.exe \
+ $(BINDIR)/start_erl.exe
+
+INSTALL_SRC = ./start_erl.c ./Nmakefile.start_erl
+
+INSTALL_LIBS = $(BINDIR)/erl_dll.lib
+
+INSTALL_ICONS = ./beam_icon.ico ./erl_icon.ico ./hrl_icon.ico
+
+opt debug all clean depend:
+ @echo Nothing to do for "'"$@"'" on $(TARGET)
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec:
+ $(INSTALL_DIR) $(RELSYSDIR)/bin
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(ROOTSYSDIR)/usr/include
+ $(INSTALL_DIR) $(ROOTSYSDIR)/usr/lib
+ $(INSTALL_DIR) $(ROOTSYSDIR)/usr/lib/icons
+ $(INSTALL_PROGRAM) $(INSTALL_PROGS) $(RELSYSDIR)/bin
+ $(INSTALL_DATA) $(INSTALL_SRC) $(RELSYSDIR)/src
+ $(INSTALL_DATA) $(INSTALL_ICONS) $(ROOTSYSDIR)/usr/lib/icons
+
+release_docs release_docs_spec docs:
+
diff --git a/erts/etc/win32/Nmakefile.start_erl b/erts/etc/win32/Nmakefile.start_erl
new file mode 100644
index 0000000000..5bf9fd78d5
--- /dev/null
+++ b/erts/etc/win32/Nmakefile.start_erl
@@ -0,0 +1,33 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1998-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+# Example nmakefile to build start_erl.exe from start_erl.c
+# Microsoft Visual C++ is expected to be installed
+# and the PATH, INCLUDE and LIB environment valiables set up correctly.
+# Invoke with nmake -f NMakefile.start_erl.
+
+CC=cl
+CFLAGS=-W3
+LDFLAGS=user32.lib advapi32.lib
+
+start_erl.exe: start_erl.c
+ $(CC) $(CFLAGS) $? -Festart_erl.exe $(LDFLAGS)
+
+clean:
+ -del start_erl.obj start_erl.exe
+
diff --git a/erts/etc/win32/beam.rc b/erts/etc/win32/beam.rc
new file mode 100644
index 0000000000..cd7db67d4d
--- /dev/null
+++ b/erts/etc/win32/beam.rc
@@ -0,0 +1,102 @@
+//
+// %CopyrightBegin%
+//
+// Copyright Ericsson AB 1997-2009. All Rights Reserved.
+//
+// The contents of this file are subject to the Erlang Public License,
+// Version 1.1, (the "License"); you may not use this file except in
+// compliance with the License. You should have received a copy of the
+// Erlang Public License along with this software. If not, it can be
+// retrieved online at http://www.erlang.org/.
+//
+// Software distributed under the License is distributed on an "AS IS"
+// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+// the License for the specific language governing rights and limitations
+// under the License.
+//
+// %CopyrightEnd%
+//
+#include <windows.h>
+#include "resource.h"
+
+1 ICON DISCARDABLE "erlang.ico"
+2 ICON DISCARDABLE "erl_icon.ico"
+3 ICON DISCARDABLE "hrl_icon.ico"
+4 ICON DISCARDABLE "beam_icon.ico"
+1 BITMAP MOVEABLE PURE "toolbar.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+1 MENU DISCARDABLE
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&Open Logfile...", IDMENU_STARTLOG
+ MENUITEM "&Close Logfile", IDMENU_STOPLOG
+ MENUITEM SEPARATOR
+ MENUITEM "&Exit\tAlt+F4", IDMENU_EXIT
+ END
+ POPUP "&Edit"
+ BEGIN
+ MENUITEM "&Copy\tCtrl+C", IDMENU_COPY
+ MENUITEM "&Paste\tCtrl+V", IDMENU_PASTE
+ MENUITEM SEPARATOR
+ MENUITEM "Select A&ll", IDMENU_SELALL
+ END
+ POPUP "&Options"
+ BEGIN
+ MENUITEM "&Select Font...", IDMENU_FONT
+ MENUITEM "Select &Background...", IDMENU_SELECTBKG
+ END
+ POPUP "&View"
+ BEGIN
+ MENUITEM "&Toolbar", IDMENU_TOOLBAR
+ END
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&About", IDMENU_ABOUT
+ END
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+AboutBox DIALOG DISCARDABLE 0, 0, 217, 55
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "About Erlang Shell"
+FONT 8, "MS Sans Serif"
+BEGIN
+ ICON 1,-1,11,17,18,20
+ LTEXT "Erlang Shell Version 1.0",ID_VERSIONSTRING,40,10,119,8,
+ SS_NOPREFIX
+ LTEXT "Copyright � Ericsson Telecom AB",-1,40,25,
+ 119,8
+ DEFPUSHBUTTON "OK",IDOK,178,7,32,14,WS_GROUP
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerators
+//
+
+1 ACCELERATORS
+{
+ VK_CANCEL, ID_BREAK, VIRTKEY, CONTROL
+ "^C", IDMENU_COPY
+ VK_INSERT, IDMENU_COPY, VIRTKEY, CONTROL
+ "^V", IDMENU_PASTE
+ VK_INSERT, IDMENU_PASTE, VIRTKEY, SHIFT
+ VK_F1, IDMENU_ABOUT, VIRTKEY
+}
+
+
+
+
+
+
+
+
+
diff --git a/erts/etc/win32/beam_icon.ico b/erts/etc/win32/beam_icon.ico
new file mode 100644
index 0000000000..fb22afda62
--- /dev/null
+++ b/erts/etc/win32/beam_icon.ico
Binary files differ
diff --git a/erts/etc/win32/cygwin_tools/erl b/erts/etc/win32/cygwin_tools/erl
new file mode 100755
index 0000000000..576825c4be
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/erl
@@ -0,0 +1,48 @@
+#! /bin/sh
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2002-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+# Note! This shellscript expects to be run in a cygwin environment,
+# it converts erlc command lines to native windows erlc commands, which
+# basically means running the command cygpath on whatever is a path...
+
+CMD=""
+for x in "$@"; do
+ case "$x" in
+ -I/*|-o/*)
+ y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`;
+ z=`echo $x | sed 's,^-\([Io]\)\(/.*\),\1,g'`;
+ #echo "Foooo:$z"
+ MPATH=`cygpath -m $y`;
+ CMD="$CMD -$z\"$MPATH\"";;
+ /*)
+ #echo "absolute:"$x;
+ MPATH=`cygpath -m $x`;
+ CMD="$CMD \"$MPATH\"";;
+# +{*);;
+ *)
+# y=`echo $x | sed 's,",\\\\\\\\\\\",g'`;
+ y=`echo $x | sed 's,",\\\",g'`;
+ CMD="$CMD \"$y\"";;
+ esac
+done
+#echo "$@"
+#eval echo erlc.exe $CMD
+ERL_TOP=`cygpath -m $ERL_TOP`
+export ERL_TOP
+eval erl.exe $CMD
diff --git a/erts/etc/win32/cygwin_tools/erlc b/erts/etc/win32/cygwin_tools/erlc
new file mode 100755
index 0000000000..a18ec27bf4
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/erlc
@@ -0,0 +1,61 @@
+#! /bin/sh
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2002-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+# Note! This shellscript expects to be run in a cygwin environment,
+# it converts erlc command lines to native windows erlc commands, which
+# basically means running the command cygpath on whatever is a path...
+
+CMD=""
+ECHO_ONLY=false
+for x in "$@"; do
+ case "$x" in
+ --echo_only)
+ ECHO_ONLY=true;;
+ -I/*|-o/*)
+ y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`;
+ z=`echo $x | sed 's,^-\([Io]\)\(/.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ CMD="$CMD -$z$MPATH";;
+ -pa/*)
+ y=`echo $x | sed 's,^-pa\(/.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ CMD="$CMD -pa $MPATH";;
+ /*)
+ MPATH=`cygpath -m $x`;
+ CMD="$CMD \"$MPATH\"";;
+# Needed for +'{preproc_flags,whatever}'
+ +{preproc_flags,*})
+ y=`echo $x | sed 's,^+{preproc_flags\,"\(.*\)"},\1,g'`;
+ z=`eval $0 --echo_only $y`;
+ case "$z" in # Dont "doubledoublequote"
+ \"*\")
+ CMD="$CMD +'{preproc_flags,$z}'";;
+ *)
+ CMD="$CMD +'{preproc_flags,\"$z\"}'";;
+ esac;;
+ *)
+ y=`echo $x | sed 's,",\\\",g'`;
+ CMD="$CMD \"$y\"";;
+ esac
+done
+if [ $ECHO_ONLY = true ]; then
+ echo $CMD
+else
+ eval erlc.exe $CMD
+fi
diff --git a/erts/etc/win32/cygwin_tools/javac.sh b/erts/etc/win32/cygwin_tools/javac.sh
new file mode 100755
index 0000000000..f9ee24593f
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/javac.sh
@@ -0,0 +1,53 @@
+#! /bin/sh
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2002-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+# Note! This shellscript expects to be run in a cygwin environment,
+# it converts erlc command lines to native windows erlc commands, which
+# basically means running the command cygpath on whatever is a path...
+
+CMD=""
+CLASSPATH=`cygpath -m -p $CLASSPATH`
+export CLASSPATH
+#echo "CLASSPATH=$CLASSPATH"
+SAVE="$@"
+while test -n "$1" ; do
+ x="$1"
+ case "$x" in
+ -I/*|-o/*|-d/*)
+ y=`echo $x | sed 's,^-[Iod]\(/.*\),\1,g'`;
+ z=`echo $x | sed 's,^-\([Iod]\)\(/.*\),\1,g'`;
+ #echo "Foooo:$z"
+ MPATH=`cygpath -m $y`;
+ CMD="$CMD -$z\"$MPATH\"";;
+ -d|-I|-o)
+ shift;
+ MPATH=`cygpath -m $1`;
+ CMD="$CMD $x $MPATH";;
+ /*)
+ #echo "absolute:"$x;
+ MPATH=`cygpath -m $x`;
+ CMD="$CMD \"$MPATH\"";;
+ *)
+ y=`echo $x | sed 's,",\\\",g'`;
+ CMD="$CMD \"$y\"";;
+ esac
+ shift
+done
+#echo javac.exe $CMD
+eval javac.exe $CMD
diff --git a/erts/etc/win32/cygwin_tools/make_bootstrap_ini.sh b/erts/etc/win32/cygwin_tools/make_bootstrap_ini.sh
new file mode 100755
index 0000000000..20fe143890
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/make_bootstrap_ini.sh
@@ -0,0 +1,44 @@
+#! /bin/bash
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2003-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+# Create a local init-file for erlang in the build environment.
+if [ -z "$1" ]; then
+ echo "error: $0: No rootdir given"
+ exit 1
+else
+ RDIR=$1
+fi
+if [ -z "$2" ]; then
+ echo "error: $0: No bindir given"
+ exit 1
+else
+ BDIR=$2
+fi
+
+DRDIR=`(cygpath -d $RDIR 2>/dev/null || cygpath -w $RDIR) | sed 's,\\\,\\\\\\\\,g'`
+DBDIR=`(cygpath -d $BDIR 2>/dev/null || cygpath -w $BDIR) | sed 's,\\\,\\\\\\\\,g'`
+
+
+cat > $RDIR/bin/erl.ini <<EOF
+[erlang]
+Bindir=$DBDIR
+Progname=erl
+Rootdir=$DRDIR
+EOF
+
diff --git a/erts/etc/win32/cygwin_tools/make_local_ini.sh b/erts/etc/win32/cygwin_tools/make_local_ini.sh
new file mode 100755
index 0000000000..8e29573dc4
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/make_local_ini.sh
@@ -0,0 +1,41 @@
+#! /bin/bash
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2003-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+# Create a local init-file for erlang in the build environment.
+if [ -z "$1" ]; then
+ if [ -z $ERL_TOP ]; then
+ echo "error: $0: No rootdir available"
+ exit 1
+ else
+ RDIR=$ERL_TOP
+ fi
+else
+ RDIR=$1
+fi
+
+DDIR=`(cygpath -d $RDIR 2>/dev/null || cygpath -w $RDIR) | sed 's,\\\,\\\\\\\\,g'`
+
+
+cat > $RDIR/bin/erl.ini <<EOF
+[erlang]
+Bindir=$DDIR\\\\bin\\\\win32
+Progname=erl
+Rootdir=$DDIR
+EOF
+
diff --git a/erts/etc/win32/cygwin_tools/mingw/ar.sh b/erts/etc/win32/cygwin_tools/mingw/ar.sh
new file mode 100755
index 0000000000..5b8f58e5de
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/mingw/ar.sh
@@ -0,0 +1,55 @@
+#! /bin/sh
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2006-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+CMD=""
+if [ -z "$MINGW_EXE_PATH" ]; then
+ echo "You have to set MINGW_EXE_PATH to run ar.sh" >&2
+ exit 1
+fi
+while test -n "$1" ; do
+ x="$1"
+ case "$x" in
+ -o|-out:)
+ shift
+ case "$1" in
+ /*)
+ MPATH=`cygpath -m $1`;;
+ *)
+ MPATH=$1;;
+ esac
+ CMD="rcv \"$MPATH\" $CMD";;
+ -out:*)
+ y=`echo $x | sed 's,^-out:\(.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ CMD="rcv \"$MPATH\" $CMD";;
+ -o*)
+ y=`echo $x | sed 's,^-o\(.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ CMD="rcv \"$MPATH\" $CMD";;
+ /*)
+ MPATH=`cygpath -m $x`;
+ CMD="$CMD \"$MPATH\"";;
+ *)
+ y=`echo $x | sed 's,",\\\",g'`;
+ CMD="$CMD \"$y\"";;
+ esac
+ shift
+done
+
+eval $MINGW_EXE_PATH/ar.exe $CMD
diff --git a/erts/etc/win32/cygwin_tools/mingw/cc.sh b/erts/etc/win32/cygwin_tools/mingw/cc.sh
new file mode 100755
index 0000000000..ae284893fa
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/mingw/cc.sh
@@ -0,0 +1,293 @@
+#! /bin/sh
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2006-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+# Icky cl wrapper that does it's best to behave like a Unixish cc.
+# Made to work for Erlang builds and to make configure happy, not really
+# general I suspect.
+# set -x
+# Save the command line for debug outputs
+SAVE="$@"
+
+# Constants
+COMMON_CFLAGS="-mwindows -D__WIN32__ -DWIN32 -DWINDOWS -D_WIN32 -DNT -DWIN32_MINGW"
+
+# Variables
+# The stdout and stderr for the compiler
+MSG_FILE=/tmp/gcc.exe.$$.1
+ERR_FILE=/tmp/gcc.exe.$$.2
+
+# "Booleans" determined during "command line parsing"
+# If the stdlib option is explicitly passed to this program
+MD_FORCED=false
+# If we're preprocession (only) i.e. -E
+PREPROCESSING=false
+# If this is supposed to be a debug build
+DEBUG_BUILD=false
+# If this is supposed to be an optimized build (there can only be one...)
+OPTIMIZED_BUILD=false
+# If we're linking or only compiling
+LINKING=true
+
+# This data is accumulated during command line "parsing"
+# The stdlibrary option, default multithreaded dynamic
+# NOTE! The standard library options are actually ignored by the linker later
+# on, I've retained parsing of them from the VC++ version as they may be
+# needed in the future...
+MD=-MD
+# Flags for debug compilation
+DEBUG_FLAGS=""
+# Flags for optimization
+OPTIMIZE_FLAGS=""
+# The specified output filename (if any), may be either object or exe.
+OUTFILE=""
+# Unspe3cified command line options for the compiler
+CMD=""
+# All the c source files, in unix style
+SOURCES=""
+# All the options to pass to the linker, kept in Unix style
+LINKCMD=""
+LINKSOURCES=""
+DEPENDING=false
+
+if [ -z "$MINGW_EXE_PATH" ]; then
+ echo "You have to set MINGW_EXE_PATH to run cc.sh" >&2
+ exit 1
+fi
+
+
+# Loop through the parameters and set the above variables accordingly
+# Also convert some cygwin filenames to "mixed style" dito (understood by the
+# compiler very well), except for anything passed to the linker, that script
+# handles those and the sources, which are also kept unixish for now
+
+while test -n "$1" ; do
+ x="$1"
+ case "$x" in
+ -Wall)
+ ;;
+ -c)
+ LINKING=false;;
+ -E)
+ PREPROCESSING=true;
+ LINKING=false;; # Obviously...
+ -MM|-M)
+ DEPENDING=true;
+ LINKING=false;; # Obviously...
+ -O*)
+ # Optimization hardcoded
+ OPTIMIZE_FLAGS="$x";
+ DEBUG_FLAGS="-ggdb";
+ DEBUG_BUILD=false;
+ if [ $MD_FORCED = false ]; then
+ MD=-MD;
+ fi
+ OPTIMIZED_BUILD=true;;
+ -g|-ggdb)
+ if [ $OPTIMIZED_BUILD = false ];then
+ # Hardcoded windows debug flags
+ DEBUG_FLAGS="-ggdb";
+ if [ $MD_FORCED = false ]; then
+ MD=-MDd;
+ fi
+ DEBUG_BUILD=true;
+ fi;;
+ # Allow forcing of stdlib
+ -mt|-MT)
+ MD="-MT";
+ MD_FORCED=true;;
+ -md|-MD)
+ MD="-MD";
+ MD_FORCED=true;;
+ -ml|-ML)
+ MD="-ML";
+ MD_FORCED=true;;
+ -mdd|-MDD|-MDd)
+ MD="-MDd";
+ MD_FORCED=true;;
+ -mtd|-MTD|-MTd)
+ MD="-MTd";
+ MD_FORCED=true;;
+ -mld|-MLD|-MLd)
+ MD="-MLd";
+ MD_FORCED=true;;
+ -o)
+ shift;
+ OUTFILE="$1";;
+ -o*)
+ y=`echo $x | sed 's,^-[Io]\(.*\),\1,g'`;
+ OUTFILE="$y";;
+ -I/*)
+ y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`;
+ z=`echo $x | sed 's,^-\([Io]\)\(/.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ CMD="$CMD -$z\"$MPATH\"";;
+ -I*)
+ y=`echo $x | sed 's,",\\\",g'`;
+ CMD="$CMD $y";;
+ -D*)
+ y=`echo $x | sed 's,",\\\",g'`;
+ CMD="$CMD $y";;
+ -l*)
+ y=`echo $x | sed 's,^-l\(.*\),\1,g'`;
+ LINKCMD="$LINKCMD $x";;
+ /*.c)
+ SOURCES="$SOURCES $x";;
+ *.c)
+ SOURCES="$SOURCES $x";;
+ /*.o)
+ LINKCMD="$LINKCMD $x";;
+ *.o)
+ LINKCMD="$LINKCMD $x";;
+ *)
+ # Try to quote uninterpreted options
+ y=`echo $x | sed 's,",\\\",g'`;
+ LINKCMD="$LINKCMD $y";;
+ esac
+ shift
+done
+
+#Return code from compiler, linker.sh and finally this script...
+RES=0
+
+# Accumulated object names
+ACCUM_OBJECTS=""
+
+# A temporary object file location
+TMPOBJDIR=/tmp/tmpobj$$
+rm -rf $TMPOBJDIR
+mkdir $TMPOBJDIR
+
+
+for x in $SOURCES; do
+ # Compile each source
+ if [ $LINKING = false ]; then
+ # We should have an output defined, which is a directory
+ # or an object file
+ case $OUTFILE in
+ /*.o)
+ # Simple output, SOURCES should be one single
+ n=`echo $SOURCES | wc -w`;
+ if [ $n -gt 1 ]; then
+ echo "cc.sh:Error, multiple sources, one object output.";
+ exit 1;
+ else
+ output_filename=`cygpath -m $OUTFILE`;
+ fi;;
+ *.o)
+ # Relative path needs no translation
+ n=`echo $SOURCES | wc -w`
+ if [ $n -gt 1 ]; then
+ echo "cc.sh:Error, multiple sources, one object output."
+ exit 1
+ else
+ output_filename=$OUTFILE
+ fi;;
+ /*)
+ # Absolute directory
+ o=`echo $x | sed 's,.*/,,' | sed 's,\.c$,.o,'`
+ output_filename=`cygpath -m $OUTFILE`
+ output_filename="$output_filename/${o}";;
+ *)
+ # Relative_directory or empty string (.//x.o is valid)
+ o=`echo $x | sed 's,.*/,,' | sed 's,\.c$,.o,'`
+ output_filename="./${OUTFILE}/${o}";;
+ esac
+ else
+ # We are linking, which means we build objects in a temporary
+ # directory and link from there. We should retain the basename
+ # of each source to make examining the exe easier...
+ o=`echo $x | sed 's,.*/,,' | sed 's,\.c$,.o,'`
+ output_filename=$TMPOBJDIR/$o
+ ACCUM_OBJECTS="$ACCUM_OBJECTS $output_filename"
+ fi
+ # Now we know enough, lets try a compilation...
+ MPATH=`cygpath -m $x`
+ if [ $DEPENDING = true ]; then
+ output_flag="-MM"
+ elif [ $PREPROCESSING = true ]; then
+ output_flag="-E"
+ else
+ output_flag="-c -o `cygpath -m ${output_filename}`"
+ fi
+ params="$COMMON_CFLAGS $DEBUG_FLAGS $OPTIMIZE_FLAGS \
+ $CMD ${output_flag} $MPATH"
+ if [ "X$CC_SH_DEBUG_LOG" != "X" ]; then
+ echo cc.sh "$SAVE" >>$CC_SH_DEBUG_LOG
+ echo $MINGW_EXE_PATH/gcc $params >>$CC_SH_DEBUG_LOG
+ fi
+ eval $MINGW_EXE_PATH/gcc $params >$MSG_FILE 2>$ERR_FILE
+ RES=$?
+ if [ $PREPROCESSING = false -a $DEPENDING = false ]; then
+ cat $ERR_FILE >&2
+ cat $MSG_FILE
+ else
+ cat $ERR_FILE >&2
+ if [ $DEPENDING = true ]; then
+ cat $MSG_FILE | sed 's|\([a-z]\):/|/cygdrive/\1/|g'
+ else
+ cat $MSG_FILE
+ fi
+ fi
+ rm -f $ERR_FILE $MSG_FILE
+ if [ $RES != 0 ]; then
+ rm -rf $TMPOBJDIR
+ exit $RES
+ fi
+done
+
+#If we got here, we succeeded in compiling (if there were anything to compile)
+#The output filename should name an executable if we're linking
+if [ $LINKING = true ]; then
+ case $OUTFILE in
+ "")
+ # Use the first source name to name the executable
+ first_source=""
+ for x in $SOURCES; do first_source=$x; break; done;
+ if [ -n "$first_source" ]; then
+ e=`echo $x | sed 's,.*/,,' | sed 's,\.c$,.exe,'`;
+ out_spec="-o $e";
+ else
+ out_spec="";
+ fi;;
+ *)
+ out_spec="-o $OUTFILE";;
+ esac
+ # Descide which standard library to link against
+ case $MD in
+ -ML)
+ stdlib="-lLIBC";;
+ -MLd)
+ stdlib="-lLIBCD";;
+ -MD)
+ stdlib="-lMSVCRT";;
+ -MDd)
+ stdlib="-lMSVCRTD";;
+ -MT)
+ stdlib="-lLIBCMT";;
+ -MTd)
+ stdlib="-lLIBMTD";;
+ esac
+ # And finally call the next script to do the linking...
+ params="$out_spec $LINKCMD $stdlib"
+ eval ld.sh $ACCUM_OBJECTS $params
+ RES=$?
+fi
+rm -rf $TMPOBJDIR
+
+exit $RES
diff --git a/erts/etc/win32/cygwin_tools/mingw/coffix.c b/erts/etc/win32/cygwin_tools/mingw/coffix.c
new file mode 100644
index 0000000000..5dff030a69
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/mingw/coffix.c
@@ -0,0 +1,161 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2006-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+/*
+** This mini tool fixes an incompatibility between
+** Microsoft's tools, who dont like the virtual size being put in
+** the physical address field, but rely on the raw size field for
+** sizing the ".bss" section.
+** This fixes some of the problems with linking gcc compiled objects
+** together with MSVC dito.
+**
+** Courtesy DJ Delorie for describing the COFF file format on
+** http://www.delorie.com/djgpp/doc/coff/
+** The coff structures are fetched from Microsofts headers though.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <windows.h>
+#include <winnt.h> /* Structure definitions for PE (COFF) */
+
+static int dump_edit(char *filename, int edit);
+static int v_printf(char *format, ...);
+
+
+char *progname;
+int verbouse = 0;
+
+int main(int argc, char **argv)
+{
+ int findex = 1;
+ int edit = 0;
+ int ret;
+
+ progname = argv[0];
+ if (argc == 1) {
+ fprintf(stderr,"Format : %s [-e] [-v] <filename>\n", progname);
+ return 1;
+ }
+ for (findex = 1;
+ findex < argc && (*argv[findex] == '-' || *argv[findex] == '/');
+ ++findex)
+ switch (argv[findex][1]) {
+ case 'e':
+ case 'E':
+ edit = 1;
+ break;
+ case 'v':
+ case 'V':
+ verbouse = 1;
+ default:
+ fprintf(stderr, "%s: unknown option %s\n", progname, argv[findex]);
+ break;
+ }
+ if (findex == argc) {
+ fprintf(stderr,"%s: No filenames given.\n", progname);
+ return 1;
+ }
+ for(; findex < argc; ++findex)
+ if ((ret = dump_edit(argv[findex],edit)) != 0)
+ return ret;
+ return 0;
+}
+
+int dump_edit(char *filename, int edit)
+{
+ FILE *f = fopen(filename, (edit) ? "r+b" : "rb");
+ IMAGE_FILE_HEADER filhdr;
+ IMAGE_SECTION_HEADER scnhdr;
+ int i;
+
+ if (f == NULL) {
+ fprintf(stderr, "%s: cannot open %s.\n", progname, filename);
+ return 1;
+ }
+
+ if (fread(&filhdr, sizeof(filhdr), 1, f) == 0) {
+ fprintf(stderr,"%s: Could not read COFF header from %s,"
+ " is this a PE (COFF) file?\n", progname, filename);
+ fclose(f);
+ return 1;
+ }
+ v_printf("File: %s\n", filename);
+ v_printf("Magic number: 0x%08x\n", filhdr.Machine);
+ v_printf("Number of sections: %d\n",filhdr.NumberOfSections);
+
+ if (fseek(f, (long) filhdr.SizeOfOptionalHeader, SEEK_CUR) != 0) {
+ fprintf(stderr,"%s: Could not read COFF optional header from %s,"
+ " is this a PE (COFF) file?\n", progname, filename);
+ fclose(f);
+ return 1;
+ }
+
+ for (i = 0; i < filhdr.NumberOfSections; ++i) {
+ if (fread(&scnhdr, sizeof(scnhdr), 1, f) == 0) {
+ fprintf(stderr,"%s: Could not read section header from %s,"
+ " is this a PE (COFF) file?\n", progname, filename);
+ fclose(f);
+ return 1;
+ }
+ v_printf("Section %s:\n", scnhdr.Name);
+ v_printf("Physical address: 0x%08x\n", scnhdr.Misc.PhysicalAddress);
+ v_printf("Size: 0x%08x\n", scnhdr.SizeOfRawData);
+ if (scnhdr.Misc.PhysicalAddress != 0 &&
+ scnhdr.SizeOfRawData == 0) {
+ printf("Section header %s in file %s will confuse MSC linker, "
+ "virtual size is 0x%08x and raw size is 0\n",
+ scnhdr.Name, filename, scnhdr.Misc.PhysicalAddress,
+ scnhdr.SizeOfRawData);
+ if (edit) {
+ scnhdr.SizeOfRawData = scnhdr.Misc.PhysicalAddress;
+ scnhdr.Misc.PhysicalAddress = 0;
+ if (fseek(f, (long) -((long)sizeof(scnhdr)), SEEK_CUR) != 0 ||
+ fwrite(&scnhdr, sizeof(scnhdr), 1, f) == 0) {
+ fprintf(stderr,"%s: could not edit file %s.\n",
+ progname, filename);
+ fclose(f);
+ return 1;
+ }
+ printf("Edited object, virtual size is now 0, and "
+ "raw size is 0x%08x.\n", scnhdr.SizeOfRawData);
+ } else {
+ printf("Specify option '-e' to correct the problem.\n");
+ }
+ }
+ }
+ fclose(f);
+ return 0;
+}
+
+
+static int v_printf(char *format, ...)
+{
+ va_list ap;
+ int ret = 0;
+ if (verbouse) {
+ va_start(ap, format);
+ ret = vfprintf(stdout, format, ap);
+ va_end(ap);
+ }
+ return ret;
+}
+
diff --git a/erts/etc/win32/cygwin_tools/mingw/emu_cc.sh b/erts/etc/win32/cygwin_tools/mingw/emu_cc.sh
new file mode 100755
index 0000000000..f3865c8cae
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/mingw/emu_cc.sh
@@ -0,0 +1,90 @@
+#! /bin/sh
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2006-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+TOOLDIR=$ERL_TOP/erts/etc/win32/cygwin_tools/mingw
+COFFIX=$TOOLDIR/coffix
+WTOOLDIR=`(cygpath -d $TOOLDIR 2>/dev/null || cygpath -w $TOOLDIR)`
+
+# Do primitive 'make'
+newer_exe=`find $TOOLDIR -newer $COFFIX.c -name coffix.exe -print`
+if [ -z $newer_exe ]; then
+ echo recompiling $COFFIX.exe
+ cl.exe -Fe${WTOOLDIR}\\coffix.exe ${WTOOLDIR}\\coffix.c
+ rm -f $COFFIX.obj coffix.obj $COFFIX.pdb coffix.pdb
+fi
+
+# Try to find out the output filename and remove it from command line
+CMD=""
+OUTFILE=""
+INFILE=""
+SKIP_COFFIX=false
+while test -n "$1" ; do
+ x="$1"
+ case "$x" in
+ -o/*)
+ OUTFILE=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`;;
+ -o)
+ shift
+ OUTFILE=$1;;
+ -MM)
+ SKIP_COFFIX=true
+ CMD="$CMD \"$x\"";;
+ *.c)
+ INFILE="$INFILE $x";
+ CMD="$CMD \"$x\"";;
+ *)
+ CMD="$CMD \"$x\"";;
+ esac
+ shift
+done
+if [ -z "$INFILE" ]; then
+ echo 'emu_cc.sh: please give an input filename for the compiler' >&2
+ exit 1
+fi
+if [ -z "$OUTFILE" ]; then
+ OUTFILE=`echo $INFILE | sed 's,\.c$,.o,'`
+fi
+
+if [ $SKIP_COFFIX = false ]; then
+ n=`echo $INFILE | wc -w`;
+ if [ $n -gt 1 ]; then
+ echo "emu_cc.sh:Error, multiple sources, one object output.";
+ exit 1;
+ fi
+ TEMPFILE=/tmp/tmp_emu_cc$$.o
+ if [ "X$EMU_CC_SH_DEBUG_LOG" != "X" ]; then
+ echo "gcc -o $TEMPFILE -D__WIN32__ -DWIN32 -DWINDOWS -fomit-frame-pointer $CMD" >> $EMU_CC_SH_DEBUG_LOG 2>&1
+ fi
+ eval gcc -o $TEMPFILE -D__WIN32__ -DWIN32 -DWINDOWS -fomit-frame-pointer $CMD
+ RES=$?
+ if [ $RES = 0 ]; then
+ $COFFIX.exe -e `(cygpath -d $TEMPFILE 2>/dev/null || cygpath -w $TEMPFILE)`
+ RES=$?
+ if [ $RES = 0 ]; then
+ cp $TEMPFILE $OUTFILE
+ else
+ echo "emu_cc.sh: fatal: coffix failed!" >&2
+ fi
+ fi
+ rm -f $TEMPFILE
+ exit $RES
+else
+ eval gcc -D__WIN32__ -DWIN32 -DWINDOWS -fomit-frame-pointer $CMD 2>/dev/null
+ exit $?
+fi
diff --git a/erts/etc/win32/cygwin_tools/mingw/ld.sh b/erts/etc/win32/cygwin_tools/mingw/ld.sh
new file mode 100755
index 0000000000..145bd2fad9
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/mingw/ld.sh
@@ -0,0 +1,147 @@
+#! /bin/sh
+# set -x
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2006-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+# Save the command line for debug outputs
+SAVE="$@"
+kernel_libs="-lkernel32 -ladvapi32"
+gdi_libs="-lgdi32 -luser32 -lcomctl32 -lcomdlg32 -lshell32"
+DEFAULT_LIBRARIES="$kernel_libs $gdi_libs"
+
+CMD=""
+STDLIB=-lmsvcrt
+DEBUG_BUILD=false
+STDLIB_FORCED=false
+BUILD_DLL=false
+OUTPUT_FILENAME=""
+
+if [ -z "$MINGW_EXE_PATH" ]; then
+ echo "You have to set MINGW_EXE_PATH to run cc.sh" >&2
+ exit 1
+fi
+
+while test -n "$1" ; do
+ x="$1"
+ case "$x" in
+ -dll| -DLL | -shared)
+ BUILD_DLL=true;;
+ -L/*|-L.*)
+ y=`echo $x | sed 's,^-L\(.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ CMD="$CMD -L \"$MPATH\"";;
+ -lMSVCRT|-lmsvcrt)
+ STDLIB_FORCED=true;
+ STDLIB=-lmsvcrt;;
+ -lMSVCRTD|-lmsvcrtd)
+ STDLIB_FORCED=true;
+ STDLIB=-lmsvcrtd;;
+ -lLIBCMT|-llibcmt)
+ STDLIB_FORCED=true;
+ STDLIB=-llibcmt;;
+ -lLIBCMTD|-llibcmtd)
+ STDLIB_FORCED=true;
+ STDLIB=-llibcmtd;;
+ -lsocket)
+ DEFAULT_LIBRARIES="$DEFAULT_LIBRARIES -lws2_32";;
+ -l*)
+ y=`echo $x | sed 's,^-l\(.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ CMD="$CMD -l\"${MPATH}\"";;
+ -g)
+ DEBUG_BUILD=true;;
+ -pdb:none|-incremental:no)
+ ;;
+ -implib:*)
+ y=`echo $x | sed 's,^-implib:\(.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ CMD="$CMD -Xlinker --out-implib -Xlinker \"${MPATH}\"";;
+ -entry:*)
+ y=`echo $x | sed 's,^-entry:\(.*\),\1,g'`;
+ CMD="$CMD -Xlinker --entry -Xlinker _$y";;
+ -def:*)
+ ;;
+ ## Ignore -def: for now as ld.sh core dumps...
+ # y=`echo $x | sed 's,^-def:\(.*\),\1,g'`;
+ # MPATH=`cygpath -m $y`;
+ # CMD="$CMD -Xlinker --output-def -Xlinker \"${MPATH}\"";;
+ -o)
+ shift
+ MPATH=`cygpath -m $1`;
+ OUTPUT_FILENAME="$MPATH";;
+ -o/*)
+ y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ OUTPUT_FILENAME="$MPATH";;
+ /*)
+ MPATH=`cygpath -m $x`;
+ CMD="$CMD \"$MPATH\"";;
+ *)
+ y=`echo $x | sed 's,",\\\",g'`;
+ CMD="$CMD \"$y\"";;
+ esac
+ shift
+done
+if [ $DEBUG_BUILD = true ]; then
+ linktype="-g"
+ if [ $STDLIB_FORCED = false ]; then
+ STDLIB=-lmsvcrt #d?
+ fi
+else
+ linktype=
+fi
+
+if [ $BUILD_DLL = true ];then
+ case "$OUTPUT_FILENAME" in
+ *.exe|*.EXE)
+ echo "Warning, output set to .exe when building DLL" >&2
+ CMD="-shared -o \"$OUTPUT_FILENAME\" $CMD";;
+ *.dll|*.DLL)
+ CMD="-shared -o \"$OUTPUT_FILENAME\" $CMD";;
+ "")
+ CMD="-shared -o \"a.dll\" $CMD";;
+ *)
+ CMD="-shared -o \"${OUTPUT_FILENAME}.dll\" $CMD";;
+ esac
+else
+ case "$OUTPUT_FILENAME" in
+ *.exe|*.EXE)
+ CMD="-o \"$OUTPUT_FILENAME\" $CMD";;
+ *.dll|*.DLL)
+ echo "Warning, output set to .dll when building EXE" >&2
+ CMD="-o \"$OUTPUT_FILENAME\" $CMD";;
+ "")
+ CMD="-o \"a.exe\" $CMD";;
+ *)
+ CMD="-o \"${OUTPUT_FILENAME}.exe\" $CMD";;
+ esac
+fi
+
+p=$$
+CMD="$linktype $CMD $STDLIB $DEFAULT_LIBRARIES"
+if [ "X$LD_SH_DEBUG_LOG" != "X" ]; then
+ echo ld.sh "$SAVE" >>$LD_SH_DEBUG_LOG
+ echo $MINGW_EXE_PATH/gcc.exe $CMD >>$LD_SH_DEBUG_LOG
+fi
+eval $MINGW_EXE_PATH/gcc "$CMD" >/tmp/link.exe.${p}.1 2>/tmp/link.exe.${p}.2
+RES=$?
+#tail +2 /tmp/link.exe.${p}.2 >&2
+cat /tmp/link.exe.${p}.2 >&2
+cat /tmp/link.exe.${p}.1
+rm -f /tmp/link.exe.${p}.2 /tmp/link.exe.${p}.1
+exit $RES
diff --git a/erts/etc/win32/cygwin_tools/mingw/mc.sh b/erts/etc/win32/cygwin_tools/mingw/mc.sh
new file mode 100755
index 0000000000..873149172a
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/mingw/mc.sh
@@ -0,0 +1,89 @@
+#! /bin/sh
+# set -x
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2006-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+# Save the command line for debug outputs
+SAVE="$@"
+CMD=""
+OUTPUT_DIRNAME=""
+
+# Find the correct mc.exe. This could be done by the configure script,
+# But as we seldom use the resource compiler, it might as well be done here...
+if [ -z "$WINE_EXE_PATH" ]; then
+ echo "You have to set MINGW_EXE_PATH to run cc.sh" >&2
+ exit 1
+fi
+
+MCC="$WINE_EXE_PATH/wmc.exe -i"
+RCC="$WINE_EXE_PATH/wrc.exe -i"
+
+while test -n "$1" ; do
+ x="$1"
+ case "$x" in
+ -o)
+ shift
+ OUTPUT_DIRNAME="$1";;
+ -o/*)
+ y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`;
+ OUTPUT_DIRNAME="$y";;
+ -I)
+ shift
+ MPATH=`cygpath -m $1`;
+ CMD="$CMD -I\"$MPATH\"";;
+ -I/*)
+ y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ CMD="$CMD -I\"$MPATH\"";;
+ *)
+ MPATH=`cygpath -m -a $x`;
+ INFILE=$MPATH;;
+ #CMD="$CMD \"$MPATH\"";;
+ esac
+ shift
+done
+p=$$
+if [ "X$MC_SH_DEBUG_LOG" != "X" ]; then
+ echo mc.sh "$SAVE" >>$MC_SH_DEBUG_LOG
+ echo $MCC $INFILE $CMD >>$MC_SH_DEBUG_LOG
+fi
+if [ -n "$OUTPUT_DIRNAME" ]; then
+ cd $OUTPUT_DIRNAME
+ RES=$?
+ if [ "$RES" != "0" ]; then
+ echo "mc.sh: Error: could not cd to $OUTPUT_DIRNAME">&2
+ exit $RES
+ fi
+fi
+eval $MCC "$INFILE" "$CMD" >/tmp/mc.exe.${p}.1 2>/tmp/mc.exe.${p}.2
+RES=$?
+cat /tmp/mc.exe.${p}.2 >&2
+cat /tmp/mc.exe.${p}.1
+rm -f /tmp/mc.exe.${p}.2 /tmp/mc.exe.${p}.1
+if [ $RES -eq 0 ]; then
+ XINFILE=`echo $INFILE | sed 's,.*/\([^/]*\),\1,' | sed 's,.mc$,.rc,'`
+ if [ "X$MC_SH_DEBUG_LOG" != "X" ]; then
+ echo $RCC $XINFILE $CMD >>$MC_SH_DEBUG_LOG
+ fi
+ eval $RCC $XINFILE "$CMD" >/tmp/rc.exe.${p}.1 2>/tmp/rc.exe.${p}.2
+ RES=$?
+ cat /tmp/rc.exe.${p}.2 >&2
+ cat /tmp/rc.exe.${p}.1
+ rm -f /tmp/rc.exe.${p}.2 /tmp/rc.exe.${p}.1
+fi
+exit $RES
diff --git a/erts/etc/win32/cygwin_tools/mingw/rc.sh b/erts/etc/win32/cygwin_tools/mingw/rc.sh
new file mode 100755
index 0000000000..37296f9e9f
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/mingw/rc.sh
@@ -0,0 +1,94 @@
+#! /bin/sh
+# set -x
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2006-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+# Save the command line for debug outputs
+SAVE="$@"
+CMD=""
+OUTPUT_FILENAME=""
+
+if [ -z "$MINGW_EXE_PATH" ]; then
+ echo "You have to set MINGW_EXE_PATH to run rc.sh" >&2
+ exit 1
+fi
+
+
+# # Find the correct rc.exe. This could be done by the configure script,
+# # But as we seldom use the resource compiler, it might as well be done here...
+# RCC=""
+# save_ifs=$IFS
+# IFS=:
+# for p in $PATH; do
+# if [ -f $p/windres.exe ]; then
+# if [ -n "`$p/windres.exe --version 2>&1 | grep -i "GNU windres"`" ]; then
+# RCC=$p/windres.exe
+# fi
+# fi
+# done
+# IFS=$save_ifs
+
+RCC=$MINGW_EXE_PATH/windres.exe
+
+if [ -z "$RCC" ]; then
+ echo 'windres.exe not found!' >&2
+ exit 1
+fi
+
+while test -n "$1" ; do
+ x="$1"
+ case "$x" in
+ -o)
+ shift
+ MPATH=`cygpath -m $1`;
+ OUTPUT_FILENAME="$MPATH";;
+ -o/*)
+ y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ OUTPUT_FILENAME="$MPATH";;
+ -I)
+ shift
+ MPATH=`cygpath -m $1`;
+ CMD="$CMD -I\"$MPATH\"";;
+ -I/*)
+ y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ CMD="$CMD -I\"$MPATH\"";;
+ /*)
+ MPATH=`cygpath -m $x`;
+ CMD="$CMD \"$MPATH\"";;
+ *)
+ y=`echo $x | sed 's,",\\\",g'`;
+ CMD="$CMD \"$y\"";;
+ esac
+ shift
+done
+p=$$
+if [ -n "$OUTPUT_FILENAME" ]; then
+ CMD="-o $OUTPUT_FILENAME $CMD"
+fi
+if [ "X$RC_SH_DEBUG_LOG" != "X" ]; then
+ echo rc.sh "$SAVE" >>$RC_SH_DEBUG_LOG
+ echo windres.exe $CMD >>$RC_SH_DEBUG_LOG
+fi
+eval $RCC "$CMD" >/tmp/rc.exe.${p}.1 2>/tmp/rc.exe.${p}.2
+RES=$?
+cat /tmp/rc.exe.${p}.2 >&2
+cat /tmp/rc.exe.${p}.1
+rm -f /tmp/rc.exe.${p}.2 /tmp/rc.exe.${p}.1
+exit $RES
diff --git a/erts/etc/win32/cygwin_tools/vc/ar.sh b/erts/etc/win32/cygwin_tools/vc/ar.sh
new file mode 100755
index 0000000000..24d275b01a
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/vc/ar.sh
@@ -0,0 +1,47 @@
+#! /bin/sh
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2002-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+CMD=""
+while test -n "$1" ; do
+ x="$1"
+ case "$x" in
+ -out:)
+ shift
+ case "$1" in
+ /*)
+ MPATH=`cygpath -m $1`;;
+ *)
+ MPATH=$1;;
+ esac
+ CMD="$CMD -out:\"$MPATH\"";;
+ -out:/*)
+ y=`echo $x | sed 's,^-out:\(/.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ CMD="$CMD -out:\"$MPATH\"";;
+ /*)
+ MPATH=`cygpath -m $x`;
+ CMD="$CMD \"$MPATH\"";;
+ *)
+ y=`echo $x | sed 's,",\\\",g'`;
+ CMD="$CMD \"$y\"";;
+ esac
+ shift
+done
+
+eval lib.exe $CMD
diff --git a/erts/etc/win32/cygwin_tools/vc/cc.sh b/erts/etc/win32/cygwin_tools/vc/cc.sh
new file mode 100755
index 0000000000..4939465d08
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/vc/cc.sh
@@ -0,0 +1,321 @@
+#! /bin/sh
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2002-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+# Icky cl wrapper that does it's best to behave like a Unixish cc.
+# Made to work for Erlang builds and to make configure happy, not really
+# general I suspect.
+# set -x
+# Save the command line for debug outputs
+SAVE="$@"
+
+# Constants
+COMMON_CFLAGS="-nologo -D__WIN32__ -DWIN32 -DWINDOWS -D_WIN32 -DNT -D_CRT_SECURE_NO_DEPRECATE"
+
+# Variables
+# The stdout and stderr for the compiler
+MSG_FILE=/tmp/cl.exe.$$.1
+ERR_FILE=/tmp/cl.exe.$$.2
+
+# "Booleans" determined during "command line parsing"
+# If the stdlib option is explicitly passed to this program
+MD_FORCED=false
+# If we're preprocession (only) i.e. -E
+PREPROCESSING=false
+# If we're generating dependencies (implies preprocesing)
+DEPENDENCIES=false
+# If this is supposed to be a debug build
+DEBUG_BUILD=false
+# If this is supposed to be an optimized build (there can only be one...)
+OPTIMIZED_BUILD=false
+# If we're linking or only compiling
+LINKING=true
+
+# This data is accumulated during command line "parsing"
+# The stdlibrary option, default multithreaded dynamic
+MD=-MD
+# Flags for debug compilation
+DEBUG_FLAGS=""
+# Flags for optimization
+OPTIMIZE_FLAGS=""
+# The specified output filename (if any), may be either object or exe.
+OUTFILE=""
+# Unspecified command line options for the compiler
+CMD=""
+# All the c source files, in unix style
+SOURCES=""
+# All the options to pass to the linker, kept in Unix style
+LINKCMD=""
+
+
+# Loop through the parameters and set the above variables accordingly
+# Also convert some cygwin filenames to "mixed style" dito (understood by the
+# compiler very well), except for anything passed to the linker, that script
+# handles those and the sources, which are also kept unixish for now
+
+while test -n "$1" ; do
+ x="$1"
+ case "$x" in
+ -Wall)
+ ;;
+ -c)
+ LINKING=false;;
+ #CMD="$CMD -c";;
+ -MM)
+ PREPROCESSING=true;
+ LINKING=false;
+ DEPENDENCIES=true;;
+ -E)
+ PREPROCESSING=true;
+ LINKING=false;; # Obviously...
+ #CMD="$CMD -E";;
+ -Owx)
+ # Optimization hardcoded of wxErlang, needs to disable debugging too
+ OPTIMIZE_FLAGS="-Ob2ity -Gs -Zi";
+ DEBUG_FLAGS="";
+ DEBUG_BUILD=false;
+ if [ $MD_FORCED = false ]; then
+ MD=-MD;
+ fi
+ OPTIMIZED_BUILD=true;;
+ -O*)
+ # Optimization hardcoded, needs to disable debugging too
+ OPTIMIZE_FLAGS="-Ox -Zi";
+ DEBUG_FLAGS="";
+ DEBUG_BUILD=false;
+ if [ $MD_FORCED = false ]; then
+ MD=-MD;
+ fi
+ OPTIMIZED_BUILD=true;;
+ -g|-ggdb)
+ if [ $OPTIMIZED_BUILD = false ];then
+ # Hardcoded windows debug flags
+ DEBUG_FLAGS="-Z7";
+ if [ $MD_FORCED = false ]; then
+ MD=-MDd;
+ fi
+ LINKCMD="$LINKCMD -g";
+ DEBUG_BUILD=true;
+ fi;;
+ # Allow forcing of stdlib
+ -mt|-MT)
+ MD="-MT";
+ MD_FORCED=true;;
+ -md|-MD)
+ MD="-MD";
+ MD_FORCED=true;;
+ -ml|-ML)
+ MD="-ML";
+ MD_FORCED=true;;
+ -mdd|-MDD|-MDd)
+ MD="-MDd";
+ MD_FORCED=true;;
+ -mtd|-MTD|-MTd)
+ MD="-MTd";
+ MD_FORCED=true;;
+ -mld|-MLD|-MLd)
+ MD="-MLd";
+ MD_FORCED=true;;
+ -o)
+ shift;
+ OUTFILE="$1";;
+ -o*)
+ y=`echo $x | sed 's,^-[Io]\(.*\),\1,g'`;
+ OUTFILE="$y";;
+ -I/*)
+ y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`;
+ z=`echo $x | sed 's,^-\([Io]\)\(/.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ CMD="$CMD -$z\"$MPATH\"";;
+ -I*)
+ y=`echo $x | sed 's,",\\\",g'`;
+ CMD="$CMD $y";;
+ -D*)
+ y=`echo $x | sed 's,",\\\",g'`;
+ CMD="$CMD $y";;
+ -EH*)
+ y=`echo $x | sed 's,",\\\",g'`;
+ CMD="$CMD $y";;
+ -l*)
+ y=`echo $x | sed 's,^-l\(.*\),\1,g'`;
+ LINKCMD="$LINKCMD $x";;
+ /*.c)
+ SOURCES="$SOURCES $x";;
+ *.c)
+ SOURCES="$SOURCES $x";;
+ /*.cc)
+ SOURCES="$SOURCES $x";;
+ *.cc)
+ SOURCES="$SOURCES $x";;
+ /*.cpp)
+ SOURCES="$SOURCES $x";;
+ *.cpp)
+ SOURCES="$SOURCES $x";;
+ /*.o)
+ LINKCMD="$LINKCMD $x";;
+ *.o)
+ LINKCMD="$LINKCMD $x";;
+ *)
+ # Try to quote uninterpreted options
+ y=`echo $x | sed 's,",\\\",g'`;
+ LINKCMD="$LINKCMD $y";;
+ esac
+ shift
+done
+
+#Return code from compiler, linker.sh and finally this script...
+RES=0
+
+# Accumulated object names
+ACCUM_OBJECTS=""
+
+# A temporary object file location
+TMPOBJDIR=/tmp/tmpobj$$
+mkdir $TMPOBJDIR
+
+# Compile
+for x in $SOURCES; do
+ start_time=`date '+%s'`
+ # Compile each source
+ if [ $LINKING = false ]; then
+ # We should have an output defined, which is a directory
+ # or an object file
+ case $OUTFILE in
+ /*.o)
+ # Simple output, SOURCES should be one single
+ n=`echo $SOURCES | wc -w`;
+ if [ $n -gt 1 ]; then
+ echo "cc.sh:Error, multiple sources, one object output.";
+ exit 1;
+ else
+ output_filename=`cygpath -m $OUTFILE`;
+ fi;;
+ *.o)
+ # Relative path needs no translation
+ n=`echo $SOURCES | wc -w`
+ if [ $n -gt 1 ]; then
+ echo "cc.sh:Error, multiple sources, one object output."
+ exit 1
+ else
+ output_filename=$OUTFILE
+ fi;;
+ /*)
+ # Absolute directory
+ o=`echo $x | sed 's,.*/,,' | sed 's,\.c$,.o,'`
+ output_filename=`cygpath -m $OUTFILE`
+ output_filename="$output_filename/${o}";;
+ *)
+ # Relative_directory or empty string (.//x.o is valid)
+ o=`echo $x | sed 's,.*/,,' | sed 's,\.cp*$,.o,'`
+ output_filename="./${OUTFILE}/${o}";;
+ esac
+ else
+ # We are linking, which means we build objects in a temporary
+ # directory and link from there. We should retain the basename
+ # of each source to make examining the exe easier...
+ o=`echo $x | sed 's,.*/,,' | sed 's,\.c$,.o,'`
+ output_filename=$TMPOBJDIR/$o
+ ACCUM_OBJECTS="$ACCUM_OBJECTS $output_filename"
+ fi
+ # Now we know enough, lets try a compilation...
+ MPATH=`cygpath -m $x`
+ if [ $PREPROCESSING = true ]; then
+ output_flag="-E"
+ else
+ output_flag="-c -Fo`cygpath -m ${output_filename}`"
+ fi
+ params="$COMMON_CFLAGS $MD $DEBUG_FLAGS $OPTIMIZE_FLAGS \
+ $CMD ${output_flag} $MPATH"
+ if [ "X$CC_SH_DEBUG_LOG" != "X" ]; then
+ echo cc.sh "$SAVE" >>$CC_SH_DEBUG_LOG
+ echo cl.exe $params >>$CC_SH_DEBUG_LOG
+ fi
+ eval cl.exe $params >$MSG_FILE 2>$ERR_FILE
+ RES=$?
+ if test $PREPROCESSING = false; then
+ cat $ERR_FILE >&2
+ tail -n +2 $MSG_FILE
+ else
+ tail -n +2 $ERR_FILE >&2
+ if test $DEPENDENCIES = true; then
+ if test `grep -v $x $MSG_FILE | grep -c '#line'` != "0"; then
+ o=`echo $x | sed 's,.*/,,' | sed 's,\.cp*$,.o,'`
+ echo -n $o':'
+ # Some versions of cygpath does not read paths linewise
+ # but uses space as separator, why pathnames containing
+ # spaces need to be removed. To avoid different
+ # behaviours in different versions of cygwin, we would need to
+ # write our own cygpath replacement, but this will have to do
+ # for now...
+ cat $MSG_FILE | grep '#line' | grep -v $x | awk -F\" '{printf("%s\n",$2)}' | sort -u | grep -v " " | cygpath -f - -m -s | cygpath -f - | awk '{printf("\\\n %s ",$0)}'
+ echo
+ echo
+ after_sed=`date '+%s'`
+ echo Made dependencises for $x':' `expr $after_sed '-' $start_time` 's' >&2
+ fi
+ else
+ cat $MSG_FILE
+ fi
+ fi
+ rm -f $ERR_FILE $MSG_FILE
+ if [ $RES != 0 ]; then
+ rm -rf $TMPOBJDIR
+ exit $RES
+ fi
+done
+
+# If we got here, we succeeded in compiling (if there were anything to compile)
+# The output filename should name an executable if we're linking
+if [ $LINKING = true ]; then
+ case $OUTFILE in
+ "")
+ # Use the first source name to name the executable
+ first_source=""
+ for x in $SOURCES; do first_source=$x; break; done;
+ if [ -n "$first_source" ]; then
+ e=`echo $x | sed 's,.*/,,' | sed 's,\.c$,.exe,'`;
+ out_spec="-o $e";
+ else
+ out_spec="";
+ fi;;
+ *)
+ out_spec="-o $OUTFILE";;
+ esac
+ # Descide which standard library to link against
+ case $MD in
+ -ML)
+ stdlib="-lLIBC";;
+ -MLd)
+ stdlib="-lLIBCD";;
+ -MD)
+ stdlib="-lMSVCRT";;
+ -MDd)
+ stdlib="-lMSVCRTD";;
+ -MT)
+ stdlib="-lLIBCMT";;
+ -MTd)
+ stdlib="-lLIBMTD";;
+ esac
+ # And finally call the next script to do the linking...
+ params="$out_spec $LINKCMD $stdlib"
+ eval ld.sh $ACCUM_OBJECTS $params
+ RES=$?
+fi
+rm -rf $TMPOBJDIR
+
+exit $RES
diff --git a/erts/etc/win32/cygwin_tools/vc/cc_wrap.c b/erts/etc/win32/cygwin_tools/vc/cc_wrap.c
new file mode 100644
index 0000000000..18ecc31c17
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/vc/cc_wrap.c
@@ -0,0 +1,864 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2008-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+#include <dirent.h>
+#include <sys/cygwin.h>
+
+
+
+#ifdef CCP_POSIX_TO_WIN_A
+#define NEW_CYGPATH_INTERFACE
+#endif
+
+#ifdef NEW_CYGPATH_INTERFACE
+#define GET_WIN32_SIZE(Posix) \
+cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, (Posix), NULL, 0)
+#define CONVERT_TO_WIN32(Posix,Win32,Size) \
+cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, (Posix), \
+ (Win32), (Size))
+#else
+#define GET_WIN32_SIZE(Posix) PATH_MAX
+#define CONVERT_TO_WIN32(Posix,Win32,Size) \
+((cygwin32_conv_to_full_win32_path((Posix),(Win32)) >= 0) ? 0 : -1)
+#endif
+
+/*#define HARDDEBUG 1*/
+
+#ifdef HARDDEBUG
+#define DEBUGF(X) printf X
+#else
+#define DEBUGF(X) /* noop */
+#endif
+char *tmpobjdir = "";
+
+char *add_to(char *src,char *add) {
+ int len = strlen(src)+strlen(add)+1;
+ char *n;
+
+ if (strlen(src) == 0) {
+ n = malloc(len);
+ strcpy(n,add);
+ return n;
+ }
+ n = realloc(src,len);
+ strcat(n,add);
+ return n;
+}
+
+void maybe_cleanup(void)
+{
+ DIR *dir;
+ struct dirent *dent;
+ if (*tmpobjdir == '\0') {
+ return;
+ }
+ if (!(dir = opendir(tmpobjdir))) {
+ return;
+ }
+ while((dent = readdir(dir)) != NULL) {
+ char *fullname = add_to("",tmpobjdir);
+ fullname = add_to(fullname,"/");
+ fullname = add_to(fullname,dent->d_name);
+ unlink(fullname);
+ free(fullname);
+ }
+ closedir(dir);
+ rmdir(tmpobjdir);
+}
+
+
+
+
+void error(char *str)
+{
+ fprintf(stderr,"%s\n",str);
+ maybe_cleanup();
+ exit(1);
+}
+
+
+char **add_to_src(char **srcarr, char *add)
+{
+ int num;
+ if (srcarr == NULL) {
+ srcarr = malloc(sizeof(char *)*2);
+ srcarr[0]=malloc(strlen(add)+1);
+ strcpy(srcarr[0],add);
+ srcarr[1] = NULL;
+ } else {
+ for(num = 0; srcarr[num] != NULL; ++num)
+ ;
+ num +=1;
+ srcarr = realloc(srcarr,sizeof(char *)*(num+1));
+ srcarr[num-1] = malloc(strlen(add)+1);
+ strcpy(srcarr[num-1],add);
+ srcarr[num] = NULL;
+ }
+ return srcarr;
+}
+
+
+
+char *object_name(char *source) {
+ char *tmp = add_to("",source);
+ int j = strlen(tmp)-2;
+ if (j < 0) {
+ j = 0;
+ }
+ while(j>0 && tmp[j] != '.') {
+ --j;
+ }
+ if (tmp[j] == '.') {
+ ++j;
+ }
+ tmp[j++] = 'o';
+ tmp[j] = '\0';
+ return tmp;
+}
+
+char *exe_name(char *source) {
+ char *tmp = add_to("",source);
+ int j = strlen(tmp)-2;
+ if (j < 0) {
+ j = 0;
+ }
+ while(j>0 && tmp[j] != '.') {
+ --j;
+ }
+ if (tmp[j] == '.') {
+ ++j;
+ }
+ tmp[j] = '\0';
+ return add_to(tmp,"exe");
+}
+
+char *dyn_get_short(char *longp)
+{
+ int size;
+ char *shortp;
+ size = GetShortPathName(longp,NULL,0);
+ if (size <= 0) {
+ return NULL;
+ }
+ shortp = malloc(size);
+ if (GetShortPathName(longp,shortp,size) != size - 1) {
+ free(shortp);
+ return NULL;
+ }
+ return shortp;
+}
+
+char *do_cyp(char *posix)
+{
+ ssize_t size;
+ char *win32;
+ size = GET_WIN32_SIZE(posix);
+ char *ret = NULL;
+ if (size < 0) {
+ fprintf(stderr,"Could not cygpath %s, errno = %d\n",
+ posix,errno);
+ } else {
+ win32 = (char *) malloc (size);
+ if (CONVERT_TO_WIN32(posix,
+ win32, size)) {
+ fprintf(stderr,"Could not cygpath %s, errno = %d\n",
+ posix,errno);
+ } else {
+ char *w32_short = dyn_get_short(win32);
+ DEBUGF(("win32 = %s, w32_short = %s\n",win32, (w32_short == NULL) ? "NULL" : w32_short));
+ if (w32_short == NULL) {
+ char *rest = malloc(size);
+ char *first = malloc(size);
+ int x = 0;
+ int y = strlen(win32) - 1;
+ strcpy(first,win32);
+ while (w32_short == NULL) {
+ while ( y > 0 && first[y] != '\\') {
+ rest[x++] = first[y--];
+ }
+ if (y > 0) {
+ rest[x++] = first[y];
+ first[y--] = '\0';
+ } else {
+ break;
+ }
+ w32_short = dyn_get_short(first);
+ DEBUGF(("first = %s, w32_short = %s\n",first, (w32_short == NULL) ? "NULL" : w32_short));
+ }
+ if (w32_short != NULL) {
+ y = strlen(w32_short);
+ w32_short = realloc(w32_short,y+1+x);
+ /* spool back */
+ while ( x > 0) {
+ w32_short[y++] = rest[--x];
+ }
+ w32_short[y] = '\0';
+ } else {
+ w32_short = malloc(strlen(win32)+1);
+ strcpy(w32_short,win32); /* last resort */
+ }
+ free(first);
+ free(rest);
+ }
+ ret = w32_short;
+ while (*ret) {
+ if (*ret == '\\') {
+ *ret = '/';
+ }
+ ++ret;
+ }
+ ret = w32_short;
+ }
+ free(win32);
+ }
+ return ret;
+}
+
+
+
+char *save = "";
+
+void save_args(int argc, char **argv)
+{
+ int i;
+ for(i = 0; i < argc; ++i) {
+ save = add_to(save,argv[i]);
+ save = add_to(save," ");
+ }
+}
+
+char *progname="cc_wrap";
+
+int my_create_pipe(HANDLE *read_p, HANDLE *write_p)
+{
+ char name_buff[1000];
+ SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
+ static int counter = 0;
+
+ ++counter;
+
+ sprintf(name_buff,"\\\\.\\pipe\\%s_%d_%d",progname,getpid(),counter);
+ sa.bInheritHandle = FALSE;
+ if ((*read_p = CreateNamedPipe(name_buff,
+ PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
+ 1,
+ 0,
+ 0,
+ 2000,
+ &sa)) == INVALID_HANDLE_VALUE ||
+ *read_p == NULL) {
+ return 0;
+ }
+ sa.bInheritHandle = TRUE;
+ if ((*write_p = CreateFile(name_buff,
+ GENERIC_WRITE,
+ 0, /* No sharing */
+ &sa,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL)) == INVALID_HANDLE_VALUE ||
+ *write_p == NULL) {
+ CloseHandle(*read_p);
+ return 0;
+ }
+ return 1;
+}
+
+void forwardenv(void)
+{
+ char *(envs[]) = {"LIB","INCLUDE","LIBPATH", "LD_SH_DEBUG_LOG", NULL};
+ char **p = envs;
+ while (*p != NULL) {
+ char *val = getenv(*p);
+ if (val != NULL) {
+ SetEnvironmentVariable(*p,val);
+ }
+ ++p;
+ }
+}
+
+HANDLE do_run(char *commandline, HANDLE *out, HANDLE *err)
+{
+ STARTUPINFO start;
+ HANDLE write_pipe_stdout = NULL, read_pipe_stdout = NULL;
+ HANDLE write_pipe_stderr = NULL, read_pipe_stderr = NULL;
+ SECURITY_ATTRIBUTES pipe_security;
+ SECURITY_ATTRIBUTES attr;
+ PROCESS_INFORMATION info;
+
+ memset(&start,0,sizeof(start));
+ memset(&pipe_security,0,sizeof(pipe_security));
+ memset(&attr,0,sizeof(attr));
+ memset(&info,0,sizeof(info));
+
+ pipe_security.nLength = sizeof(pipe_security);
+ pipe_security.lpSecurityDescriptor = NULL;
+ pipe_security.bInheritHandle = TRUE;
+
+ if(!my_create_pipe(&read_pipe_stdout,&write_pipe_stdout)){
+ error("Could not create stdout pipes!");
+ }
+ if(!my_create_pipe(&read_pipe_stderr,&write_pipe_stderr)){
+ error("Could not create stderr pipes!");
+ }
+ start.cb = sizeof (start);
+ start.dwFlags = STARTF_USESHOWWINDOW;
+ start.wShowWindow = SW_HIDE;
+ start.hStdOutput = write_pipe_stdout;
+ start.hStdError = write_pipe_stderr;
+ start.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ start.dwFlags |= STARTF_USESTDHANDLES;
+
+ attr.nLength = sizeof(attr);
+ attr.lpSecurityDescriptor = NULL;
+ attr.bInheritHandle = TRUE;
+ forwardenv(); /* Cygwin and windows environment variables... sigh... */
+ if(!CreateProcess(NULL,
+ commandline,
+ &attr,
+ NULL,
+ TRUE,
+ CREATE_DEFAULT_ERROR_MODE,
+ NULL,
+ NULL,
+ &start,
+ &info)){
+ fprintf(stderr,"Could not run %s, last error: %d\n",commandline,GetLastError());
+ error("Could not create process");
+ }
+ *out = read_pipe_stdout;
+ *err = read_pipe_stderr;
+ CloseHandle(write_pipe_stdout);
+ CloseHandle(write_pipe_stderr);
+ return info.hProcess;
+}
+#define HANDLE_STDOUT 0
+#define HANDLE_STDERR 1
+#define HANDLE_PROC 2
+
+#ifdef HARDDEBUG
+char *prefix = "";
+#endif
+
+int handle_overlapped(HANDLE fd, OVERLAPPED *ovp, char *buffer,
+ int bufflen, int get_old, FILE *whereto, int *skip)
+{
+ DWORD res,read,err;
+ char *ptr;
+
+ DEBUGF(("In handle_overlapped(%d,0x%08x,0x%08x,%d,%d), prefix = %s\n",
+ fd,ovp,buffer,bufflen,get_old,prefix));
+ /* h�mta resultat av gamla f�rst */
+ if (get_old) {
+ res = GetOverlappedResult(fd,ovp,&read,TRUE);
+ DEBUGF(("read = %d, res = %d, GetLastError() = %d\n",read,res,GetLastError()));
+ if (!res) {
+ return 0;
+ }
+ buffer[read] = '\0';
+ ptr = buffer;
+ while(*skip && *ptr != '\0') {
+ if (*ptr == '\n') {
+ --(*skip);
+ }
+ ++ptr;
+ }
+ if(*ptr != '\0') {
+ fprintf(whereto,"%s",ptr);
+ }
+ }
+
+ ResetEvent(ovp->hEvent);
+
+ for(;;) {
+ res = ReadFile(fd,buffer,bufflen-1,&read,ovp);
+
+ if (!res) {
+ err = GetLastError();
+ if (err == ERROR_IO_PENDING) {
+ DEBUGF(("Error I/O Pending\n"));
+ return 1;
+ }
+ DEBUGF(("ReadFileFailed for %s, %d\n",prefix,err));
+ return 0;
+ }
+ buffer[read] = '\0';
+ ptr = buffer;
+ while(*skip && *ptr != '\0') {
+ if (*ptr == '\n') {
+ --(*skip);
+ }
+ ++ptr;
+ }
+ if(*ptr != '\0') {
+ fprintf(whereto,"%s",ptr);
+ }
+ }
+}
+
+
+int run(char *commandline,int skipout,int skiperr)
+{
+ HANDLE harr[3];
+ HANDLE real_stdout,real_stderr;
+ OVERLAPPED ov_out,ov_err;
+ char outbuff[1024],errbuff[1024];
+ DWORD ret,exitcode;
+ HANDLE wait[3];
+ int map[3];
+ DWORD nwait = 3;
+ int i,j;
+ unsigned living_handles = 0x7;
+
+ harr[HANDLE_STDOUT] = CreateEvent(NULL,
+ TRUE,
+ FALSE, /*not signalled */
+ NULL);
+ harr[HANDLE_STDERR] = CreateEvent(NULL,
+ TRUE,
+ FALSE,/*not signalled */
+ NULL);
+
+ memset(&ov_out,0,sizeof(ov_out));
+ memset(&ov_err,0,sizeof(ov_err));
+
+ ov_out.hEvent = harr[HANDLE_STDOUT];
+ ov_err.hEvent = harr[HANDLE_STDERR];
+
+ harr[HANDLE_PROC] = do_run(commandline,&real_stdout,&real_stderr);
+
+#ifdef HARDDEBUG
+ prefix = "STDOUT";
+#endif
+ handle_overlapped(real_stdout,&ov_out,outbuff,1024,0,stdout,&skipout);
+#ifdef HARDDEBUG
+ prefix = "STDERR";
+#endif
+ handle_overlapped(real_stderr,&ov_err,errbuff,1024,0,stderr,&skiperr);
+
+ for(;;) {
+ nwait = 0;
+ for(i=0;i<3;++i) {
+ if ((living_handles & (1U << i))) {
+ map[nwait] = i;
+ wait[nwait++] = harr[i];
+ }
+ }
+
+ ret = WaitForMultipleObjects(nwait,
+ wait,
+ FALSE,
+ INFINITE);
+ DEBUGF(("Wait returned %d\n",ret));
+
+ if (ret == WAIT_FAILED) {
+ error("Wait failed");
+ }
+
+ ret -= WAIT_OBJECT_0;
+
+ switch (map[ret]) {
+ case HANDLE_PROC:
+
+ DEBUGF(("Process died!\n"));
+ GetExitCodeProcess(harr[HANDLE_PROC],&exitcode);
+ if ((living_handles &= (~(1U<<HANDLE_PROC))) == 0) {
+ goto done;
+ }
+ --nwait;
+ break;
+ case HANDLE_STDOUT:
+#ifdef HARDDEBUG
+ prefix = "STDOUT";
+#endif
+ if (!handle_overlapped(real_stdout,&ov_out, outbuff,1024,1,stdout,&skipout)) {
+ if ((living_handles &= (~(1U<<HANDLE_STDOUT))) == 0) {
+ goto done;
+ }
+ }
+ break;
+ case HANDLE_STDERR:
+#ifdef HARDDEBUG
+ prefix = "STDERR";
+#endif
+ if (!handle_overlapped(real_stderr,&ov_err, errbuff,1024,1,stderr,&skiperr)){
+ if ((living_handles &= (~(1U<<HANDLE_STDERR))) == 0) {
+ goto done;
+ }
+ }
+ break;
+ default:
+ error("Unexpected wait result");
+ }
+ }
+ done:
+ CloseHandle(harr[HANDLE_PROC]);
+ CloseHandle(harr[HANDLE_STDOUT]);
+ CloseHandle(harr[HANDLE_STDERR]);
+ CloseHandle(real_stdout);
+ CloseHandle(real_stderr);
+ return (int) exitcode;
+}
+
+int main(int argc, char **argv)
+{
+ int i;
+ int x;
+ char *s;
+ char *mpath;
+ char *debuglog;
+ FILE *debugfile;
+
+ char *common_cflags="-nologo -D__WIN32__ -DWIN32 -DWINDOWS -D_WIN32 -DNT -D_CRT_SECURE_NO_DEPRECATE";
+ char *md = "-MD";
+ char *debug_flags = "";
+ char *optimize_flags = "";
+ char *outfile = "";
+ char *cmd = "";
+ char **sources = NULL;
+ char *accum_objects = "";
+ char *linkcmd = "";
+
+ int md_forced = 0;
+ int preprocessing = 0;
+ int debug_build = 0;
+ int optimized_build = 0;
+ int linking = 1;
+ int retval;
+
+ save_args(argc,argv);
+
+ for(i = 1; i < argc; ++i) {
+ if (argv[i][0] == '-') {
+ char *opt = argv[i]+1;
+ switch(*opt) {
+ case 'W':
+ if(strcmp(opt,"Wall")) {
+ goto filename;
+ }
+ break;
+ case 'c':
+ if(strlen(opt) > 1) {
+ goto filename;
+ }
+ linking = 0;
+ break;
+ case 'E':
+ if(strlen(opt) > 1) {
+ if (opt[1] == 'H') {
+ cmd = add_to(cmd," ");
+ cmd = add_to(cmd,opt);
+ } else {
+ goto filename;
+ }
+ }
+ preprocessing = 1;
+ linking = 0;
+ break;
+ case 'O':
+ /* ignore what opt is requested, set hard */
+ optimize_flags = "-Ox -Zi";
+ debug_flags = "";
+ debug_build = 0;
+ if (!md_forced) {
+ md = "-MD";
+ }
+ optimized_build = 1;
+ break;
+ case 'g':
+ if (strcmp(opt,"g") && strcmp(opt,"ggdb")) {
+ goto filename;
+ }
+ if (!optimized_build) {
+ debug_flags = "-Z7";
+ if (!md_forced) {
+ md = "-MDd";
+ }
+ linkcmd = add_to(linkcmd," -g");
+ debug_build = 1;
+ }
+ break;
+ case 'm':
+ case 'M':
+ if(!strcmp(opt,"mt") || !strcmp(opt,"MT")) {
+ md = "-MT";
+ } else if (!strcmp(opt,"md") || !strcmp(opt,"MD")) {
+ md = "-MD";
+ } else if (!strcmp(opt,"ml") || !strcmp(opt,"ML")) {
+ md = "-ML";
+ } else if (!strcmp(opt,"mdd") || !strcmp(opt,"MDd") ||
+ !strcmp(opt,"MDD")) {
+ md = "-MDd";
+ } else if (!strcmp(opt,"mtd") || !strcmp(opt,"MTd") ||
+ !strcmp(opt,"MTD")) {
+ md = "-MTd";
+ } else if (!strcmp(opt,"mld") || !strcmp(opt,"MLd") ||
+ !strcmp(opt,"MLD")) {
+ md = "-MLd";
+ } else {
+ goto filename;
+ }
+ md_forced = 1;
+ break;
+ case 'o':
+ if (!strcmp(opt,"o")) {
+ ++i;
+ if (i >= argc) {
+ error("-o without filename");
+ }
+ outfile = argv[i];
+ } else {
+ outfile = opt+1;
+ }
+ break;
+ case 'I':
+ if(opt[1] == '/') {
+ mpath = do_cyp(opt+1);
+ cmd = add_to(cmd," -I\"");
+ cmd = add_to(cmd,mpath);
+ cmd = add_to(cmd,"\"");
+ free(mpath);
+ } else {
+ cmd = add_to(cmd," ");
+ cmd = add_to(cmd,opt);
+ }
+ break;
+ case 'D':
+ cmd = add_to(cmd," -");
+ cmd = add_to(cmd,opt);
+ case 'l':
+ linkcmd = add_to(linkcmd," -");
+ linkcmd = add_to(linkcmd,opt);
+ break;
+ default:
+ goto filename;
+ }
+ continue;
+ }
+ filename:
+ s = argv[i];
+ x = strlen(s);
+ if (x > 1 && s[x-1] == 'c' && s[x-2] == '.') {
+ /* C source */
+ sources = add_to_src(sources,s);
+ } else if (x > 3 && !strcmp(s + (x - 4),".cpp")) {
+ /* C++ */
+ sources = add_to_src(sources,s);
+ } else if (x > 1 && s[x-1] == 'o' && s[x-2] == '.') {
+ linkcmd = add_to(linkcmd," ");
+ linkcmd = add_to(linkcmd,s);
+ } else {
+ /* Pass rest to linker */
+ linkcmd = add_to(linkcmd," ");
+ linkcmd = add_to(linkcmd,s);
+ }
+ }
+ if ((debuglog = getenv("CC_SH_DEBUG_LOG")) != NULL) {
+ debugfile = fopen(debuglog,"wb+");
+ if (debugfile) {
+ fprintf(debugfile,"----------------\n");
+ }
+ } else {
+ debugfile = NULL;
+ }
+
+ tmpobjdir = add_to("","/tmp/tmpobj");
+ {
+ char pidstr[100];
+ pid_t pid = getpid();
+ sprintf(pidstr,"%d",pid);
+ tmpobjdir = add_to(tmpobjdir,pidstr);
+ }
+ mkdir(tmpobjdir,0777);
+ if (sources != NULL) {
+ char *output_filename;
+ char *output_flag;
+ char *params;
+ for (i=0;sources[i] != NULL; ++i) {
+ if (!linking) {
+ int x = strlen(outfile);
+ if (x > 1 && outfile[x-1] == 'o' && outfile[x-2] == '.') {
+ if (*outfile != '/') {
+ /* non absolute object */
+ if (i > 0) {
+ error("Single object multiple sources");
+ }
+ output_filename = add_to("",outfile);
+ } else {
+ if (i > 0) {
+ error("Single object multiple sources");
+ }
+ output_filename = do_cyp(outfile);
+ }
+ } else {
+ char *tmp = object_name(sources[i]);
+
+ /*fprintf(stderr,"sources[i] = %s\ntmp = %s\n",
+ sources[i],tmp);*/
+
+ if (!x || outfile[0] != '/') {
+ /* non absolute directory */
+ output_filename = add_to("",outfile);
+ } else {
+ output_filename = do_cyp(outfile);
+ }
+ /*fprintf(stderr,"output_filename = %s\n",output_filename);*/
+ if (*output_filename != '\0') {
+ output_filename = add_to(output_filename,"/");
+ }
+ output_filename = add_to(output_filename,tmp);
+ free(tmp);
+ }
+ } else {
+ char *tmp = object_name(sources[i]);
+ output_filename = add_to("",tmpobjdir);
+ output_filename = add_to(output_filename,"/");
+ output_filename = add_to(output_filename,tmp);
+ accum_objects = add_to(accum_objects," ");
+ accum_objects = add_to(accum_objects,output_filename);
+ /* reform to dos path */
+ free(output_filename);
+ output_filename = do_cyp(tmpobjdir);
+ output_filename = add_to(output_filename,"/");
+ output_filename = add_to(output_filename,tmp);
+ }
+ mpath = do_cyp(sources[i]);
+ if (preprocessing) {
+ output_flag = add_to("","-E");
+ } else {
+ output_flag = add_to("","-c -Fo");
+ output_flag = add_to(output_flag,output_filename);
+ }
+ params = add_to("","cl.exe ");
+ params = add_to(params,common_cflags);
+ params = add_to(params," ");
+ params = add_to(params,md);
+ params = add_to(params," ");
+ params = add_to(params,debug_flags);
+ params = add_to(params," ");
+ params = add_to(params,optimize_flags);
+ params = add_to(params," ");
+ params = add_to(params,cmd);
+ params = add_to(params," ");
+ params = add_to(params,output_flag);
+ params = add_to(params," ");
+ params = add_to(params,mpath);
+ free(output_filename);
+ free(output_flag);
+ free(mpath);
+
+ if (debugfile) {
+ fprintf(debugfile,"%s\n",save);
+ fprintf(debugfile,"%s\n",params);
+ }
+ if (preprocessing) {
+ retval = run(params,0,1);
+ } else {
+ retval = run(params,1,0);
+ }
+ if (retval != 0) {
+ maybe_cleanup();
+ return retval;
+ }
+ free(params);
+ }
+ }
+ if (linking) {
+ char *out_spec;
+ char *stdlib;
+ char *params;
+ if (strlen(outfile) == 0) {
+ if (sources != NULL && sources[0] != NULL) {
+ char *tmp = exe_name(sources[0]);
+ out_spec = add_to("","-o ");
+ out_spec = add_to(out_spec,tmp);
+ free(tmp);
+ } else {
+ out_spec = add_to("","");
+ }
+ } else {
+ out_spec = add_to("","-o ");
+ out_spec = add_to(out_spec,outfile);
+ }
+ if (!strcmp(md,"-ML")) {
+ stdlib="-lLIBC";
+ } else if (!strcmp(md,"-MLd")) {
+ stdlib="-lLIBCD";
+ } else if (!strcmp(md,"-MD")) {
+ stdlib="-lMSVCRT";
+ } else if (!strcmp(md,"-MDd")) {
+ stdlib="-lMSVCRTD";
+ } else if (!strcmp(md,"-MT")) {
+ stdlib="-lLIBCMT";
+ } else if (!strcmp(md,"-MTd")) {
+ stdlib="-lLIBMTD";
+ } else {
+ stdlib = "";
+ }
+#if 0
+ params = add_to("","bash ld.sh ");
+#else
+ params = add_to("","ld_wrap.exe ");
+#endif
+ params = add_to(params,accum_objects);
+ params = add_to(params," ");
+ params = add_to(params,out_spec);
+ params = add_to(params," ");
+ params = add_to(params,linkcmd);
+ params = add_to(params," ");
+ params = add_to(params,stdlib);
+ free(out_spec);
+ free(accum_objects);
+ if (debugfile) {
+ fprintf(debugfile,"%s\n",params);
+ }
+ if (retval = run(params,0,0) != 0) {
+ maybe_cleanup();
+ return retval;
+ }
+ free(params);
+ }
+ maybe_cleanup();
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/erts/etc/win32/cygwin_tools/vc/coffix.c b/erts/etc/win32/cygwin_tools/vc/coffix.c
new file mode 100644
index 0000000000..dee0132a61
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/vc/coffix.c
@@ -0,0 +1,161 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1999-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+/*
+** This mini tool fixes an incompatibility between
+** Microsoft's tools, who dont like the virtual size being put in
+** the physical address field, but rely on the raw size field for
+** sizing the ".bss" section.
+** This fixes some of the problems with linking gcc compiled objects
+** together with MSVC dito.
+**
+** Courtesy DJ Delorie for describing the COFF file format on
+** http://www.delorie.com/djgpp/doc/coff/
+** The coff structures are fetched from Microsofts headers though.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <windows.h>
+#include <winnt.h> /* Structure definitions for PE (COFF) */
+
+static int dump_edit(char *filename, int edit);
+static int v_printf(char *format, ...);
+
+
+char *progname;
+int verbouse = 0;
+
+int main(int argc, char **argv)
+{
+ int findex = 1;
+ int edit = 0;
+ int ret;
+
+ progname = argv[0];
+ if (argc == 1) {
+ fprintf(stderr,"Format : %s [-e] [-v] <filename>\n", progname);
+ return 1;
+ }
+ for (findex = 1;
+ findex < argc && (*argv[findex] == '-' || *argv[findex] == '/');
+ ++findex)
+ switch (argv[findex][1]) {
+ case 'e':
+ case 'E':
+ edit = 1;
+ break;
+ case 'v':
+ case 'V':
+ verbouse = 1;
+ default:
+ fprintf(stderr, "%s: unknown option %s\n", progname, argv[findex]);
+ break;
+ }
+ if (findex == argc) {
+ fprintf(stderr,"%s: No filenames given.\n", progname);
+ return 1;
+ }
+ for(; findex < argc; ++findex)
+ if ((ret = dump_edit(argv[findex],edit)) != 0)
+ return ret;
+ return 0;
+}
+
+int dump_edit(char *filename, int edit)
+{
+ FILE *f = fopen(filename, (edit) ? "r+b" : "rb");
+ IMAGE_FILE_HEADER filhdr;
+ IMAGE_SECTION_HEADER scnhdr;
+ int i;
+
+ if (f == NULL) {
+ fprintf(stderr, "%s: cannot open %s.\n", progname, filename);
+ return 1;
+ }
+
+ if (fread(&filhdr, sizeof(filhdr), 1, f) == 0) {
+ fprintf(stderr,"%s: Could not read COFF header from %s,"
+ " is this a PE (COFF) file?\n", progname, filename);
+ fclose(f);
+ return 1;
+ }
+ v_printf("File: %s\n", filename);
+ v_printf("Magic number: 0x%08x\n", filhdr.Machine);
+ v_printf("Number of sections: %d\n",filhdr.NumberOfSections);
+
+ if (fseek(f, (long) filhdr.SizeOfOptionalHeader, SEEK_CUR) != 0) {
+ fprintf(stderr,"%s: Could not read COFF optional header from %s,"
+ " is this a PE (COFF) file?\n", progname, filename);
+ fclose(f);
+ return 1;
+ }
+
+ for (i = 0; i < filhdr.NumberOfSections; ++i) {
+ if (fread(&scnhdr, sizeof(scnhdr), 1, f) == 0) {
+ fprintf(stderr,"%s: Could not read section header from %s,"
+ " is this a PE (COFF) file?\n", progname, filename);
+ fclose(f);
+ return 1;
+ }
+ v_printf("Section %s:\n", scnhdr.Name);
+ v_printf("Physical address: 0x%08x\n", scnhdr.Misc.PhysicalAddress);
+ v_printf("Size: 0x%08x\n", scnhdr.SizeOfRawData);
+ if (scnhdr.Misc.PhysicalAddress != 0 &&
+ scnhdr.SizeOfRawData == 0) {
+ printf("Section header %s in file %s will confuse MSC linker, "
+ "virtual size is 0x%08x and raw size is 0\n",
+ scnhdr.Name, filename, scnhdr.Misc.PhysicalAddress,
+ scnhdr.SizeOfRawData);
+ if (edit) {
+ scnhdr.SizeOfRawData = scnhdr.Misc.PhysicalAddress;
+ scnhdr.Misc.PhysicalAddress = 0;
+ if (fseek(f, (long) -((long)sizeof(scnhdr)), SEEK_CUR) != 0 ||
+ fwrite(&scnhdr, sizeof(scnhdr), 1, f) == 0) {
+ fprintf(stderr,"%s: could not edit file %s.\n",
+ progname, filename);
+ fclose(f);
+ return 1;
+ }
+ printf("Edited object, virtual size is now 0, and "
+ "raw size is 0x%08x.\n", scnhdr.SizeOfRawData);
+ } else {
+ printf("Specify option '-e' to correct the problem.\n");
+ }
+ }
+ }
+ fclose(f);
+ return 0;
+}
+
+
+static int v_printf(char *format, ...)
+{
+ va_list ap;
+ int ret = 0;
+ if (verbouse) {
+ va_start(ap, format);
+ ret = vfprintf(stdout, format, ap);
+ va_end(ap);
+ }
+ return ret;
+}
+
diff --git a/erts/etc/win32/cygwin_tools/vc/emu_cc.sh b/erts/etc/win32/cygwin_tools/vc/emu_cc.sh
new file mode 100755
index 0000000000..c74c35111b
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/vc/emu_cc.sh
@@ -0,0 +1,90 @@
+#! /bin/sh
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2002-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+TOOLDIR=$ERL_TOP/erts/etc/win32/cygwin_tools/vc
+COFFIX=$TOOLDIR/coffix
+WTOOLDIR=`(cygpath -d $TOOLDIR 2>/dev/null || cygpath -w $TOOLDIR)`
+
+# Do primitive 'make'
+newer_exe=`find $TOOLDIR -newer $COFFIX.c -name coffix.exe -print`
+if [ -z $newer_exe ]; then
+ echo recompiling $COFFIX.exe
+ cl.exe -Fe${WTOOLDIR}\\coffix.exe ${WTOOLDIR}\\coffix.c
+ rm -f $COFFIX.obj coffix.obj $COFFIX.pdb coffix.pdb
+fi
+
+# Try to find out the output filename and remove it from command line
+CMD=""
+OUTFILE=""
+INFILE=""
+SKIP_COFFIX=false
+while test -n "$1" ; do
+ x="$1"
+ case "$x" in
+ -o/*)
+ OUTFILE=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`;;
+ -o)
+ shift
+ OUTFILE=$1;;
+ -MM)
+ SKIP_COFFIX=true
+ CMD="$CMD \"$x\"";;
+ *.c)
+ INFILE="$INFILE $x";
+ CMD="$CMD \"$x\"";;
+ *)
+ CMD="$CMD \"$x\"";;
+ esac
+ shift
+done
+if [ -z "$INFILE" ]; then
+ echo 'emu_cc.sh: please give an input filename for the compiler' >&2
+ exit 1
+fi
+if [ -z "$OUTFILE" ]; then
+ OUTFILE=`echo $INFILE | sed 's,\.c$,.o,'`
+fi
+
+if [ $SKIP_COFFIX = false ]; then
+ n=`echo $INFILE | wc -w`;
+ if [ $n -gt 1 ]; then
+ echo "emu_cc.sh:Error, multiple sources, one object output.";
+ exit 1;
+ fi
+ TEMPFILE=/tmp/tmp_emu_cc$$.o
+ if [ "X$EMU_CC_SH_DEBUG_LOG" != "X" ]; then
+ echo "gcc -o $TEMPFILE -D__WIN32__ -DWIN32 -DWINDOWS -fomit-frame-pointer $CMD" >> $EMU_CC_SH_DEBUG_LOG 2>&1
+ fi
+ eval gcc -o $TEMPFILE -D__WIN32__ -DWIN32 -DWINDOWS -fomit-frame-pointer $CMD
+ RES=$?
+ if [ $RES = 0 ]; then
+ $COFFIX.exe -e `(cygpath -d $TEMPFILE 2>/dev/null || cygpath -w $TEMPFILE)`
+ RES=$?
+ if [ $RES = 0 ]; then
+ cp $TEMPFILE $OUTFILE
+ else
+ echo "emu_cc.sh: fatal: coffix failed!" >&2
+ fi
+ fi
+ rm -f $TEMPFILE
+ exit $RES
+else
+ eval gcc -D__WIN32__ -DWIN32 -DWINDOWS -fomit-frame-pointer -fno-tree-copyrename $CMD 2>/dev/null
+ exit $?
+fi
diff --git a/erts/etc/win32/cygwin_tools/vc/ld.sh b/erts/etc/win32/cygwin_tools/vc/ld.sh
new file mode 100755
index 0000000000..ac39bf871c
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/vc/ld.sh
@@ -0,0 +1,192 @@
+#! /bin/sh
+# set -x
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2002-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+# Save the command line for debug outputs
+SAVE="$@"
+kernel_libs="kernel32.lib advapi32.lib"
+gdi_libs="gdi32.lib user32.lib comctl32.lib comdlg32.lib shell32.lib"
+DEFAULT_LIBRARIES="$kernel_libs $gdi_libs"
+
+CMD=""
+STDLIB=MSVCRT.LIB
+DEBUG_BUILD=false
+STDLIB_FORCED=false
+BUILD_DLL=false
+OUTPUT_FILENAME=""
+
+while test -n "$1" ; do
+ x="$1"
+ case "$x" in
+ -dll| -DLL)
+ BUILD_DLL=true;;
+ -L/*|-L.*)
+ y=`echo $x | sed 's,^-L\(.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ CMD="$CMD -libpath:\"$MPATH\"";;
+ -lMSVCRT|-lmsvcrt)
+ STDLIB_FORCED=true;
+ STDLIB=MSVCRT.LIB;;
+ -lMSVCRTD|-lmsvcrtd)
+ STDLIB_FORCED=true;
+ STDLIB=MSVCRTD.LIB;;
+ -lLIBCMT|-llibcmt)
+ STDLIB_FORCED=true;
+ STDLIB=LIBCMT.LIB;;
+ -lLIBCMTD|-llibcmtd)
+ STDLIB_FORCED=true;
+ STDLIB=LIBCMTD.LIB;;
+ -lsocket)
+ DEFAULT_LIBRARIES="$DEFAULT_LIBRARIES WS2_32.LIB";;
+ -l*)
+ y=`echo $x | sed 's,^-l\(.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ CMD="$CMD \"${MPATH}.lib\"";;
+ -g)
+ DEBUG_BUILD=true;;
+ -pdb:none|-incremental:no)
+ ;;
+ -implib:*)
+ y=`echo $x | sed 's,^-implib:\(.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ CMD="$CMD -implib:\"${MPATH}\"";;
+ -def:*)
+ y=`echo $x | sed 's,^-def:\(.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ CMD="$CMD -def:\"${MPATH}\"";;
+ -o)
+ shift
+ MPATH=`cygpath -m $1`;
+ OUTPUT_FILENAME="$MPATH";;
+ -o/*)
+ y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ OUTPUT_FILENAME="$MPATH";;
+ /*)
+ MPATH=`cygpath -m $x`;
+ CMD="$CMD \"$MPATH\"";;
+ *)
+ y=`echo $x | sed 's,",\\\",g'`;
+ CMD="$CMD \"$y\"";;
+ esac
+ shift
+done
+if [ $DEBUG_BUILD = true ]; then
+ linktype="-debug -pdb:none"
+ if [ $STDLIB_FORCED = false ]; then
+ STDLIB=MSVCRTD.LIB
+ fi
+fi
+# Generate a PDB
+linkadd_pdb=""
+case "$OUTPUT_FILENAME" in
+ *.exe|*.EXE)
+ fn=`echo "$OUTPUT_FILENAME" | sed 's,[eE][xX][eE]$,,g'`;
+ linkadd_pdb="-pdb:\"${fn}pdb\"";;
+ *.dll|*.DLL)
+ fn=`echo "$OUTPUT_FILENAME" | sed 's,[dD][lL][lL]$,,g'`;
+ linkadd_pdb="-pdb:\"${fn}pdb\"";;
+ "")
+ linkadd_pdb="-pdb:\"a.pdb\"";;
+ *)
+ linkadd_pdb="-pdb:\"${OUTPUT_FILENAME}.pdb\"";;
+esac
+
+ linktype="-debug $linkadd_pdb"
+
+CHMOD_FILE=""
+
+if [ $BUILD_DLL = true ];then
+ case "$OUTPUT_FILENAME" in
+ *.exe|*.EXE)
+ echo "Warning, output set to .exe when building DLL" >&2
+ CHMOD_FILE="$OUTPUT_FILENAME";
+ CMD="-dll -out:\"$OUTPUT_FILENAME\" $CMD";
+ OUTPUTRES="${OUTPUT_FILENAME}\;2";
+ MANIFEST="${OUTPUT_FILENAME}.manifest";;
+ *.dll|*.DLL)
+ CMD="-dll -out:\"$OUTPUT_FILENAME\" $CMD";
+ OUTPUTRES="${OUTPUT_FILENAME}\;2";
+ MANIFEST="${OUTPUT_FILENAME}.manifest";;
+ "")
+ CMD="-dll -out:\"a.dll\" $CMD";
+ OUTPUTRES="a.dll\;2";
+ MANIFEST="a.dll.manifest";;
+ *)
+ CMD="-dll -out:\"${OUTPUT_FILENAME}.dll\" $CMD";
+ OUTPUTRES="${OUTPUT_FILENAME}.dll\;2";
+ MANIFEST="${OUTPUT_FILENAME}.dll.manifest";;
+ esac
+else
+ case "$OUTPUT_FILENAME" in
+ *.exe|*.EXE)
+ CHMOD_FILE="$OUTPUT_FILENAME";
+ CMD="-out:\"$OUTPUT_FILENAME\" $CMD";
+ OUTPUTRES="${OUTPUT_FILENAME}\;1"
+ MANIFEST="${OUTPUT_FILENAME}.manifest";;
+ *.dll|*.DLL)
+ echo "Warning, output set to .dll when building EXE" >&2
+ CMD="-out:\"$OUTPUT_FILENAME\" $CMD";
+ OUTPUTRES="${OUTPUT_FILENAME}\;1";
+ MANIFEST="${OUTPUT_FILENAME}.manifest";;
+ "")
+ CHMOD_FILE="a.exe";
+ CMD="-out:\"a.exe\" $CMD";
+ OUTPUTRES="a.exe\;1";
+ MANIFEST="a.exe.manifest";;
+ *)
+ CMD="-out:\"${OUTPUT_FILENAME}.exe\" $CMD";
+ OUTPUTRES="${OUTPUT_FILENAME}.exe\;1";
+ MANIFEST="${OUTPUT_FILENAME}.exe.manifest";;
+ esac
+fi
+
+p=$$
+CMD="$linktype -nologo -incremental:no $CMD $STDLIB $DEFAULT_LIBRARIES"
+if [ "X$LD_SH_DEBUG_LOG" != "X" ]; then
+ echo ld.sh "$SAVE" >>$LD_SH_DEBUG_LOG
+ echo link.exe $CMD >>$LD_SH_DEBUG_LOG
+fi
+eval link.exe "$CMD" >/tmp/link.exe.${p}.1 2>/tmp/link.exe.${p}.2
+RES=$?
+CMANIFEST=`cygpath $MANIFEST`
+if [ "$RES" = "0" -a -f "$CMANIFEST" ]; then
+ eval mt.exe -nologo -manifest "$MANIFEST" -outputresource:"$OUTPUTRES" >>/tmp/link.exe.${p}.1 2>>/tmp/link.exe.${p}.2
+ RES=$?
+ if [ "$RES" != "0" ]; then
+ REMOVE=`echo "$OUTPUTRES" | sed 's,\\\;[12]$,,g'`
+ CREMOVE=`cygpath $REMOVE`
+ rm -f "$CREMOVE"
+ fi
+ rm -f "$CMANIFEST"
+fi
+
+# This works around some strange behaviour
+# in cygwin 1.7 Beta on Windows 7 with samba drive.
+# Configure will think the compiler failed if test -x fails,
+# which it might do as we might not be the owner of the
+# file.
+if [ '!' -z "$CHMOD_FILE" -a -s "$CHMOD_FILE" -a '!' -x "$CHMOD_FILE" ]; then
+ chmod +x $CHMOD_FILE
+fi
+
+tail -n +2 /tmp/link.exe.${p}.2 >&2
+cat /tmp/link.exe.${p}.1
+rm -f /tmp/link.exe.${p}.2 /tmp/link.exe.${p}.1
+exit $RES
diff --git a/erts/etc/win32/cygwin_tools/vc/ld_wrap.c b/erts/etc/win32/cygwin_tools/vc/ld_wrap.c
new file mode 100644
index 0000000000..7fb3c145ee
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/vc/ld_wrap.c
@@ -0,0 +1,796 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2008-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+#include <dirent.h>
+#include <sys/cygwin.h>
+
+
+
+#ifdef CCP_POSIX_TO_WIN_A
+#define NEW_CYGPATH_INTERFACE
+#endif
+
+#ifdef NEW_CYGPATH_INTERFACE
+#define GET_WIN32_SIZE(Posix) \
+cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, (Posix), NULL, 0)
+#define CONVERT_TO_WIN32(Posix,Win32,Size) \
+cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, (Posix), \
+ (Win32), (Size))
+#else
+#define GET_WIN32_SIZE(Posix) PATH_MAX
+#define CONVERT_TO_WIN32(Posix,Win32,Size) \
+((cygwin32_conv_to_full_win32_path((Posix),(Win32)) >= 0) ? 0 : -1)
+#endif
+
+/*#define HARDDEBUG 1*/
+
+#ifdef HARDDEBUG
+#define DEBUGF(X) printf X
+#else
+#define DEBUGF(X) /* noop */
+#endif
+char *tmpobjdir = "";
+
+char *add_to(char *src,char *add) {
+ int len = strlen(src)+strlen(add)+1;
+ char *n;
+
+ if (strlen(src) == 0) {
+ n = malloc(len);
+ strcpy(n,add);
+ return n;
+ }
+ n = realloc(src,len);
+ strcat(n,add);
+ return n;
+}
+
+void error(char *str)
+{
+ fprintf(stderr,"%s\n",str);
+ exit(1);
+}
+
+
+char *dyn_get_short(char *longp)
+{
+ int size;
+ char *shortp;
+ size = GetShortPathName(longp,NULL,0);
+ if (size <= 0) {
+ return NULL;
+ }
+ shortp = malloc(size);
+ if (GetShortPathName(longp,shortp,size) != size - 1) {
+ free(shortp);
+ return NULL;
+ }
+ return shortp;
+}
+
+char *do_cyp(char *posix)
+{
+ ssize_t size;
+ char *win32;
+ size = GET_WIN32_SIZE(posix);
+ char *ret = NULL;
+ if (size < 0) {
+ fprintf(stderr,"Could not cygpath %s, errno = %d\n",
+ posix,errno);
+ } else {
+ win32 = (char *) malloc (size);
+ if (CONVERT_TO_WIN32(posix,
+ win32, size)) {
+ fprintf(stderr,"Could not cygpath %s, errno = %d\n",
+ posix,errno);
+ } else {
+ char *w32_short = dyn_get_short(win32);
+ DEBUGF(("win32 = %s, w32_short = %s\n",win32, (w32_short == NULL) ? "NULL" : w32_short));
+ if (w32_short == NULL) {
+ char *rest = malloc(size);
+ char *first = malloc(size);
+ int x = 0;
+ int y = strlen(win32) - 1;
+ strcpy(first,win32);
+ while (w32_short == NULL) {
+ while ( y > 0 && first[y] != '\\') {
+ rest[x++] = first[y--];
+ }
+ if (y > 0) {
+ rest[x++] = first[y];
+ first[y--] = '\0';
+ } else {
+ break;
+ }
+ w32_short = dyn_get_short(first);
+ DEBUGF(("first = %s, w32_short = %s\n",first, (w32_short == NULL) ? "NULL" : w32_short));
+ }
+ if (w32_short != NULL) {
+ y = strlen(w32_short);
+ w32_short = realloc(w32_short,y+1+x);
+ /* spool back */
+ while ( x > 0) {
+ w32_short[y++] = rest[--x];
+ }
+ w32_short[y] = '\0';
+ } else {
+ w32_short = malloc(strlen(win32)+1);
+ strcpy(w32_short,win32); /* last resort */
+ }
+ free(first);
+ free(rest);
+ }
+ ret = w32_short;
+ while (*ret) {
+ if (*ret == '\\') {
+ *ret = '/';
+ }
+ ++ret;
+ }
+ ret = w32_short;
+ }
+ free(win32);
+ }
+ return ret;
+}
+
+
+
+char *save = "";
+
+void save_args(int argc, char **argv)
+{
+ int i;
+ for(i = 0; i < argc; ++i) {
+ save = add_to(save,argv[i]);
+ save = add_to(save," ");
+ }
+}
+
+char *progname="ld_wrap";
+
+int my_create_pipe(HANDLE *read_p, HANDLE *write_p)
+{
+ char name_buff[1000];
+ SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
+ static int counter = 0;
+
+ ++counter;
+
+ sprintf(name_buff,"\\\\.\\pipe\\%s_%d_%d",progname,getpid(),counter);
+ sa.bInheritHandle = FALSE;
+ if ((*read_p = CreateNamedPipe(name_buff,
+ PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
+ 1,
+ 0,
+ 0,
+ 2000,
+ &sa)) == INVALID_HANDLE_VALUE ||
+ *read_p == NULL) {
+ return 0;
+ }
+ sa.bInheritHandle = TRUE;
+ if ((*write_p = CreateFile(name_buff,
+ GENERIC_WRITE,
+ 0, /* No sharing */
+ &sa,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL)) == INVALID_HANDLE_VALUE ||
+ *write_p == NULL) {
+ CloseHandle(*read_p);
+ return 0;
+ }
+ return 1;
+}
+
+void forwardenv(void)
+{
+ char *(envs[]) = {"LIB","INCLUDE","LIBPATH", NULL};
+ char **p = envs;
+ while (*p != NULL) {
+ char *val = getenv(*p);
+ if (val != NULL) {
+ SetEnvironmentVariable(*p,val);
+ }
+ ++p;
+ }
+}
+
+HANDLE do_run(char *commandline, HANDLE *out, HANDLE *err)
+{
+ STARTUPINFO start;
+ HANDLE write_pipe_stdout = NULL, read_pipe_stdout = NULL;
+ HANDLE write_pipe_stderr = NULL, read_pipe_stderr = NULL;
+ SECURITY_ATTRIBUTES pipe_security;
+ SECURITY_ATTRIBUTES attr;
+ PROCESS_INFORMATION info;
+
+
+ memset(&start,0,sizeof(start));
+ memset(&pipe_security,0,sizeof(pipe_security));
+ memset(&attr,0,sizeof(attr));
+ memset(&info,0,sizeof(info));
+
+
+ pipe_security.nLength = sizeof(pipe_security);
+ pipe_security.lpSecurityDescriptor = NULL;
+ pipe_security.bInheritHandle = TRUE;
+
+ if(!my_create_pipe(&read_pipe_stdout,&write_pipe_stdout)){
+ error("Could not create stdout pipes!");
+ }
+ if(!my_create_pipe(&read_pipe_stderr,&write_pipe_stderr)){
+ error("Could not create stderr pipes!");
+ }
+ start.cb = sizeof (start);
+ start.dwFlags = STARTF_USESHOWWINDOW;
+ start.wShowWindow = SW_HIDE;
+ start.hStdOutput = write_pipe_stdout;
+ start.hStdError = write_pipe_stderr;
+ start.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ start.dwFlags |= STARTF_USESTDHANDLES;
+
+ attr.nLength = sizeof(attr);
+ attr.lpSecurityDescriptor = NULL;
+ attr.bInheritHandle = TRUE;
+ forwardenv(); /* Cygwin and windows environment variables... sigh... */
+ if(!CreateProcess(NULL,
+ commandline,
+ &attr,
+ NULL,
+ TRUE,
+ CREATE_DEFAULT_ERROR_MODE,
+ NULL,
+ NULL,
+ &start,
+ &info)){
+ error("Could not create process");
+ }
+ *out = read_pipe_stdout;
+ *err = read_pipe_stderr;
+ CloseHandle(write_pipe_stdout);
+ CloseHandle(write_pipe_stderr);
+ return info.hProcess;
+}
+#define HANDLE_STDOUT 0
+#define HANDLE_STDERR 1
+#define HANDLE_PROC 2
+
+#ifdef HARDDEBUG
+char *prefix = "";
+#endif
+
+int handle_overlapped(HANDLE fd, OVERLAPPED *ovp, char *buffer,
+ int bufflen, int get_old, FILE *whereto, int *skip)
+{
+ DWORD res,read,err;
+ char *ptr;
+
+ DEBUGF(("In handle_overlapped(%d,0x%08x,0x%08x,%d,%d), prefix = %s\n",
+ fd,ovp,buffer,bufflen,get_old,prefix));
+ /* h�mta resultat av gamla f�rst */
+ if (get_old) {
+ res = GetOverlappedResult(fd,ovp,&read,TRUE);
+ DEBUGF(("read = %d, res = %d, GetLastError() = %d\n",read,res,GetLastError()));
+ if (!res) {
+ return 0;
+ }
+ buffer[read] = '\0';
+ ptr = buffer;
+ while(*skip && *ptr != '\0') {
+ if (*ptr == '\n') {
+ --(*skip);
+ }
+ ++ptr;
+ }
+ if(*ptr != '\0') {
+ fprintf(whereto,"%s",ptr);
+ }
+ }
+
+ ResetEvent(ovp->hEvent);
+
+ for(;;) {
+ res = ReadFile(fd,buffer,bufflen-1,&read,ovp);
+
+ if (!res) {
+ err = GetLastError();
+ if (err == ERROR_IO_PENDING) {
+ DEBUGF(("Error I/O Pending\n"));
+ return 1;
+ }
+ DEBUGF(("ReadFileFailed for %s, %d\n",prefix,err));
+ return 0;
+ }
+ buffer[read] = '\0';
+ ptr = buffer;
+ while(*skip && *ptr != '\0') {
+ if (*ptr == '\n') {
+ --(*skip);
+ }
+ ++ptr;
+ }
+ if(*ptr != '\0') {
+ fprintf(whereto,"%s",ptr);
+ }
+ }
+}
+
+
+int run(char *commandline,int skipout,int skiperr)
+{
+ HANDLE harr[3];
+ HANDLE real_stdout,real_stderr;
+ OVERLAPPED ov_out,ov_err;
+ char outbuff[1024],errbuff[1024];
+ DWORD ret,exitcode;
+ HANDLE wait[3];
+ int map[3];
+ DWORD nwait = 3;
+ int i,j;
+ unsigned living_handles = 0x7;
+
+ harr[HANDLE_STDOUT] = CreateEvent(NULL,
+ TRUE,
+ FALSE, /*not signalled */
+ NULL);
+ harr[HANDLE_STDERR] = CreateEvent(NULL,
+ TRUE,
+ FALSE,/*not signalled */
+ NULL);
+
+ memset(&ov_out,0,sizeof(ov_out));
+ memset(&ov_err,0,sizeof(ov_err));
+
+ ov_out.hEvent = harr[HANDLE_STDOUT];
+ ov_err.hEvent = harr[HANDLE_STDERR];
+
+ harr[HANDLE_PROC] = do_run(commandline,&real_stdout,&real_stderr);
+
+#ifdef HARDDEBUG
+ prefix = "STDOUT";
+#endif
+ handle_overlapped(real_stdout,&ov_out,outbuff,1024,0,stdout,&skipout);
+#ifdef HARDDEBUG
+ prefix = "STDERR";
+#endif
+ handle_overlapped(real_stderr,&ov_err,errbuff,1024,0,stderr,&skiperr);
+
+ for(;;) {
+ nwait = 0;
+ for(i=0;i<3;++i) {
+ if ((living_handles & (1U << i))) {
+ map[nwait] = i;
+ wait[nwait++] = harr[i];
+ }
+ }
+
+ ret = WaitForMultipleObjects(nwait,
+ wait,
+ FALSE,
+ INFINITE);
+ DEBUGF(("Wait returned %d\n",ret));
+
+ if (ret == WAIT_FAILED) {
+ error("Wait failed");
+ }
+
+ ret -= WAIT_OBJECT_0;
+
+ switch (map[ret]) {
+ case HANDLE_PROC:
+
+ DEBUGF(("Process died!\n"));
+ GetExitCodeProcess(harr[HANDLE_PROC],&exitcode);
+ if ((living_handles &= (~(1U<<HANDLE_PROC))) == 0) {
+ goto done;
+ }
+ --nwait;
+ break;
+ case HANDLE_STDOUT:
+#ifdef HARDDEBUG
+ prefix = "STDOUT";
+#endif
+ if (!handle_overlapped(real_stdout,&ov_out, outbuff,1024,1,stdout,&skipout)) {
+ if ((living_handles &= (~(1U<<HANDLE_STDOUT))) == 0) {
+ goto done;
+ }
+ }
+ break;
+ case HANDLE_STDERR:
+#ifdef HARDDEBUG
+ prefix = "STDERR";
+#endif
+ if (!handle_overlapped(real_stderr,&ov_err, errbuff,1024,1,stderr,&skiperr)){
+ if ((living_handles &= (~(1U<<HANDLE_STDERR))) == 0) {
+ goto done;
+ }
+ }
+ break;
+ default:
+ error("Unexpected wait result");
+ }
+ }
+ done:
+ CloseHandle(harr[HANDLE_PROC]);
+ CloseHandle(harr[HANDLE_STDOUT]);
+ CloseHandle(harr[HANDLE_STDERR]);
+ CloseHandle(real_stdout);
+ CloseHandle(real_stderr);
+ return (int) exitcode;
+}
+
+int main(int argc, char **argv)
+{
+ int i;
+ int x;
+ char *s;
+ char *mpath;
+ char *debuglog;
+ char *remove;
+ FILE *debugfile;
+ FILE *tmpfile;
+ int filefound;
+ int retval = 0;
+
+ char *kernel_libs="kernel32.lib advapi32.lib";
+ char *gdi_libs="gdi32.lib user32.lib comctl32.lib comdlg32.lib shell32.lib";
+ char *default_libraries = "";
+ char *cmd = "";
+ char *stdlib = "MSVCRT.LIB";
+ int debug_build = 0;
+ int stdlib_forced = 0;
+ int build_dll = 0;
+ char *output_filename = "";
+ char *linkadd_pdb = "";
+ char *linktype = "";
+ char *manifest = "";
+ char *outputres = "";
+
+ save_args(argc,argv);
+ //fprintf(stderr,"ld_wrap!\n");
+
+ default_libraries = add_to(default_libraries,kernel_libs);
+ default_libraries = add_to(default_libraries," ");
+ default_libraries = add_to(default_libraries,gdi_libs);
+
+ for(i = 1; i < argc; ++i) {
+ if (argv[i][0] == '-') {
+ char *opt = argv[i]+1;
+ switch(*opt) {
+ case 'D':
+ if(strcmp(opt,"DLL")) {
+ goto filename;
+ }
+ build_dll = 1;
+ break;
+ case 'd':
+ if(!strncmp(opt,"def:",4)) {
+ mpath = do_cyp(opt+4);
+ cmd = add_to(cmd," -def:\"");
+ cmd = add_to(cmd,mpath);
+ cmd = add_to(cmd,"\"");
+ free(mpath);
+ } else if(strcmp(opt,"dll")) {
+ goto filename;
+ } else {
+ build_dll = 1;
+ }
+ break;
+ case 'L':
+ mpath = do_cyp(opt+1);
+ cmd = add_to(cmd," -libpath:\"");
+ cmd = add_to(cmd,mpath);
+ cmd = add_to(cmd,"\"");
+ free(mpath);
+ break;
+ case 'l':
+ if(!strcmp(opt,"lMSVCRT") || !strcmp(opt,"lmsvcrt")) {
+ stdlib = "MSVCRT.LIB";
+ stdlib_forced = 1;
+ } else if(!strcmp(opt,"lMSVCRTD") || !strcmp(opt,"lmsvcrtd")) {
+ stdlib = "MSVCRTD.LIB";
+ stdlib_forced = 1;
+ } else if(!strcmp(opt,"lLIBCMT") || !strcmp(opt,"llibcmt")) {
+ stdlib = "LIBCMT.LIB";
+ stdlib_forced = 1;
+ } else if(!strcmp(opt,"lLIBCMTD") || !strcmp(opt,"llibcmtd")) {
+ stdlib = "LIBCMTD.LIB";
+ stdlib_forced = 1;
+ } else if(!strcmp(opt,"lsocket")) {
+ default_libraries = add_to(default_libraries," ");
+ default_libraries = add_to(default_libraries,"WS2_32.LIB");
+ } else {
+ mpath = do_cyp(opt+1);
+ cmd = add_to(cmd," \"");
+ cmd = add_to(cmd,mpath);
+ cmd = add_to(cmd,"\"");
+ free(mpath);
+ }
+ break;
+ case 'g':
+ debug_build = 1;
+ break;
+ case 'p':
+ if (strcmp(opt,"pdb:none")) {
+ goto filename;
+ }
+ break;
+ case 'i':
+ if (!strncmp(opt,"implib:",7)) {
+ mpath = do_cyp(opt+7);
+ cmd = add_to(cmd," -implib:\"");
+ cmd = add_to(cmd,mpath);
+ cmd = add_to(cmd,"\"");
+ free(mpath);
+ } else if (strcmp(opt,"incremental:no")) {
+ goto filename;
+ }
+ break;
+ case 'o':
+ if (!strcmp(opt,"o")) {
+ ++i;
+ if (i >= argc) {
+ error("-o without filename");
+ }
+ output_filename = do_cyp(argv[i]);
+ } else {
+ output_filename = do_cyp(opt+1);
+ }
+ break;
+ default:
+ goto filename;
+ }
+ continue;
+ }
+ filename:
+ s = argv[i];
+ if (*s == '/') {
+ mpath = do_cyp(s);
+ cmd = add_to(cmd," \"");
+ cmd = add_to(cmd,mpath);
+ cmd = add_to(cmd,"\"");
+ free(mpath);
+ } else {
+ cmd = add_to(cmd," \"");
+ cmd = add_to(cmd,s);
+ cmd = add_to(cmd,"\"");
+ }
+ }
+ if ((debuglog = getenv("LD_SH_DEBUG_LOG")) != NULL) {
+ debugfile = fopen(debuglog,"wb+");
+ if (debugfile) {
+ fprintf(debugfile,"----------------\n");
+ }
+ } else {
+ debugfile = NULL;
+ }
+
+ if (debug_build) {
+ if (!stdlib_forced) {
+ stdlib = "MSVCRTD.LIB";
+ }
+ }
+
+ s = add_to("",output_filename);
+ x = strlen(s);
+
+ if (x >= 4 && (!strcmp(s+x-4,".exe") || !strcmp(s+x-4,".EXE") ||
+ !strcmp(s+x-4,".dll") || !strcmp(s+x-4,".DLL"))) {
+ *(s+x-3) = '\0';
+ linkadd_pdb = add_to(linkadd_pdb,"-pdb:\"");
+ linkadd_pdb = add_to(linkadd_pdb,s);
+ linkadd_pdb = add_to(linkadd_pdb,"pdb\"");
+ } else if (!x) {
+ linkadd_pdb = add_to(linkadd_pdb,"-pdb:\"a.pdb\"");
+ } else {
+ linkadd_pdb = add_to(linkadd_pdb,"-pdb:\"");
+ linkadd_pdb = add_to(linkadd_pdb,s);
+ linkadd_pdb = add_to(linkadd_pdb,".pdb\"");
+ }
+ free(s);
+
+
+ linktype = add_to(linktype,"-debug ");
+ linktype = add_to(linktype,linkadd_pdb);
+
+ free(linkadd_pdb);
+
+ s = add_to("",output_filename);
+ x = strlen(s);
+
+ if (build_dll) {
+ if (x >= 4 && (!strcmp(s+x-4,".exe") || !strcmp(s+x-4,".EXE") ||
+ !strcmp(s+x-4,".dll") || !strcmp(s+x-4,".DLL"))) {
+
+ if (!strcmp(s+x-4,".exe") || !strcmp(s+x-4,".EXE")) {
+ fprintf(stderr,"Warning, output set to .exe when building DLL");
+ }
+ mpath = cmd;
+ cmd = add_to("","-dll -out:\"");
+ cmd = add_to(cmd,s);
+ cmd = add_to(cmd,"\" ");
+ cmd = add_to(cmd,mpath);
+ if (*mpath) {
+ free(mpath);
+ }
+
+ outputres = add_to(outputres,output_filename);
+ outputres = add_to(outputres,";2");
+ manifest = add_to(manifest,output_filename);
+ manifest = add_to(manifest,".manifest");
+ } else if (x == 0) {
+ mpath = cmd;
+ cmd = add_to("","-dll -out:\"a.dll\" ");
+ cmd = add_to(cmd,mpath);
+ if (*mpath) {
+ free(mpath);
+ }
+
+ outputres = add_to(outputres,"a.dll;2");
+ manifest = add_to(manifest,"a.dll.manifest");
+ } else {
+ mpath = cmd;
+ cmd = add_to("","-dll -out:\"");
+ cmd = add_to(cmd,s);
+ cmd = add_to(cmd,".dll\" ");
+ cmd = add_to(cmd,mpath);
+ if (*mpath) {
+ free(mpath);
+ }
+
+ outputres = add_to(outputres,output_filename);
+ outputres = add_to(outputres,".dll;2");
+ manifest = add_to(manifest,output_filename);
+ manifest = add_to(manifest,".dll.manifest");
+ }
+ } else {
+ if (x >= 4 && (!strcmp(s+x-4,".exe") || !strcmp(s+x-4,".EXE") ||
+ !strcmp(s+x-4,".dll") || !strcmp(s+x-4,".DLL"))) {
+
+ if (!strcmp(s+x-4,".dll") || !strcmp(s+x-4,".DLL")) {
+ fprintf(stderr,"Warning, output set to .exe when building DLL");
+ }
+ mpath = cmd;
+ cmd = add_to("","-out:\"");
+ cmd = add_to(cmd,s);
+ cmd = add_to(cmd,"\" ");
+ cmd = add_to(cmd,mpath);
+ if (*mpath) {
+ free(mpath);
+ }
+
+ outputres = add_to(outputres,output_filename);
+ outputres = add_to(outputres,";1");
+ manifest = add_to(manifest,output_filename);
+ manifest = add_to(manifest,".manifest");
+ } else if (x == 0) {
+ mpath = cmd;
+ cmd = add_to("","-out:\"a.exe\" ");
+ cmd = add_to(cmd,mpath);
+ if (*mpath) {
+ free(mpath);
+ }
+
+ outputres = add_to(outputres,"a.exe;1");
+ manifest = add_to(manifest,"a.exe.manifest");
+ } else {
+ mpath = cmd;
+ cmd = add_to("","-out:\"");
+ cmd = add_to(cmd,s);
+ cmd = add_to(cmd,".exe\" ");
+ cmd = add_to(cmd,mpath);
+ if (*mpath) {
+ free(mpath);
+ }
+
+ outputres = add_to(outputres,output_filename);
+ outputres = add_to(outputres,".exe;1");
+ manifest = add_to(manifest,output_filename);
+ manifest = add_to(manifest,".exe.manifest");
+ }
+ }
+
+ s = cmd;
+ cmd = add_to("","link.exe ");
+ cmd = add_to(cmd,linktype);
+ cmd = add_to(cmd," -nologo -incremental:no ");
+ cmd = add_to(cmd,s);
+ cmd = add_to(cmd," ");
+ cmd = add_to(cmd,stdlib);
+ cmd = add_to(cmd," ");
+ cmd = add_to(cmd,default_libraries);
+
+ if (*s) {
+ free(s);
+ }
+
+
+ if (debugfile) {
+ fprintf(debugfile,"%s\n",save);
+ fprintf(debugfile,"%s\n",cmd);
+ }
+
+ retval = run(cmd,0,0);
+
+
+ mpath = do_cyp(manifest);
+ filefound = 0;
+ tmpfile = fopen(mpath,"rb");
+ if (tmpfile != NULL) {
+ filefound = 1;
+ fclose(tmpfile);
+ }
+ if (retval == 0 && filefound) {
+ s = add_to("","mt.exe -nologo -manifest \"");
+ s = add_to(s,manifest);
+ s = add_to(s,"\" -outputresource:\"");
+ s = add_to(s,outputres);
+ s = add_to(s,"\"");
+ if (debugfile) {
+ fprintf(debugfile,"%s\n",s);
+ }
+ retval = run(s,0,0);
+ if (*s) {
+ free(s);
+ }
+ if (retval) {
+ /* cleanup needed */
+ remove = add_to("",outputres);
+ x = strlen(remove);
+ remove[x-2] = '\0';
+ if (debugfile) {
+ fprintf(debugfile,"remove %s\n",remove);
+ }
+ DeleteFile(remove);
+ free(remove);
+ }
+ if (debugfile) {
+ fprintf(debugfile,"remove %s\n",manifest);
+ }
+ DeleteFile(manifest);
+ }
+ return retval;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/erts/etc/win32/cygwin_tools/vc/mc.sh b/erts/etc/win32/cygwin_tools/vc/mc.sh
new file mode 100755
index 0000000000..813b59947b
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/vc/mc.sh
@@ -0,0 +1,87 @@
+#! /bin/sh
+# set -x
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2002-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+# Save the command line for debug outputs
+SAVE="$@"
+CMD=""
+OUTPUT_DIRNAME=""
+
+# Find the correct mc.exe. This could be done by the configure script,
+# But as we seldom use the resource compiler, it might as well be done here...
+MCC=""
+save_ifs=$IFS
+IFS=:
+for p in $PATH; do
+ if [ -f $p/mc.exe ]; then
+ if [ -n "`$p/mc.exe -? 2>&1 >/dev/null </dev/null \
+ | grep -i \"message compiler\"`" ]; then
+ MCC=$p/mc.exe
+ fi
+ fi
+done
+IFS=$save_ifs
+
+if [ -z "$MCC" ]; then
+ echo 'mc.exe not found!' >&2
+ exit 1
+fi
+
+while test -n "$1" ; do
+ x="$1"
+ case "$x" in
+ -o)
+ shift
+ OUTPUT_DIRNAME="$1";;
+ -o/*)
+ y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`;
+ OUTPUT_DIRNAME="$y";;
+ -I)
+ shift
+ MPATH=`cygpath -m $1`;
+ CMD="$CMD -I\"$MPATH\"";;
+ -I/*)
+ y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ CMD="$CMD -I\"$MPATH\"";;
+ *)
+ MPATH=`cygpath -m -a $x`;
+ CMD="$CMD \"$MPATH\"";;
+ esac
+ shift
+done
+p=$$
+if [ "X$MC_SH_DEBUG_LOG" != "X" ]; then
+ echo rc.sh "$SAVE" >>$MC_SH_DEBUG_LOG
+ echo rc.exe $CMD >>$MC_SH_DEBUG_LOG
+fi
+if [ -n "$OUTPUT_DIRNAME" ]; then
+ cd $OUTPUT_DIRNAME
+ RES=$?
+ if [ "$RES" != "0" ]; then
+ echo "mc.sh: Error: could not cd to $OUTPUT_DIRNAME">&2
+ exit $RES
+ fi
+fi
+eval $MCC "$CMD" >/tmp/mc.exe.${p}.1 2>/tmp/mc.exe.${p}.2
+RES=$?
+tail +2 /tmp/mc.exe.${p}.2 >&2
+cat /tmp/mc.exe.${p}.1
+rm -f /tmp/mc.exe.${p}.2 /tmp/mc.exe.${p}.1
+exit $RES
diff --git a/erts/etc/win32/cygwin_tools/vc/rc.sh b/erts/etc/win32/cygwin_tools/vc/rc.sh
new file mode 100755
index 0000000000..748de48890
--- /dev/null
+++ b/erts/etc/win32/cygwin_tools/vc/rc.sh
@@ -0,0 +1,86 @@
+#! /bin/sh
+# set -x
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2002-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+# Save the command line for debug outputs
+SAVE="$@"
+CMD=""
+OUTPUT_FILENAME=""
+
+# Find the correct rc.exe. This could be done by the configure script,
+# But as we seldom use the resource compiler, it might as well be done here...
+RCC=""
+save_ifs=$IFS
+IFS=:
+for p in $PATH; do
+ if [ -f $p/rc.exe ]; then
+ if [ -n "`$p/rc.exe -? 2>&1 | grep -i "resource compiler"`" ]; then
+ RCC=$p/rc.exe
+ fi
+ fi
+done
+IFS=$save_ifs
+
+if [ -z "$RCC" ]; then
+ echo 'rc.exe not found!' >&2
+ exit 1
+fi
+
+while test -n "$1" ; do
+ x="$1"
+ case "$x" in
+ -o)
+ shift
+ MPATH=`cygpath -m $1`;
+ OUTPUT_FILENAME="$MPATH";;
+ -o/*)
+ y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ OUTPUT_FILENAME="$MPATH";;
+ -I)
+ shift
+ MPATH=`cygpath -m $1`;
+ CMD="$CMD -I\"$MPATH\"";;
+ -I/*)
+ y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`;
+ MPATH=`cygpath -m $y`;
+ CMD="$CMD -I\"$MPATH\"";;
+ /*)
+ MPATH=`cygpath -m $x`;
+ CMD="$CMD \"$MPATH\"";;
+ *)
+ y=`echo $x | sed 's,",\\\",g'`;
+ CMD="$CMD \"$y\"";;
+ esac
+ shift
+done
+p=$$
+if [ -n "$OUTPUT_FILENAME" ]; then
+ CMD="-Fo$OUTPUT_FILENAME $CMD"
+fi
+if [ "X$RC_SH_DEBUG_LOG" != "X" ]; then
+ echo rc.sh "$SAVE" >>$RC_SH_DEBUG_LOG
+ echo rc.exe $CMD >>$RC_SH_DEBUG_LOG
+fi
+eval $RCC "$CMD" >/tmp/rc.exe.${p}.1 2>/tmp/rc.exe.${p}.2
+RES=$?
+tail +2 /tmp/rc.exe.${p}.2 >&2
+cat /tmp/rc.exe.${p}.1
+rm -f /tmp/rc.exe.${p}.2 /tmp/rc.exe.${p}.1
+exit $RES
diff --git a/erts/etc/win32/erl.c b/erts/etc/win32/erl.c
new file mode 100644
index 0000000000..d341153966
--- /dev/null
+++ b/erts/etc/win32/erl.c
@@ -0,0 +1,283 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2003-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#pragma comment(linker,"/manifestdependency:\"type='win32' "\
+ "name='Microsoft.Windows.Common-Controls' "\
+ "version='6.0.0.0' processorArchitecture='*' "\
+ "publicKeyToken='6595b64144ccf1df' language='*'\"")
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "init_file.h"
+
+typedef int ErlexecFunction(int, char **, HANDLE, int);
+
+#define INI_FILENAME "erl.ini"
+#define INI_SECTION "erlang"
+#define ERLEXEC_BASENAME "erlexec.dll"
+
+static void get_parameters(void);
+static void error(char* format, ...);
+
+static char *erlexec_name;
+static char *erlexec_dir;
+
+#ifdef WIN32_WERL
+#define WERL 1
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+ PSTR szCmdLine, int iCmdShow)
+{
+ int argc = __argc;
+ char **argv = __argv;
+#else
+#define WERL 0
+int main(int argc, char **argv)
+{
+#endif
+ HANDLE erlexec_handle; /* Instance */
+ ErlexecFunction *win_erlexec;
+ char *path = malloc(100);
+ char *npath;
+ int pathlen;
+
+ get_parameters();
+
+ if ((pathlen = GetEnvironmentVariable("PATH",path,100)) == 0) {
+ error("No PATH variable (!)");
+ } else if (pathlen > 100) {
+ path = realloc(path,pathlen);
+ GetEnvironmentVariable("PATH",path,pathlen);
+ }
+ npath = malloc(strlen(path) + strlen(erlexec_dir) + 2);
+ sprintf(npath,"%s;%s",erlexec_dir,path);
+ SetEnvironmentVariable("PATH",npath);
+
+ if ((erlexec_handle = LoadLibrary(erlexec_name)) == NULL) {
+ error("Could not load module %s.",erlexec_name);
+ }
+
+ if ((win_erlexec = (ErlexecFunction *)
+ GetProcAddress(erlexec_handle,"win_erlexec")) == NULL) {
+ error("Could not find entry point \"win_erlexec\" in %s.", erlexec_name);
+ }
+
+ return (*win_erlexec)(argc,argv,erlexec_handle,WERL);
+
+}
+
+
+static char *replace_filename(char *path, char *new_base)
+{
+ int plen = strlen(path);
+ char *res = malloc((plen+strlen(new_base)+1)*sizeof(char));
+ char *p;
+
+ strcpy(res,path);
+ for (p = res+plen-1 ;p >= res && *p != '\\'; --p)
+ ;
+ *(p+1) ='\0';
+ strcat(res,new_base);
+ return res;
+}
+
+static char *do_lookup_in_section(InitSection *inis, char *name,
+ char *section, char *filename)
+{
+ char *p = lookup_init_entry(inis, name);
+
+ if (p == NULL) {
+ error("Could not find key %s in section %s of file %s",
+ name,section,filename);
+ }
+ return _strdup(p);
+}
+
+static void copy_latest_vsn(char *latest_vsn, char *next_vsn)
+{
+ /* Copy */
+ char *lp;
+ char *np;
+ /* Find vsn */
+ for (lp = next_vsn+strlen(next_vsn)-1 ;lp >= next_vsn && *lp != '\\'; --lp)
+ ;
+ /* lp =+ length("erts-"); */
+ for (np = next_vsn+strlen(next_vsn)-1 ;np >= next_vsn && *np != '\\'; --np)
+ ;
+ /* np =+ length("erts-"); */
+
+ for (; lp && np; ++lp, ++np) {
+ if (*lp == *np) {
+ continue;
+ }
+ if (*np == '.' || *np == '\0' || *np <= *lp) {
+ /* */
+ return;
+ }
+ if (*lp == '.' || *lp == '\0') {
+ strcpy(latest_vsn, next_vsn);
+ return;
+ }
+ }
+ return;
+}
+
+static char *find_erlexec_dir2(char *install_dir)
+{
+ /* List install dir and look for latest erts-vsn */
+
+ HANDLE dir_handle; /* Handle to directory. */
+ char wildcard[MAX_PATH]; /* Wildcard to search for. */
+ WIN32_FIND_DATA find_data; /* Data found by FindFirstFile() or FindNext(). */
+ char latest_vsn[MAX_PATH];
+
+ /* Setup wildcard */
+ int length = strlen(install_dir);
+ char *p;
+
+ if (length+3 >= MAX_PATH) {
+ error("Cannot find erlexec.exe");
+ }
+
+ strcpy(wildcard, install_dir);
+ p = wildcard+length-1;
+ if (*p != '/' && *p != '\\')
+ *++p = '\\';
+ strcpy(++p, "erts-*");
+
+ /* Find first dir */
+ dir_handle = FindFirstFile(wildcard, &find_data);
+ if (dir_handle == INVALID_HANDLE_VALUE) {
+ /* No erts-vsn found*/
+ return NULL;
+ }
+ strcpy(latest_vsn, find_data.cFileName);
+
+ /* Find the rest */
+ while(FindNextFile(dir_handle, &find_data)) {
+ copy_latest_vsn(latest_vsn, find_data.cFileName);
+ }
+
+ FindClose(dir_handle);
+
+ p = malloc((strlen(install_dir)+1+strlen(latest_vsn)+4+1)*sizeof(char));
+
+ strcpy(p,install_dir);
+ strcat(p,"\\");
+ strcat(p,latest_vsn);
+ strcat(p,"\\bin");
+ return p;
+}
+
+static char *find_erlexec_dir(char *erlpath)
+{
+ /* Assume that the path to erl is absolute and
+ * that it is not a symbolic link*/
+
+ char *dir =_strdup(erlpath);
+ char *p;
+ char *p2;
+
+ /* Chop of base name*/
+ for (p = dir+strlen(dir)-1 ;p >= dir && *p != '\\'; --p)
+ ;
+ *p ='\0';
+ p--;
+
+ /* Check if dir path is like ...\install_dir\erts-vsn\bin */
+ for (;p >= dir && *p != '\\'; --p)
+ ;
+ p--;
+ for (p2 = p;p2 >= dir && *p2 != '\\'; --p2)
+ ;
+ p2++;
+ if (strncmp(p2, "erts-", strlen("erts-")) == 0) {
+ p = _strdup(dir);
+ free(dir);
+ return p;
+ }
+
+ /* Assume that dir path is like ...\install_dir\bin */
+ *++p ='\0'; /* chop off bin dir */
+
+ p = find_erlexec_dir2(dir);
+ free(dir);
+ if (p == NULL) {
+ error("Cannot find erlexec.exe");
+ } else {
+ return p;
+ }
+}
+
+static void get_parameters(void)
+{
+ char buffer[MAX_PATH];
+ char *ini_filename;
+ HANDLE module = GetModuleHandle(NULL);
+ InitFile *inif;
+ InitSection *inis;
+ char *bindir;
+
+ if (module = NULL) {
+ error("Cannot GetModuleHandle()");
+ }
+
+ if (GetModuleFileName(module,buffer,MAX_PATH) == 0) {
+ error("Could not GetModuleFileName");
+ }
+
+ ini_filename = replace_filename(buffer,INI_FILENAME);
+
+ if ((inif = load_init_file(ini_filename)) == NULL) {
+ erlexec_dir = find_erlexec_dir(ini_filename);
+ SetEnvironmentVariable("ERLEXEC_DIR", erlexec_dir);
+ } else {
+
+ if ((inis = lookup_init_section(inif,INI_SECTION)) == NULL) {
+ error("Could not find section %s in init file %s",
+ INI_SECTION, ini_filename);
+ }
+
+ erlexec_dir = do_lookup_in_section(inis, "Bindir", INI_SECTION, ini_filename);
+ free_init_file(inif);
+ }
+
+ erlexec_name = malloc(strlen(erlexec_dir) + strlen(ERLEXEC_BASENAME) + 2);
+ strcpy(erlexec_name,erlexec_dir);
+ strcat(erlexec_name, "\\" ERLEXEC_BASENAME);
+
+ free(ini_filename);
+}
+
+
+static void error(char* format, ...)
+{
+ char sbuf[2048];
+ va_list ap;
+
+ va_start(ap, format);
+ vsprintf(sbuf, format, ap);
+ va_end(ap);
+
+#ifndef WIN32_WERL
+ fprintf(stderr, "%s\n", sbuf);
+#else
+ MessageBox(NULL, sbuf, "Werl", MB_OK|MB_ICONERROR);
+#endif
+ exit(1);
+}
+
diff --git a/erts/etc/win32/erl.rc b/erts/etc/win32/erl.rc
new file mode 100644
index 0000000000..88213d48f2
--- /dev/null
+++ b/erts/etc/win32/erl.rc
@@ -0,0 +1,31 @@
+//
+// %CopyrightBegin%
+//
+// Copyright Ericsson AB 1998-2009. All Rights Reserved.
+//
+// The contents of this file are subject to the Erlang Public License,
+// Version 1.1, (the "License"); you may not use this file except in
+// compliance with the License. You should have received a copy of the
+// Erlang Public License along with this software. If not, it can be
+// retrieved online at http://www.erlang.org/.
+//
+// Software distributed under the License is distributed on an "AS IS"
+// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+// the License for the specific language governing rights and limitations
+// under the License.
+//
+// %CopyrightEnd%
+//
+#include <windows.h>
+#include "resource.h"
+
+1 ICON DISCARDABLE "erlang.ico"
+
+
+
+
+
+
+
+
+
diff --git a/erts/etc/win32/erl_icon.ico b/erts/etc/win32/erl_icon.ico
new file mode 100644
index 0000000000..3e228317cd
--- /dev/null
+++ b/erts/etc/win32/erl_icon.ico
Binary files differ
diff --git a/erts/etc/win32/erl_log.c b/erts/etc/win32/erl_log.c
new file mode 100644
index 0000000000..85cc49e0e3
--- /dev/null
+++ b/erts/etc/win32/erl_log.c
@@ -0,0 +1,73 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1996-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+/* -----------------------------------------------------------------
+ * erl_log:
+ *
+ * Provides a simple debug log for the Erlang emulator.
+ * It simples echoes its standard intput to the console.
+ *
+ * Author: Bjorn Gustavsson
+ * Created: 1996-12-06
+ * -----------------------------------------------------------------
+ */
+
+#include <windows.h>
+#include <stdio.h>
+
+static void print_last_error(char* message);
+
+main()
+{
+ HANDLE in;
+ HANDLE out;
+ char sbuf[256];
+ DWORD written;
+ DWORD numChars;
+
+ in = GetStdHandle(STD_INPUT_HANDLE);
+ out = CreateFile("CONOUT$", GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if (out == INVALID_HANDLE_VALUE) {
+ print_last_error("CreateFile");
+ exit(1);
+ }
+
+ while (ReadFile(in, sbuf, sizeof(sbuf), &numChars, NULL) && numChars) {
+ WriteFile(out, sbuf, numChars, &written, NULL);
+ }
+ return 0;
+}
+
+static void print_last_error(char* message)
+{
+ LPTSTR* lpBufPtr;
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpBufPtr,
+ 0,
+ NULL);
+ if (message == NULL)
+ printf("%s", lpBufPtr);
+ else
+ printf("%s: %s\n", message, lpBufPtr);
+}
diff --git a/erts/etc/win32/erlang.ico b/erts/etc/win32/erlang.ico
new file mode 100644
index 0000000000..cee8b58af9
--- /dev/null
+++ b/erts/etc/win32/erlang.ico
Binary files differ
diff --git a/erts/etc/win32/erlsrv/erlsrv_global.h b/erts/etc/win32/erlsrv/erlsrv_global.h
new file mode 100644
index 0000000000..d3922dc1e3
--- /dev/null
+++ b/erts/etc/win32/erlsrv/erlsrv_global.h
@@ -0,0 +1,37 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifndef _ERLSRV_GLOBAL_H
+#define _ERLSRV_GLOBAL_H
+
+#define APP_NAME "ErlSrv"
+
+#define ERLANG_MACHINE "erl.exe"
+
+#define SERVICE_ENV "ERLSRV_SERVICE_NAME"
+#define EXECUTABLE_ENV "ERLSRV_EXECUTABLE"
+#define DEBUG_ENV "ERLSRV_DEBUG"
+
+#ifdef _DEBUG
+#define HARDDEBUG 1
+#define DEBUG 1
+#else
+#define NDEBUG 1
+#endif
+
+#endif /* _ERLSRV_GLOBAL_H */
diff --git a/erts/etc/win32/erlsrv/erlsrv_interactive.c b/erts/etc/win32/erlsrv/erlsrv_interactive.c
new file mode 100644
index 0000000000..13e029b364
--- /dev/null
+++ b/erts/etc/win32/erlsrv/erlsrv_interactive.c
@@ -0,0 +1,1163 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#include <windows.h>
+#include <winsvc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "erlsrv_global.h"
+#include "erlsrv_registry.h"
+#include "erlsrv_interactive.h"
+#include "erlsrv_util.h" /* service_name */
+
+#define DBG fprintf(stderr,"argv[0]:%s line %d\n",argv[0],__LINE__)
+
+/* Really HAS to correcpond to the enum in erlsrv_registry.h */
+static char *arg_tab[] = {
+ "stopaction", "st",
+ "onfail", "on",
+ "machine", "m",
+ "env", "e",
+ "workdir", "w",
+ "priority", "p",
+ "sname", "sn",
+ "name", "n",
+ "args", "ar",
+ "debugtype", "d",
+ "internalservicename","i",
+ "comment","c",
+ NULL, NULL
+};
+
+static char *generate_real_service_name(char *display_name){
+ SYSTEMTIME systime;
+ FILETIME ftime;
+ char *buff = malloc(strlen(display_name)+
+ (8*2)+1);
+ char *tmp = _strdup(display_name);
+ int i;
+ /* 2 Hex chars for each byte in a DWORD */
+ GetSystemTime(&systime);
+ SystemTimeToFileTime(&systime,&ftime);
+ /* Remove trailing version info to avoid user confusion */
+ for(i = (strlen(tmp)-1);i > 0; --i)
+ if(tmp[i] == '_'){
+ tmp[i] = '\0';
+ break;
+ }
+ sprintf(buff,"%s%08x%08x",tmp,ftime.dwHighDateTime,
+ ftime.dwLowDateTime);
+ free(tmp);
+ return buff;
+}
+
+static int lookup_arg(char *arg){
+ int i;
+ if(*arg != '-' && *arg != '/')
+ return -1;
+ for(i=0; arg_tab[i] != NULL; i += 2){
+ if(!_strnicmp(arg_tab[i],arg+1,strlen(arg+1)) &&
+ !_strnicmp(arg_tab[i+1],arg+1,strlen(arg_tab[i+1])))
+ return (i / 2);
+ }
+ return -1;
+}
+
+
+
+char *edit_env(char *edit, char *oldenv){
+ char **arg;
+ char *value;
+ char *name = strdup(edit);
+ int i;
+ char *tmp;
+ arg = env_to_arg(oldenv);
+ value = strchr(name,'=');
+ if(value){
+ *(value++) = '\0';
+ if(*value == '\0')
+ value = NULL;
+ }
+ for(i=0;arg[i] != NULL; ++i){
+ tmp = strchr(arg[i],'=');
+ if(((int) strlen(name)) == (tmp - arg[i]) &&
+ !_strnicmp(name,arg[i], tmp - arg[i]))
+ break;
+ }
+ if(arg[i] != NULL){
+ free(arg[i]);
+ if(value){
+ arg[i] = strdup(edit);
+ } else {
+ do {
+ arg[i] = arg[i+1];
+ ++i;
+ } while(arg[i] != NULL);
+ }
+ } else if(value){ /* add to arg, which is always allocated
+ to hold one extra environment variable*/
+ arg[i] = strdup(edit);
+ arg[i+1] = NULL;
+ }
+ free(name);
+ return arg_to_env(arg);
+}
+
+int last_error = 0;
+
+void print_last_error(void){
+ char *mes;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ (last_error) ? last_error : GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &mes,
+ 0,
+ NULL );
+ fprintf(stderr,"Error: %s",mes);
+ LocalFree(mes);
+}
+
+static BOOL install_service(void){
+ SC_HANDLE scm;
+ SC_HANDLE service;
+ char filename[MAX_PATH + 3];
+ DWORD fnsiz=MAX_PATH;
+ char dependant[] = { 'L','a','n','m','a','n',
+ 'W','o','r','k','s','t',
+ 'a','t','i','o','n','\0','\0'};
+
+ if(!(fnsiz = GetModuleFileName(NULL, filename, fnsiz)))
+ return FALSE;
+ if(strchr(filename,' ')){
+ memmove(filename+1,filename,fnsiz);
+ filename[0] ='\"'; /* " */
+ filename[fnsiz+1] = '\"'; /* " */
+ filename[fnsiz+2] = '\0';
+ }
+ if((scm = OpenSCManager(NULL,
+ NULL,
+ SC_MANAGER_CONNECT |
+ SC_MANAGER_CREATE_SERVICE))
+ == NULL){
+ last_error = GetLastError();
+ return FALSE;
+ }
+ service = CreateService(scm,
+ real_service_name,
+ service_name,
+ SERVICE_ALL_ACCESS &
+ ~(SERVICE_PAUSE_CONTINUE),
+ SERVICE_WIN32_OWN_PROCESS,
+ SERVICE_AUTO_START,
+ SERVICE_ERROR_NORMAL,
+ filename,
+ NULL,
+ NULL,
+ dependant,
+ NULL,
+ NULL);
+ if(service == NULL){
+ CloseServiceHandle(scm);
+ last_error = GetLastError();
+ return FALSE;
+ }
+ CloseServiceHandle(service);
+ CloseServiceHandle(scm);
+ return TRUE;
+}
+
+static BOOL remove_service(void){
+ SC_HANDLE scm;
+ SC_HANDLE service;
+ if((scm = OpenSCManager(NULL,
+ NULL,
+ GENERIC_WRITE))
+ == NULL)
+ return FALSE;
+ service = OpenService(scm,
+ real_service_name,
+ SERVICE_ALL_ACCESS);
+ if(service == NULL){
+ CloseServiceHandle(scm);
+ return FALSE;
+ }
+ if(!DeleteService(service)){
+ last_error = GetLastError();
+ return FALSE;
+ }
+ CloseServiceHandle(service);
+ CloseServiceHandle(scm);
+ return TRUE;
+}
+
+static BOOL open_service_control(SC_HANDLE *scm, SC_HANDLE *service){
+ if((*scm = OpenSCManager(NULL,
+ NULL,
+ SC_MANAGER_ALL_ACCESS))
+ == NULL)
+ return FALSE;
+ *service = OpenService(*scm,
+ real_service_name,
+ SERVICE_ALL_ACCESS);
+ if(service == NULL){
+ CloseServiceHandle(*scm);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static BOOL open_service_config(SC_HANDLE *scm, SC_HANDLE *service){
+ if((*scm = OpenSCManager(NULL,
+ NULL,
+ /*GENERIC_WRITE | GENERIC_EXECUTE*/
+ SC_MANAGER_ALL_ACCESS))
+ == NULL){
+ last_error = GetLastError();
+ return FALSE;
+ }
+ *service = OpenService(*scm,
+ real_service_name,
+ /*GENERIC_WRITE*/
+ SERVICE_ALL_ACCESS);
+ if(service == NULL){
+ last_error = GetLastError();
+ CloseServiceHandle(*scm);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static BOOL set_service_comment(char *comment) {
+ SC_HANDLE scm;
+ SC_HANDLE service;
+ SERVICE_DESCRIPTION sd;
+ BOOL ret = TRUE;
+ sd.lpDescription = comment;
+ if (!open_service_config(&scm,&service)) {
+ return FALSE;
+ }
+ if (!ChangeServiceConfig2(service,SERVICE_CONFIG_DESCRIPTION,&sd)) {
+ last_error = GetLastError();
+ ret = FALSE;
+ }
+ CloseServiceHandle(service);
+ CloseServiceHandle(scm);
+ return ret;
+}
+
+static BOOL wait_service_trans(DWORD initial, DWORD passes, DWORD goal,
+ int timeout)
+{
+ SC_HANDLE scm;
+ SC_HANDLE service;
+ int moved = 0;
+ BOOL ret;
+ int i;
+ SERVICE_STATUS stat;
+
+ if(! open_service_config(&scm,&service))
+ return FALSE;
+ for(i = 0; i < timeout; ++i){
+ if(!QueryServiceStatus(service,&stat)){
+ last_error = GetLastError();
+ ret = FALSE;
+ goto out;
+ }
+ if(stat.dwCurrentState == initial){
+ if(moved){
+ ret = FALSE;
+
+ /*
+ * The exitcode is usually strange when we tried to stop and failed,
+ * to report a timeout is more appropriate.
+ */
+ if(goal == SERVICE_STOPPED)
+ last_error = ERROR_SERVICE_REQUEST_TIMEOUT;
+ else
+ last_error = stat.dwWin32ExitCode;
+ goto out;
+ }
+ } else if(stat.dwCurrentState == passes){
+ moved = 1;
+ } else if(stat.dwCurrentState == goal){
+ ret = TRUE;
+ goto out;
+ }
+ Sleep(1000);
+ }
+ ret = FALSE;
+ last_error = ERROR_SERVICE_REQUEST_TIMEOUT;
+out:
+ CloseServiceHandle(scm);
+ CloseServiceHandle(service);
+ return ret;
+}
+
+static BOOL stop_service(void){
+ SC_HANDLE scm;
+ SC_HANDLE service;
+ BOOL ret;
+ SERVICE_STATUS ss;
+
+ if(!open_service_control(&scm,&service)){
+#ifdef HARDDEBUG
+ fprintf(stderr,"Failed to open service.\n");
+#endif
+ return FALSE;
+ }
+ ret = ControlService(service,SERVICE_CONTROL_STOP,&ss);
+ if(!ret){
+ last_error = GetLastError();
+ }
+ CloseServiceHandle(service);
+ CloseServiceHandle(scm);
+#ifdef HARDDEBUG
+ if(!ret)
+ {
+ fprintf(stderr,"Failed to control service.\n");
+ print_last_error();
+ }
+#endif
+ return ret;
+}
+
+static BOOL start_service(void){
+ SC_HANDLE scm;
+ SC_HANDLE service;
+ BOOL ret;
+
+ if(!open_service_control(&scm,&service))
+ return FALSE;
+
+ ret = StartService(service,0,NULL);
+ if(!ret){
+ last_error = GetLastError();
+ }
+ CloseServiceHandle(service);
+ CloseServiceHandle(scm);
+ return ret;
+}
+
+static BOOL disable_service(void){
+ SC_HANDLE scm;
+ SC_HANDLE service;
+ BOOL ret;
+
+ if(!open_service_config(&scm,&service))
+ return FALSE;
+
+ ret = ChangeServiceConfig(service,
+ SERVICE_NO_CHANGE,
+ SERVICE_DISABLED,
+ SERVICE_NO_CHANGE,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if(!ret){
+ last_error = GetLastError();
+ }
+
+ CloseServiceHandle(service);
+ CloseServiceHandle(scm);
+ return ret;
+}
+
+static BOOL enable_service(void){
+ SC_HANDLE scm;
+ SC_HANDLE service;
+ BOOL ret;
+
+if(!open_service_config(&scm,&service))
+ return FALSE;
+
+ ret = ChangeServiceConfig(service,
+ SERVICE_NO_CHANGE,
+ SERVICE_AUTO_START,
+ SERVICE_NO_CHANGE,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ if(!ret){
+ last_error = GetLastError();
+ }
+ CloseServiceHandle(service);
+ CloseServiceHandle(scm);
+ return ret;
+}
+
+static BOOL set_interactive(BOOL interactive){
+ SC_HANDLE scm;
+ SC_HANDLE service;
+ BOOL ret;
+
+ if(!open_service_config(&scm,&service))
+ return FALSE;
+
+ ret = ChangeServiceConfig(service,
+ SERVICE_WIN32_OWN_PROCESS | ((interactive) ?
+ SERVICE_INTERACTIVE_PROCESS : 0),
+ SERVICE_NO_CHANGE,
+ SERVICE_NO_CHANGE,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ if(!ret){
+ last_error = GetLastError();
+ }
+ CloseServiceHandle(service);
+ CloseServiceHandle(scm);
+ return ret;
+}
+
+
+RegEntry *old_entries = NULL;
+
+BOOL fetch_current(RegEntry *new){
+ int i;
+
+ if(!(old_entries = get_keys(service_name)))
+ return FALSE;
+ for(i=0;i<num_reg_entries;++i)
+ new[i] = old_entries[i];
+ return TRUE;
+}
+
+void cleanup_old(){
+ if(old_entries != NULL)
+ free_keys(old_entries);
+}
+
+BOOL fill_in_defaults(RegEntry *new){
+ char filename[MAX_PATH];
+ char *ptr;
+
+
+ if(!GetModuleFileName(NULL, filename, MAX_PATH))
+ return FALSE;
+ for(ptr = filename + strlen(filename) - 1;
+ ptr > filename && *ptr != '\\';
+ --ptr)
+ ;
+ if(*ptr == '\\')
+ ++ptr;
+ *ptr = '\0';
+
+ ptr = malloc(strlen(filename)+strlen(ERLANG_MACHINE)+1);
+ strcpy(ptr,filename);
+ strcat(ptr,ERLANG_MACHINE);
+
+ new[StopAction].data.bytes = "";
+ new[OnFail].data.value = ON_FAIL_IGNORE;
+ new[Machine].data.bytes = ptr;
+ new[Machine].data.expand.unexpanded = ptr;
+ new[Env].data.bytes = "\0";
+ new[WorkDir].data.bytes = new[WorkDir].data.expand.unexpanded =
+ "";
+ new[Priority].data.value = NORMAL_PRIORITY_CLASS;
+ new[SName].data.bytes = service_name;
+ new[Name].data.bytes = "";
+ new[Args].data.bytes = new[Args].data.expand.unexpanded = "";
+ new[DebugType].data.value = DEBUG_TYPE_NO_DEBUG;
+ new[InternalServiceName].data.bytes = real_service_name;
+ new[Comment].data.bytes = "";
+ return TRUE;
+}
+
+int do_usage(char *arg0){
+ printf("Usage:\n");
+ printf("%s {set | add} <servicename>\n"
+ "\t[-st[opaction] [<erlang shell command>]]\n"
+ "\t[-on[fail] [{reboot | restart | restart_always}]]\n"
+ "\t[-m[achine] [<erl-command>]]\n"
+ "\t[-e[nv] [<variable>[=<value>]]]\n"
+ "\t[-w[orkdir] [<directory>]]\n"
+ "\t[-p[riority] [{low|high|realtime}]]\n"
+ "\t[{-sn[ame] | -n[ame]} [<nodename>]]\n"
+ "\t[-d[ebugtype] [{new|reuse|console}]]\n"
+ "\t[-ar[gs] [<limited erl arguments>]]\n\n"
+ "%s {start | stop | disable | enable} <servicename>\n\n"
+ "%s remove <servicename>\n\n"
+ "%s rename <servicename> <servicename>\n\n"
+ "%s list [<servicename>]\n\n"
+ "%s help\n\n",
+ arg0,arg0,arg0,arg0,arg0,arg0);
+ printf("Manipulates Erlang system services on Windows NT.\n\n");
+ printf("When no parameter to an option is specified, the option\n"
+ "is reset to it's default value. To set an empty argument\n"
+ "list, give option -args as last option on command line "
+ "with\n"
+ "no arguments.\n\n");
+ printf("Se Erlang documentation for full description.\n");
+ return 0;
+}
+
+int do_manage(int argc,char **argv){
+ char *action = argv[1];
+ RegEntry *current = empty_reg_tab();
+
+ if(argc < 3){
+ fprintf(stderr,"%s: No servicename given!\n",argv[0]);
+ do_usage(argv[0]);
+ return 1;
+ }
+ service_name = argv[2];
+ if(!fetch_current(current)){
+ fprintf(stderr,"%s: The service %s is not an erlsrv controlled service.\n",
+ argv[0],service_name);
+ return 1;
+ }
+ real_service_name = _strdup(current[InternalServiceName].data.bytes);
+ free_keys(current);
+
+ if(!_stricmp(action,"start")){
+ if(!start_service()){
+ fprintf(stderr,"%s: Failed to start service %s.\n",
+ argv[0],service_name);
+ print_last_error();
+ return 1;
+ } else {
+ if(!wait_service_trans(SERVICE_STOPPED, SERVICE_START_PENDING,
+ SERVICE_RUNNING, 60)){
+ fprintf(stderr,"%s: Failed to start service %s.\n",
+ argv[0],service_name);
+ print_last_error();
+ return 1;
+ }
+ printf("%s: Service %s started.\n",
+ argv[0],service_name);
+ return 0;
+ }
+ }
+ if(!_stricmp(action,"stop")){
+ if(!stop_service()){
+ fprintf(stderr,"%s: Failed to stop service %s.\n",
+ argv[0],service_name);
+ print_last_error();
+ return 1;
+ } else {
+ if(!wait_service_trans(SERVICE_RUNNING, SERVICE_STOP_PENDING,
+ SERVICE_STOPPED, 60)){
+ fprintf(stderr,"%s: Failed to stop service %s.\n",
+ argv[0],service_name);
+ print_last_error();
+ return 1;
+ }
+ printf("%s: Service %s stopped.\n",
+ argv[0],service_name);
+ return 0;
+ }
+ }
+ if(!_stricmp(action,"disable")){
+#if 0
+ if(stop_service()){
+ printf("%s: Service %s stopped.\n",
+ argv[0],service_name);
+ }
+#endif
+ if(!disable_service()){
+ fprintf(stderr,"%s: Failed to disable service %s.\n",
+ argv[0],service_name);
+ print_last_error();
+ return 1;
+ } else {
+ printf("%s: Service %s disabled.\n",
+ argv[0],service_name);
+ return 0;
+ }
+ }
+ if(!_stricmp(action,"enable")){
+ if(!enable_service()){
+ fprintf(stderr,"%s: Failed to enable service %s.\n",
+ argv[0],service_name);
+ print_last_error();
+ return 1;
+ } else {
+ printf("%s: Service %s enabled.\n",
+ argv[0],service_name);
+ return 0;
+ }
+ }
+ fprintf(stderr,"%s: Unrecignized argument %s.\n",
+ argv[0],action);
+ return 1;
+}
+
+int do_add_or_set(int argc, char **argv){
+ RegEntry *new_entries;
+ RegEntry *default_entries;
+ int add = 0;
+ int i;
+ int current;
+ int set_comment = 0;
+ new_entries = empty_reg_tab();
+ default_entries = empty_reg_tab();
+ if(argc < 3){
+ fprintf(stderr,"%s: No servicename given!\n",argv[0]);
+ do_usage(argv[0]);
+ return 1;
+ }
+ service_name = argv[2];
+ if(!_stricmp(argv[1],"add")){
+ if(fetch_current(default_entries)){
+ fprintf(stderr,"%s: A service with the name %s already "
+ "exists.\n",
+ argv[0],service_name);
+ return 1;
+ }
+ real_service_name = generate_real_service_name(service_name);
+ if(!fill_in_defaults(new_entries)){
+ fprintf(stderr,"%s: Internal error.\n", argv[0]);
+ return 1;
+ }
+ add = 1;
+ } else {
+ if(!fetch_current(new_entries)){
+ fprintf(stderr,"%s: No service with the name %s exists.\n",
+ argv[0], service_name);
+ return 1;
+ }
+ real_service_name = new_entries[InternalServiceName].data.bytes;
+ }
+
+ if(!fill_in_defaults(default_entries)){
+ fprintf(stderr,"%s: Internal error.\n", argv[0]);
+ return 1;
+ }
+
+ /* make sure env is malloced... */
+ new_entries[Env].data.bytes = envdup(new_entries[Env].data.bytes);
+
+ for(i = 3; i < argc; ++i){
+ switch((current = lookup_arg(argv[i]))){
+ case Comment:
+ set_comment = 1;
+ case Machine:
+ case WorkDir:
+ case Args:
+ if(i+1 >= argc){
+ new_entries[current].data.bytes =
+ default_entries[current].data.bytes;
+ new_entries[current].data.expand.unexpanded =
+ default_entries[current].data.expand.unexpanded;
+ } else {
+ new_entries[current].data.expand.unexpanded =
+ new_entries[current].data.bytes = argv[i+1];
+ ++i;
+ }
+ break;
+ case SName:
+ new_entries[Name].data.bytes = "";
+ case StopAction:
+ case Name:
+ if(i+1 >= argc ||
+ *argv[i+1] == '-' || *argv[i+1] == '/'){
+ new_entries[current].data.bytes =
+ default_entries[current].data.bytes;
+ } else {
+ new_entries[current].data.bytes = argv[i+1];
+ ++i;
+ }
+ break;
+ case OnFail:
+ if(i+1 >= argc ||
+ *argv[i+1] == '-' || *argv[i+1] == '/'){
+ new_entries[current].data.value =
+ default_entries[current].data.value;
+ } else {
+ if(!_stricmp(argv[i+1],"reboot"))
+ new_entries[current].data.value = ON_FAIL_REBOOT;
+ else if(!_stricmp(argv[i+1],"restart"))
+ new_entries[current].data.value = ON_FAIL_RESTART;
+ else if(!_stricmp(argv[i+1],"restart_always"))
+ new_entries[current].data.value = ON_FAIL_RESTART_ALWAYS;
+ else {
+ fprintf(stderr,"%s: Unrecognized keyword value %s.\n",
+ argv[0],argv[i+1]);
+ return 1;
+ }
+ ++i;
+ }
+ break;
+ case DebugType:
+ if(i+1 >= argc ||
+ *argv[i+1] == '-' || *argv[i+1] == '/'){
+ new_entries[current].data.value =
+ default_entries[current].data.value;
+ } else {
+ if(!_stricmp(argv[i+1],"new"))
+ new_entries[current].data.value = DEBUG_TYPE_NEW;
+ else if(!_stricmp(argv[i+1],"reuse"))
+ new_entries[current].data.value = DEBUG_TYPE_REUSE;
+ else if(!_stricmp(argv[i+1],"console"))
+ new_entries[current].data.value = DEBUG_TYPE_CONSOLE;
+ else {
+ fprintf(stderr,"%s: Unrecognized keyword value %s.\n",
+ argv[0],argv[i+1]);
+ return 1;
+ }
+ ++i;
+ }
+ break;
+ case Priority:
+ if(i+1 >= argc ||
+ *argv[i+1] == '-' || *argv[i+1] == '/'){
+ new_entries[current].data.value =
+ default_entries[current].data.value;
+ } else {
+ if(!_stricmp(argv[i+1],"high"))
+ new_entries[current].data.value = HIGH_PRIORITY_CLASS;
+ else if(!_stricmp(argv[i+1],"low"))
+ new_entries[current].data.value = IDLE_PRIORITY_CLASS;
+ else if(!_stricmp(argv[i+1],"realtime"))
+ new_entries[current].data.value = REALTIME_PRIORITY_CLASS;
+ else {
+ fprintf(stderr,"%s: Unrecognized keyword value %s.\n",
+ argv[0],argv[i+1]);
+ return 1;
+ }
+ ++i;
+ }
+ break;
+
+ case Env:
+ if(i+1 >= argc ||
+ *argv[i+1] == '-' || *argv[i+1] == '/'){
+ fprintf(stderr,"%s: %s requires a parameter.\n",
+ argv[0],argv[i]);
+ return 1;
+ }
+ new_entries[current].data.bytes =
+ edit_env(argv[i+1],
+ new_entries[current].data.bytes);
+ ++i;
+ break;
+ case InternalServiceName:
+ if (!add) {
+ fprintf(stderr,"%s: %s only allowed when adding a new service.\n",
+ argv[0],argv[i]);
+ return 1;
+ }
+ if(i+1 >= argc){
+ fprintf(stderr,"%s: %s requires a parameter.\n",
+ argv[0],argv[i]);
+ return 1;
+ }
+ new_entries[InternalServiceName].data.expand.unexpanded =
+ new_entries[InternalServiceName].data.bytes = argv[i+1];
+ ++i;
+ /* Discard old, should maybe be fred' but we'll exit anyway */
+ real_service_name = new_entries[InternalServiceName].data.bytes;
+ break;
+ default:
+ fprintf(stderr,"%s: Unrecognized option %s.\n", argv[0],
+ argv[i]);
+ return 1;
+ }
+ }
+ if(*new_entries[SName].data.bytes &&
+ *new_entries[Name].data.bytes){
+#if 0
+ fprintf(stderr,"%s: Both -sname and -name specified.\n",
+ argv[0]);
+ return 1;
+#else
+ new_entries[SName].data.bytes = "";
+#endif
+ }
+ if(add && !(*new_entries[SName].data.bytes) &&
+ !(*new_entries[Name].data.bytes)){
+ fprintf(stderr,"%s: Neither -sname nor -name specified.\n",
+ argv[0]);
+ return 1;
+ }
+ if(add && !install_service()){
+ fprintf(stderr,"%s: Unable to register service with service manager.\n",
+ argv[0], service_name);
+ print_last_error();
+ return 1;
+ }
+ if(!set_interactive(new_entries[DebugType].data.value ==
+ DEBUG_TYPE_CONSOLE)){
+ fprintf(stderr,"%s: Warning, could not set correct interactive mode.\n",
+ argv[0], service_name);
+ print_last_error();
+ /* Not severe or??? */
+ }
+ /* Update registry */
+ register_logkeys();
+ set_keys(service_name, new_entries);
+ /* Update service comment if needed */
+ if(set_comment) {
+ if (!set_service_comment(new_entries[Comment].data.bytes)) {
+ fprintf(stderr,"%s: Warning, could not set correct "
+ "service description (comment)",
+ argv[0], service_name);
+ print_last_error();
+ }
+ }
+
+ /* As I do this, I should also clean up the new entries, which is
+ somewhat harder as I really dont know what is and what is not
+ malloced, but we'll exit anyway, so... */
+ cleanup_old();
+ if(add)
+ printf("%s: Service %s added to system.\n",
+ argv[0], service_name);
+ else
+ printf("%s: Service %s updated.\n",
+ argv[0], service_name);
+ return 0;
+}
+int do_rename(int argc, char **argv){
+ RegEntry *current = empty_reg_tab();
+ RegEntry *dummy = empty_reg_tab();
+ SC_HANDLE scm;
+ SC_HANDLE service;
+ if(argc < 3){
+ fprintf(stderr,"%s: No old servicename given!\n",argv[0]);
+ do_usage(argv[0]);
+ return 1;
+ }
+ if(argc < 4){
+ fprintf(stderr,"%s: No new servicename given!\n",argv[0]);
+ do_usage(argv[0]);
+ return 1;
+ }
+ service_name = argv[3];
+ if(fetch_current(dummy)){
+ fprintf(stderr,"%s: A service with the name %s already "
+ "exists.\n",
+ argv[0],service_name);
+ return 1;
+ }
+ service_name = argv[2];
+
+ if(!fetch_current(current)){
+ fprintf(stderr,"%s: Error, old service name %s does not exist.\n",
+ argv[0],service_name);
+ return 1;
+ }
+ real_service_name = _strdup(current[InternalServiceName].data.bytes);
+ if(!open_service_config(&scm,&service)){
+ fprintf(stderr,"%s: Error, unable to communicate with service control"
+ " manager.\n",
+ argv[0]);
+ print_last_error();
+ return 1;
+ }
+ if(!ChangeServiceConfig(service,
+ SERVICE_NO_CHANGE,
+ SERVICE_NO_CHANGE,
+ SERVICE_NO_CHANGE,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ argv[3])){
+ fprintf(stderr,"%s: Error, unable to communicate with service control"
+ " manager.\n",
+ argv[0]);
+ print_last_error();
+ CloseServiceHandle(scm);
+ CloseServiceHandle(service);
+ return 1;
+ }
+ CloseServiceHandle(scm);
+ CloseServiceHandle(service);
+
+ if(remove_keys(service_name) != 0)
+ fprintf(stderr,"%s: Warning, old service parameter keys could not "
+ "be removed, continuing.\n", argv[0]);
+ /* Update registry */
+ register_logkeys();
+ set_keys(argv[3], current);
+
+ printf("%s: Service %s renamed to %s.\n",
+ argv[0], service_name, argv[3]);
+ return 0;
+}
+
+int do_remove(int argc, char **argv){
+ RegEntry *current = empty_reg_tab();
+ int rem_res;
+ BOOL found;
+
+ if(argc < 3){
+ fprintf(stderr,"%s: No servicename given!\n",argv[0]);
+ do_usage(argv[0]);
+ return 1;
+ }
+ service_name = argv[2];
+ found = fetch_current(current);
+ if(found){
+ real_service_name = _strdup(current[InternalServiceName].data.bytes);
+ } else {
+ real_service_name = _strdup(service_name);
+ }
+ if(found)
+ free_keys(current);
+ if(stop_service() && !wait_service_trans(SERVICE_RUNNING,
+ SERVICE_STOP_PENDING,
+ SERVICE_STOPPED, 60)){
+ fprintf(stderr,"%s: Failed to stop running service %s.\n",
+ argv[0],service_name);
+ print_last_error();
+ return 1;
+ }
+ if(!remove_service()){
+ fprintf(stderr,"%s: Unable to remove service (not enough "
+ "privileges?)\n",argv[0]);
+ print_last_error();
+ return 1;
+ }
+
+ if((rem_res = remove_keys(service_name)) > 0){
+ fprintf(stderr,"%s: Warning, service parameter keys belonged to old "
+ "erlsrv version.\n", argv[0]);
+ /* Backward compatibility... */
+ } else if(rem_res < 0) {
+ fprintf(stderr,"%s: Error, service parameter keys nonexistent.\n",
+ argv[0]);
+ return 1;
+ }
+ printf("%s: Service %s removed from system.\n",
+ argv[0], service_name);
+ return 0;
+}
+
+BOOL list_one(char *servicename, RegEntry *keys, BOOL longlist){
+ char *onfail;
+ char *prio;
+ char *debugtype;
+ switch(keys[OnFail].data.value){
+ case ON_FAIL_RESTART:
+ onfail = "restart";
+ break;
+ case ON_FAIL_RESTART_ALWAYS:
+ onfail = "restart_always";
+ break;
+ case ON_FAIL_REBOOT:
+ onfail = "reboot";
+ break;
+ default:
+ onfail = "ignore";
+ }
+ switch(keys[DebugType].data.value){
+ case DEBUG_TYPE_NEW:
+ debugtype = "new";
+ break;
+ case DEBUG_TYPE_REUSE:
+ debugtype = "reuse";
+ break;
+ case DEBUG_TYPE_CONSOLE:
+ debugtype = "console";
+ break;
+ default:
+ debugtype = "none";
+ }
+ switch(keys[Priority].data.value){
+ case HIGH_PRIORITY_CLASS:
+ prio = "high";
+ break;
+ case IDLE_PRIORITY_CLASS:
+ prio = "low";
+ break;
+ case REALTIME_PRIORITY_CLASS:
+ prio = "realtime";
+ break;
+ case NORMAL_PRIORITY_CLASS:
+ prio = "default";
+ break;
+ default:
+ prio = "unknown/faulty";
+ }
+
+
+ if(longlist){
+ char *env = envdup(keys[Env].data.bytes);
+ char **arg = env_to_arg(env);
+ char **pek = arg;
+ printf("Service name: %s\n",
+ servicename);
+ printf("StopAction: %s\n",
+ keys[StopAction].data.bytes);
+ printf("OnFail: %s\n",onfail);
+ printf("Machine: %s\n",
+ keys[Machine].data.expand.unexpanded);
+ printf("WorkDir: %s\n",
+ keys[WorkDir].data.expand.unexpanded);
+ if(*keys[SName].data.bytes)
+ printf("SName: %s\n",
+ keys[SName].data.bytes);
+ else
+ printf("Name: %s\n",
+ keys[Name].data.bytes);
+ printf("Priority: %s\n",prio);
+ printf("DebugType: %s\n",debugtype);
+ printf("Args: %s\n",
+ keys[Args].data.expand.unexpanded);
+ printf("InternalServiceName: %s\n",
+ keys[InternalServiceName].data.bytes);
+ printf("Comment: %s\n",
+ keys[Comment].data.bytes);
+ printf("Env:\n");
+ while(*pek){
+ printf("\t%s\n",*pek);
+ ++pek;
+ }
+ /* env is easier to free...*/
+ env = arg_to_env(arg);
+ free(env);
+ } else {
+ printf("%s\t%s\t%s\t%s\t%s\n",
+ servicename,
+ (*keys[Name].data.bytes) ?
+ keys[Name].data.bytes :
+ keys[SName].data.bytes,
+ prio,
+ onfail,
+ keys[Args].data.expand.unexpanded);
+ }
+ return TRUE;
+}
+
+
+int do_list(int argc, char **argv){
+ if(argc < 3){
+ RegEntryDesc *all_keys = get_all_keys();
+ if(!all_keys){
+ fprintf(stderr,"%s: No services found in registry.\n",
+ argv[0]);
+ return 0;
+ }
+ printf("Service\t(S)Name\tPrio\tOnFail\tArgs\n");
+ while(all_keys->servicename){
+ list_one(all_keys->servicename,all_keys->entries,FALSE);
+ ++all_keys;
+ }
+ return 0;
+ } else {
+ RegEntry *keys;
+ service_name = argv[2];
+ keys = get_keys(service_name);
+ if(!keys){
+ fprintf(stderr,"%s: Could not retrieve any "
+ "registered data for %s.\n",argv[0],service_name);
+ return 1;
+ }
+ list_one(service_name, keys, TRUE);
+ }
+ return 0;
+}
+
+#define READ_CHUNK 100
+#define ARGV_CHUNK 20
+
+char *safe_get_line(void){
+ int lsize = READ_CHUNK;
+ char *line = malloc(READ_CHUNK);
+ int pos = 0;
+ int ch;
+
+ while((ch = getchar()) != EOF && ch != '\n'){
+ if(pos + 1 >= lsize){
+ line = realloc(line,(lsize += READ_CHUNK));
+ assert(line);
+ }
+ line[pos++] = ch;
+ }
+ if(ch == EOF || !pos){
+ free(line);
+ return NULL;
+ }
+ line[pos] = '\0';
+ return line;
+}
+
+
+void read_arguments(int *pargc, char ***pargv){
+ int argc = 0;
+ int asize = ARGV_CHUNK;
+ char **argv = malloc(ARGV_CHUNK*sizeof(char *));
+ char *tmp;
+
+ argv[0] = (*pargv)[0];
+ argc = 1;
+ while((tmp = safe_get_line()) != NULL){
+ if(argc + 1 >= asize){
+ argv = realloc(argv,(asize += ARGV_CHUNK)*sizeof(char *));
+ assert(argv);
+ }
+ argv[argc++] = tmp;
+ }
+ argv[argc] = NULL;
+ *pargc = argc;
+ *pargv = argv;
+}
+
+
+int interactive_main(int argc, char **argv){
+ char *action = argv[1];
+
+ if(!_stricmp(action,"readargs")){
+ read_arguments(&argc,&argv);
+ action = argv[1];
+ }
+ if(!_stricmp(action,"set") || !_stricmp(action,"add"))
+ return do_add_or_set(argc,argv);
+ if(!_stricmp(action,"rename"))
+ return do_rename(argc,argv);
+ if(!_stricmp(action,"remove"))
+ return do_remove(argc,argv);
+ if(!_stricmp(action,"list"))
+ return do_list(argc,argv);
+ if(!_stricmp(action,"start") ||
+ !_stricmp(action,"stop") ||
+ !_stricmp(action,"enable") ||
+ !_stricmp(action,"disable"))
+ return do_manage(argc,argv);
+ if(_stricmp(action,"?") &&
+ _stricmp(action,"/?") &&
+ _stricmp(action,"-?") &&
+ *action != 'h' &&
+ *action != 'H')
+ fprintf(stderr,"%s: action %s not implemented.\n",argv[0],action);
+ do_usage(argv[0]);
+ return 1;
+}
+
diff --git a/erts/etc/win32/erlsrv/erlsrv_interactive.h b/erts/etc/win32/erlsrv/erlsrv_interactive.h
new file mode 100644
index 0000000000..deacf81899
--- /dev/null
+++ b/erts/etc/win32/erlsrv/erlsrv_interactive.h
@@ -0,0 +1,24 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifndef _ERLSRV_INTERACTIVE_H
+#define _ERLSRV_INTERACTIVE_H
+
+int interactive_main(int argc, char **argv);
+
+#endif /* _ERLSRV_INTERACTIVE_H */
diff --git a/erts/etc/win32/erlsrv/erlsrv_logmess.mc b/erts/etc/win32/erlsrv/erlsrv_logmess.mc
new file mode 100644
index 0000000000..354ac14c9f
--- /dev/null
+++ b/erts/etc/win32/erlsrv/erlsrv_logmess.mc
@@ -0,0 +1,33 @@
+;/*MessageIDTypedef=WORD*/
+;
+;/*MessageID=0x1*/
+;/*SymbolicName=CAT_GENERIC*/
+;/*Language=English*/
+;/*Generic Category*/
+;/*.*/
+;
+MessageIDTypedef=DWORD
+
+MessageID=0x10
+Severity=Warning
+Facility=Application
+SymbolicName=MSG_WARNING
+Language=English
+%1: %2
+.
+MessageID=0x11
+Severity=Error
+Facility=Application
+SymbolicName=MSG_ERROR
+Language=English
+%1: %2
+.
+MessageID=0x12
+Severity=Informational
+Facility=Application
+SymbolicName=MSG_INFO
+Language=English
+%1: %2
+.
+
+
diff --git a/erts/etc/win32/erlsrv/erlsrv_main.c b/erts/etc/win32/erlsrv/erlsrv_main.c
new file mode 100644
index 0000000000..920a4a1827
--- /dev/null
+++ b/erts/etc/win32/erlsrv/erlsrv_main.c
@@ -0,0 +1,44 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#include <windows.h>
+#include <winsvc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "erlsrv_global.h"
+#include "erlsrv_interactive.h"
+#include "erlsrv_service.h"
+
+int main(int argc, char **argv){
+ if(argc > 1)
+ return interactive_main(argc,argv);
+ else
+ return service_main(argc,argv);
+}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/erts/etc/win32/erlsrv/erlsrv_registry.c b/erts/etc/win32/erlsrv/erlsrv_registry.c
new file mode 100644
index 0000000000..c1aa9f2b67
--- /dev/null
+++ b/erts/etc/win32/erlsrv/erlsrv_registry.c
@@ -0,0 +1,404 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#include <windows.h>
+#include <winsvc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "erlsrv_global.h"
+#include "erlsrv_registry.h"
+
+#define LOG_TYPE "System"
+#define LOG_ROOT \
+"SYSTEM\\CurrentControlSet\\Services\\EventLog\\" LOG_TYPE "\\"
+#define LOG_APP_KEY APP_NAME
+
+
+#define BASE_KEY HKEY_LOCAL_MACHINE
+#define PRODUCT_NAME APP_NAME
+#define OLD_PRODUCT_VERSION "1.0"
+#define PRODUCT_VERSION "1.1"
+#define PROG_KEY "SOFTWARE\\Ericsson\\Erlang\\" PRODUCT_NAME "\\" PRODUCT_VERSION
+#define OLD_PROG_KEY "SOFTWARE\\Ericsson\\Erlang\\" PRODUCT_NAME "\\" OLD_PRODUCT_VERSION
+
+#define MAX_KEY_LEN MAX_PATH
+
+static const char * const noString = "\0";
+
+#define MAX_MANDATORY_REG_ENTRY 10 /* InternalServiceName == reg_entries[10] */
+static RegEntry reg_entries[] = {
+ {"StopAction",REG_SZ,NULL},
+ {"OnFail",REG_DWORD,NULL},
+ {"Machine",REG_EXPAND_SZ,NULL},
+ {"Env", REG_MULTI_SZ,NULL},
+ {"WorkDir", REG_EXPAND_SZ,NULL},
+ {"Priority",REG_DWORD,NULL},
+ {"SName",REG_SZ,NULL},
+ {"Name",REG_SZ,NULL},
+ {"Args",REG_EXPAND_SZ,NULL},
+ {"DebugType",REG_DWORD,NULL},
+ {"InternalServiceName",REG_SZ,NULL},
+ /* Non mandatory follows */
+ {"Comment",REG_SZ,NULL}
+};
+
+
+int num_reg_entries = sizeof(reg_entries)/sizeof(RegEntry);
+
+RegEntry *empty_reg_tab(void){
+ RegEntry *ret = malloc(num_reg_entries * sizeof(RegEntry));
+ memcpy(ret,reg_entries,num_reg_entries * sizeof(RegEntry));
+ return ret;
+}
+
+void free_keys(RegEntry *keys){
+ int i;
+
+ for(i=0;i<num_reg_entries && keys[i].name != NULL;++i){
+ if((keys[i].type == REG_SZ || keys[i].type == REG_EXPAND_SZ ||
+ keys[i].type == REG_MULTI_SZ) &&
+ keys[i].data.bytes != noString){
+ free(keys[i].data.bytes);
+ if(keys[i].type == REG_EXPAND_SZ &&
+ keys[i].data.expand.unexpanded != noString)
+ free(keys[i].data.expand.unexpanded);
+ }
+ }
+ free(keys);
+}
+
+void free_all_keys(RegEntryDesc *descs){
+ RegEntryDesc *tmp = descs;
+ for(;tmp->servicename != NULL; ++tmp){
+ free_keys(tmp->entries);
+ free(tmp->servicename);
+ }
+ free(descs);
+}
+
+RegEntry *get_keys(char *servicename){
+ RegEntry *res = NULL;
+ HKEY prog_key;
+ int key_opened = 0;
+ int i;
+ DWORD ret;
+ char *copy;
+ char *tmpbuf;
+ DWORD tmpbuflen;
+
+ char key_to_open[MAX_KEY_LEN];
+
+ DWORD val_type;
+ char *val_data = malloc(MAX_KEY_LEN);
+ DWORD val_datalen;
+ DWORD val_datasiz = MAX_KEY_LEN;
+
+ if(strlen(PROG_KEY) + strlen(servicename) + 2 > MAX_KEY_LEN)
+ goto error;
+ sprintf(key_to_open,"%s\\%s",PROG_KEY,servicename);
+
+ if(RegOpenKeyEx(BASE_KEY,
+ key_to_open,
+ 0,
+ KEY_QUERY_VALUE,
+ &prog_key) != ERROR_SUCCESS)
+ goto error;
+ key_opened = 1;
+
+ res = malloc(num_reg_entries*sizeof(RegEntry));
+ for(i=0;i<num_reg_entries;++i)
+ res[i].name = NULL;
+
+ for(i=0;i<num_reg_entries;++i){
+ for(;;){
+ val_datalen = val_datasiz;
+ ret = RegQueryValueEx(prog_key,
+ reg_entries[i].name,
+ NULL,
+ &val_type,
+ (BYTE *) val_data,
+ &val_datalen);
+ if(ret == ERROR_SUCCESS){
+ if(reg_entries[i].type == val_type)
+ break;
+ else
+ goto error;
+ } else if(ret == ERROR_MORE_DATA){
+ val_data = realloc(val_data,val_datasiz = val_datalen);
+ } else if (i > MAX_MANDATORY_REG_ENTRY && ret == ERROR_FILE_NOT_FOUND) {
+ /* Non mandatory entries, look at the type... */
+ switch (reg_entries[i].type){
+ case REG_EXPAND_SZ:
+ case REG_SZ:
+ case REG_MULTI_SZ:
+ val_datalen = 0;
+ break;
+ case REG_DWORD:
+ {
+ DWORD dummy = 0;
+ memcpy(val_data,&dummy,(val_datalen = sizeof(DWORD)));
+ }
+ break;
+ default:
+ goto error;
+ }
+ break; /* for(;;) */
+ } else {
+ goto error;
+ }
+ }
+ res[i] = reg_entries[i];
+ copy = NULL;
+ switch(reg_entries[i].type){
+ case REG_EXPAND_SZ:
+ if(!val_datalen || val_data[0] == '\0'){
+ copy = (char *) noString;
+ res[i].data.expand.unexpanded = (char *) noString;
+ } else {
+ tmpbuf = malloc(MAX_KEY_LEN);
+ tmpbuflen = (DWORD) MAX_KEY_LEN;
+ for(;;){
+ ret = ExpandEnvironmentStrings(val_data,tmpbuf,tmpbuflen);
+ if(!ret){
+ free(tmpbuf);
+ goto error;
+ }else if(ret > tmpbuflen){
+ tmpbuf=realloc(tmpbuf,tmpbuflen=ret);
+ } else {
+ copy = strdup(tmpbuf);
+ free(tmpbuf);
+ break;
+ }
+ }
+ res[i].data.expand.unexpanded = strdup(val_data);
+ }
+ case REG_MULTI_SZ:
+ case REG_SZ:
+ if(!copy){
+ if(!val_datalen ||
+ ((val_datalen == 1 && val_data[0] == '\0') ||
+ (val_datalen == 2 && val_data[0] == '\0' &&
+ val_data[1] == '\0'))){
+ copy = (char *) noString;
+ } else {
+ copy = malloc(val_datalen);
+ memcpy(copy,val_data,val_datalen);
+ }
+ }
+ res[i].data.bytes = copy;
+ break;
+ case REG_DWORD:
+ memcpy(&res[i].data.value,val_data,sizeof(DWORD));
+ break;
+ default:
+ goto error;
+ }
+ }
+ RegCloseKey(prog_key);
+ free(val_data);
+ return res;
+error:
+ free(val_data);
+ if(res != NULL)
+ free_keys(res);
+ if(key_opened)
+ RegCloseKey(prog_key);
+ return NULL;
+}
+
+int set_keys(char *servicename, RegEntry *keys){
+ HKEY prog_key;
+ int key_opened = 0;
+ int i;
+ char key_to_open[MAX_KEY_LEN];
+ DWORD disposition;
+
+ if(strlen(PROG_KEY) + strlen(servicename) + 2 > MAX_KEY_LEN)
+ goto error;
+ sprintf(key_to_open,"%s\\%s",PROG_KEY,servicename);
+
+ if(RegOpenKeyEx(BASE_KEY,
+ key_to_open,
+ 0,
+ KEY_SET_VALUE,
+ &prog_key) != ERROR_SUCCESS){
+ if(RegCreateKeyEx(BASE_KEY,
+ key_to_open,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_SET_VALUE,
+ NULL,
+ &prog_key,
+ &disposition) != ERROR_SUCCESS)
+ goto error;
+ }
+ key_opened = 1;
+
+
+ for(i=0;i<num_reg_entries;++i){
+ void *ptr;
+ DWORD siz;
+ int j;
+ switch(keys[i].type){
+ case REG_SZ:
+ ptr = keys[i].data.bytes;
+ siz = strlen(ptr)+1;
+ break;
+ case REG_EXPAND_SZ:
+ ptr = keys[i].data.expand.unexpanded;
+ siz = strlen(ptr)+1;
+ break;
+ case REG_MULTI_SZ:
+ ptr = keys[i].data.bytes;
+ for(j=0;!(((char *)ptr)[j] == '\0' &&
+ ((char *)ptr)[j+1] == '\0');++j)
+ ;
+ siz=(DWORD)j+2;
+ break;
+ case REG_DWORD:
+ ptr = &keys[i].data.value;
+ siz = sizeof(DWORD);
+ break;
+ default:
+ goto error;
+ }
+#ifdef HARDDEBUG
+ fprintf(stderr,"%s %s:%d\n",keys[i].name,
+ (keys[i].type == REG_DWORD) ? "(dword)" : ptr,siz);
+#endif
+ if(RegSetValueEx(prog_key,
+ keys[i].name,
+ 0,
+ keys[i].type,
+ ptr,
+ siz) != ERROR_SUCCESS)
+ goto error;
+ }
+ RegCloseKey(prog_key);
+ return 0;
+error:
+ if(key_opened)
+ RegCloseKey(prog_key);
+ return 1;
+}
+
+static int do_remove_keys(char *servicename, const char *prog_key_name){
+ HKEY prog_key;
+ if(RegOpenKeyEx(BASE_KEY,
+ prog_key_name,
+ 0,
+ KEY_ALL_ACCESS,
+ &prog_key) != ERROR_SUCCESS)
+ return -1;
+ if(RegDeleteKey(prog_key,servicename) != ERROR_SUCCESS){
+ RegCloseKey(prog_key);
+ return -1;
+ }
+ RegCloseKey(prog_key);
+ return 0;
+}
+
+int remove_keys(char *servicename){
+ int ret;
+
+ if((ret = do_remove_keys(servicename, PROG_KEY)) < 0){
+ if(!do_remove_keys(servicename, OLD_PROG_KEY))
+ return 1;
+ else
+ return -1;
+ }
+ return ret;
+}
+
+
+RegEntryDesc *get_all_keys(void){
+ RegEntryDesc *res = malloc(10*sizeof(RegEntryDesc));
+ int res_siz = 10;
+ int ndx = 0;
+ HKEY prog_key;
+ int key_opened = 0;
+ DWORD enum_index;
+ char name[MAX_KEY_LEN];
+ DWORD namelen;
+ char class[MAX_KEY_LEN];
+ DWORD classlen;
+ FILETIME ft;
+
+ res[ndx].servicename = NULL;
+ if(RegOpenKeyEx(BASE_KEY, PROG_KEY, 0,
+ KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
+ &prog_key) != ERROR_SUCCESS)
+ goto error;
+ key_opened = 1;
+ for(enum_index = 0, namelen = MAX_KEY_LEN, classlen = MAX_KEY_LEN;
+ ERROR_SUCCESS == RegEnumKeyEx(prog_key,
+ enum_index,
+ name,
+ &namelen,
+ NULL,
+ class,
+ &classlen,
+ &ft);
+ ++enum_index, namelen = MAX_KEY_LEN, classlen = MAX_KEY_LEN){
+ if(ndx >= res_siz - 1)
+ res = realloc(res, (res_siz += 10)*sizeof(RegEntryDesc));
+ if(!(res[ndx].entries = get_keys(name)))
+ goto error;
+ res[ndx].servicename = strdup(name);
+ res[++ndx].servicename = NULL;
+ }
+ RegCloseKey(prog_key);
+ return res;
+error:
+ if(key_opened)
+ RegCloseKey(prog_key);
+ free_all_keys(res);
+ return NULL;
+}
+
+int register_logkeys(void){
+ HKEY key;
+ DWORD disposition;
+ DWORD types = EVENTLOG_ERROR_TYPE |
+ EVENTLOG_WARNING_TYPE |
+ EVENTLOG_INFORMATION_TYPE;
+ DWORD catcount=1;
+ char filename[2048];
+ DWORD fnsiz=2048;
+
+ if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,
+ LOG_ROOT LOG_APP_KEY, 0,
+ NULL, REG_OPTION_NON_VOLATILE,
+ KEY_SET_VALUE, NULL,
+ &key, &disposition) != ERROR_SUCCESS)
+ return -1;
+ if(!GetModuleFileName(NULL, filename, fnsiz))
+ return -1;
+ if(RegSetValueEx(key, "EventMessageFile",
+ 0, REG_EXPAND_SZ, (LPBYTE) filename,
+ strlen(filename)+1) != ERROR_SUCCESS)
+ return -1;
+ if(RegSetValueEx(key, "TypesSupported",
+ 0, REG_DWORD, (LPBYTE) &types,
+ sizeof(DWORD)) != ERROR_SUCCESS)
+ return -1;
+ return 0;
+}
+
diff --git a/erts/etc/win32/erlsrv/erlsrv_registry.h b/erts/etc/win32/erlsrv/erlsrv_registry.h
new file mode 100644
index 0000000000..fbccc5416a
--- /dev/null
+++ b/erts/etc/win32/erlsrv/erlsrv_registry.h
@@ -0,0 +1,76 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifndef _ERLSRV_REGISTRY_H
+#define _ERLSRV_REGISTRY_H
+
+typedef struct _reg_entry {
+ char *name;
+ DWORD type;
+ union {
+ char *bytes;
+ DWORD value;
+ struct {
+ char *bytes;
+ char *unexpanded;
+ } expand;
+ } data;
+} RegEntry;
+
+typedef struct _reg_entry_desc {
+ char *servicename;
+ RegEntry *entries;
+} RegEntryDesc;
+
+enum {
+ StopAction,
+ OnFail,
+ Machine,
+ Env,
+ WorkDir,
+ Priority,
+ SName,
+ Name,
+ Args,
+ DebugType,
+ InternalServiceName,
+ Comment
+};
+
+#define ON_FAIL_IGNORE 0
+#define ON_FAIL_RESTART 1
+#define ON_FAIL_REBOOT 2
+#define ON_FAIL_RESTART_ALWAYS 3
+
+#define DEBUG_TYPE_NO_DEBUG 0
+#define DEBUG_TYPE_NEW 1
+#define DEBUG_TYPE_REUSE 2
+#define DEBUG_TYPE_CONSOLE 3
+
+extern int num_reg_entries;
+
+RegEntry *empty_reg_tab(void);
+void free_keys(RegEntry *keys);
+void free_all_keys(RegEntryDesc *descs);
+RegEntry *get_keys(char *servicename);
+int set_keys(char *servicename, RegEntry *keys);
+RegEntryDesc *get_all_keys(void);
+int remove_keys(char *servicename);
+int register_logkeys(void);
+#endif /* _ERLSRV_REGISTRY_H */
+
diff --git a/erts/etc/win32/erlsrv/erlsrv_service.c b/erts/etc/win32/erlsrv/erlsrv_service.c
new file mode 100644
index 0000000000..a58ee862c5
--- /dev/null
+++ b/erts/etc/win32/erlsrv/erlsrv_service.c
@@ -0,0 +1,966 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#include <windows.h>
+#include <winsvc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "erlsrv_global.h"
+#include "erlsrv_registry.h"
+#include "erlsrv_util.h"
+#include "erlsrv_service.h"
+
+static HANDLE eventStop;
+
+static HANDLE eventKillErlang;
+
+static CRITICAL_SECTION crit;
+
+static SERVICE_STATUS_HANDLE statusHandle;
+
+static DWORD currentState;
+
+static void fill_status(SERVICE_STATUS *status){
+ status->dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ status->dwCurrentState = 0;
+ status->dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
+ status->dwWin32ExitCode = NO_ERROR;
+ status->dwServiceSpecificExitCode = 0;
+ status->dwCheckPoint = 0;
+ status->dwWaitHint = 0;
+}
+
+static BOOL set_start_pending(int waithint, int checkpoint){
+ SERVICE_STATUS stat;
+ fill_status(&stat);
+ EnterCriticalSection(&crit);
+ currentState = stat.dwCurrentState = SERVICE_START_PENDING;
+ LeaveCriticalSection(&crit);
+ stat.dwControlsAccepted = 0;
+ stat.dwCheckPoint = checkpoint;
+ stat.dwWaitHint = waithint;
+ return SetServiceStatus(statusHandle, &stat);
+}
+
+static BOOL set_stop_pending(int waithint, int checkpoint){
+ SERVICE_STATUS stat;
+ fill_status(&stat);
+ EnterCriticalSection(&crit);
+ currentState = stat.dwCurrentState = SERVICE_STOP_PENDING;
+ LeaveCriticalSection(&crit);
+ stat.dwControlsAccepted = 0;
+ stat.dwCheckPoint = checkpoint;
+ stat.dwWaitHint = waithint;
+ return SetServiceStatus(statusHandle, &stat);
+}
+
+static BOOL set_running(){
+ SERVICE_STATUS stat;
+ fill_status(&stat);
+ EnterCriticalSection(&crit);
+ currentState = stat.dwCurrentState = SERVICE_RUNNING;
+ LeaveCriticalSection(&crit);
+ return SetServiceStatus(statusHandle, &stat);
+}
+
+static BOOL set_stopped(int error){
+ SERVICE_STATUS stat;
+ fill_status(&stat);
+ EnterCriticalSection(&crit);
+ currentState = stat.dwCurrentState = SERVICE_STOPPED;
+ LeaveCriticalSection(&crit);
+ stat.dwWin32ExitCode = error;
+ return SetServiceStatus(statusHandle, &stat);
+}
+
+static BOOL reset_current(){
+ SERVICE_STATUS stat;
+ fill_status(&stat);
+ EnterCriticalSection(&crit);
+ stat.dwCurrentState = currentState;
+ LeaveCriticalSection(&crit);
+ return SetServiceStatus(statusHandle, &stat);
+}
+
+static VOID WINAPI handler(DWORD control){
+ char buffer[1024];
+ sprintf(buffer,"handler called with control = %d.",(int) control);
+ log_debug(buffer);
+ switch(control){
+ case SERVICE_CONTROL_STOP:
+ set_stop_pending(30000,1);
+ SetEvent(eventStop);
+ return;
+ case SERVICE_CONTROL_SHUTDOWN:
+ return;
+ default:
+ reset_current();
+ break;
+ }
+ return;
+}
+
+typedef struct _server_info {
+ RegEntry *keys;
+ PROCESS_INFORMATION info;
+ HANDLE erl_stdin;
+ char *event_name;
+} ServerInfo;
+
+
+typedef struct {
+ BOOL initialized;
+ TOKEN_DEFAULT_DACL *defdacl;
+ PACL newacl;
+ PSID adminsid;
+} SaveAclStruct;
+
+
+static BOOL reset_acl(SaveAclStruct *save_acl){
+ HANDLE tokenh;
+
+ if(!save_acl->initialized)
+ return FALSE;
+ if(!OpenProcessToken(GetCurrentProcess(),
+ TOKEN_READ|TOKEN_WRITE,&tokenh)){
+ log_warning("Failed to open access token.");
+ return FALSE;
+ }
+ save_acl->initialized = FALSE;
+ if(!SetTokenInformation(tokenh,
+ TokenDefaultDacl,
+ save_acl->defdacl,
+ sizeof(TOKEN_DEFAULT_DACL))){
+ log_warning("Failed to get default ACL from token.");
+ CloseHandle(tokenh);
+ LocalFree(save_acl->defdacl);
+ LocalFree(save_acl->newacl);
+ FreeSid(save_acl->adminsid);
+ return FALSE;
+ }
+ CloseHandle(tokenh);
+ LocalFree(save_acl->defdacl);
+ LocalFree(save_acl->newacl);
+ FreeSid(save_acl->adminsid);
+ return TRUE;
+}
+
+
+static BOOL new_acl(SaveAclStruct *save_acl){
+ HANDLE tokenh;
+ TOKEN_DEFAULT_DACL newdacl;
+ DWORD required;
+ PACL oldacl;
+ PACL newacl;
+ int i;
+ ACL_SIZE_INFORMATION si;
+ size_t newsize;
+ PSID extra_sid;
+ SID_IDENTIFIER_AUTHORITY nt_auth = SECURITY_NT_AUTHORITY;
+ TOKEN_DEFAULT_DACL dummy;
+
+ save_acl->initialized = FALSE;
+ if(!OpenProcessToken(GetCurrentProcess(),
+ TOKEN_READ|TOKEN_WRITE,&tokenh)){
+ log_warning("Failed to open access token.");
+ return FALSE;
+ }
+ save_acl->defdacl = &dummy;
+ required = sizeof(TOKEN_DEFAULT_DACL);
+ GetTokenInformation(tokenh,
+ TokenDefaultDacl,
+ &(save_acl->defdacl),
+ sizeof(TOKEN_DEFAULT_DACL),
+ &required);
+ if(required == 0){
+ log_warning("Failed to get any ACL info from token.");
+ CloseHandle(tokenh);
+ return FALSE;
+ }
+ save_acl->defdacl = LocalAlloc(LPTR,required);
+ if(!GetTokenInformation(tokenh,
+ TokenDefaultDacl,
+ save_acl->defdacl,
+ required,
+ &required)){
+#ifdef HARDDEBUG
+ {
+ char *mes;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &mes,
+ 0,
+ NULL );
+ log_info(mes);
+ LocalFree(mes);
+ }
+#endif
+ log_warning("Failed to get default ACL from token.");
+ CloseHandle(tokenh);
+ return FALSE;
+ }
+
+ oldacl = save_acl->defdacl->DefaultDacl;
+ if(!GetAclInformation(oldacl, &si, sizeof(si),
+ AclSizeInformation)){
+ log_warning("Failed to get size information for ACL");
+ CloseHandle(tokenh);
+ return FALSE;
+ }
+
+ if(!AllocateAndInitializeSid(&nt_auth,
+ 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ &extra_sid)){
+ log_warning("Failed to initialize administrator SID.");
+ CloseHandle(tokenh);
+ return FALSE;
+ }
+
+ newsize = si.AclBytesInUse + sizeof(ACL) +
+ sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(extra_sid);
+
+ newacl = LocalAlloc(LPTR,newsize);
+
+ if(!InitializeAcl(newacl, newsize, ACL_REVISION)){
+ log_warning("Failed to initialize new ACL.");
+ LocalFree(newacl);
+ FreeSid(extra_sid);
+ CloseHandle(tokenh);
+ return FALSE;
+ }
+
+ for(i=0;i<((int)si.AceCount);++i){
+ ACE_HEADER *ace_header;
+ if (!GetAce (oldacl, i, &ace_header)){
+ log_warning("Failed to get ACE from old ACL.");
+ LocalFree(newacl);
+ FreeSid(extra_sid);
+ CloseHandle(tokenh);
+ return FALSE;
+ }
+ if(!AddAce(newacl,ACL_REVISION,0xffffffff,ace_header,
+ ace_header->AceSize)){
+ log_warning("Failed to set ACE in new ACL.");
+ LocalFree(newacl);
+ FreeSid(extra_sid);
+ CloseHandle(tokenh);
+ return FALSE;
+ }
+ }
+ if(!AddAccessAllowedAce(newacl,
+ ACL_REVISION2,
+ PROCESS_ALL_ACCESS,
+ extra_sid)){
+ log_warning("Failed to add system ACE to new ACL.");
+ LocalFree(newacl);
+ FreeSid(extra_sid);
+ return FALSE;
+ }
+
+ newdacl.DefaultDacl = newacl;
+ if(!SetTokenInformation(tokenh,
+ TokenDefaultDacl,
+ &newdacl,
+ sizeof(newdacl))){
+ log_warning("Failed to set token information");
+ LocalFree(newacl);
+ FreeSid(extra_sid);
+ CloseHandle(tokenh);
+ return FALSE;
+ }
+ save_acl->initialized = TRUE;
+ save_acl->newacl = newacl;
+ save_acl->adminsid = extra_sid;
+ CloseHandle(tokenh);
+
+ return TRUE;
+}
+
+static char **find_arg(char **arg, char *str){
+ char *tmp;
+ int len;
+
+ str = strdup(str);
+ if((tmp = strchr(str,'=')) == NULL)
+ goto fail;
+ tmp++;
+ *tmp = '\0';
+ len = tmp - str;
+ while(*arg != NULL){
+ if(!_strnicmp(*arg,str,len)){
+ free(str);
+ return arg;
+ }
+ ++arg;
+ }
+fail:
+ free(str);
+ return NULL;
+}
+
+static char **merge_environment(char *current, char *add){
+ char **c_arg = env_to_arg(envdup(current));
+ char **a_arg = env_to_arg(envdup(add));
+ char **new;
+ char **tmp;
+ int i,j;
+
+ for(i=0;c_arg[i] != NULL;++i)
+ ;
+ for(j=0;a_arg[j] != NULL;++j)
+ ;
+
+ new = malloc(sizeof(char *)*(i + j + 3));
+
+ for(i = 0; c_arg[i] != NULL; ++i)
+ new[i] = strdup(c_arg[i]);
+
+ new[i] = NULL;
+
+ for(j = 0; a_arg[j] != NULL; ++j){
+ if((tmp = find_arg(new,a_arg[j])) != NULL){
+ free(*tmp);
+ *tmp = strdup(a_arg[j]);
+ } else {
+ new[i++] = strdup(a_arg[j]);
+ new[i] = NULL;
+ }
+ }
+ free(arg_to_env(c_arg));
+ free(arg_to_env(a_arg));
+ return new;
+}
+
+
+static char *get_next_debug_file(char *prefix){
+ char *buffer = malloc(strlen(prefix)+12);
+ int i;
+ for(i=1;i<100;++i){
+ sprintf(buffer,"%s.%d",prefix,i);
+ if(GetFileAttributes(buffer) == 0xFFFFFFFF)
+ return buffer;
+ }
+ return NULL;
+}
+
+
+
+static BOOL start_a_service(ServerInfo *srvi){
+ STARTUPINFO start;
+ char execbuff[MAX_PATH*4]; /* FIXME: Can get overflow! */
+ char namebuff[MAX_PATH];
+ char errbuff[MAX_PATH*4]; /* hmmm.... */
+ HANDLE write_pipe = NULL, read_pipe = NULL;
+ SECURITY_ATTRIBUTES pipe_security;
+ SECURITY_ATTRIBUTES attr;
+ HANDLE nul;
+ SaveAclStruct save_acl;
+ char *my_environ;
+ BOOL console_allocated = FALSE;
+
+ if(!(*(srvi->keys[Env].data.bytes))){
+ my_environ = NULL;
+ } else {
+ char *tmp;
+ char **merged = merge_environment((tmp = GetEnvironmentStrings()),
+ srvi->keys[Env].data.bytes);
+ FreeEnvironmentStrings(tmp);
+ my_environ = arg_to_env(merged);
+ }
+
+ if(!*(srvi->keys[Machine].data.bytes) ||
+ (!*(srvi->keys[SName].data.bytes) &&
+ !*(srvi->keys[Name].data.bytes))){
+ log_error("Not enough parameters for erlang service.");
+ if(my_environ)
+ free(my_environ);
+ return FALSE;
+ }
+
+ if(*(srvi->keys[SName].data.bytes))
+ sprintf(namebuff,"-nohup -sname %s",srvi->keys[SName].data.bytes);
+ else
+ sprintf(namebuff,"-nohup -name %s",srvi->keys[Name].data.bytes);
+
+ if(srvi->keys[DebugType].data.value == DEBUG_TYPE_CONSOLE)
+ strcat(namebuff," -keep_window");
+
+ if (srvi->event_name != NULL) {
+ sprintf(execbuff,"\"%s\" -service_event %s %s %s",
+ srvi->keys[Machine].data.bytes,
+ srvi->event_name,
+ namebuff,
+ srvi->keys[Args].data.bytes);
+ } else {
+ sprintf(execbuff,"\"%s\" %s %s",
+ srvi->keys[Machine].data.bytes,
+ namebuff,
+ srvi->keys[Args].data.bytes);
+ }
+
+ memset (&start, 0, sizeof (start));
+ start.cb = sizeof (start);
+ start.dwFlags = STARTF_USESHOWWINDOW;
+ start.wShowWindow = SW_HIDE;
+
+ /* Console debugging implies no working StopAction */
+ if(srvi->keys[DebugType].data.value == DEBUG_TYPE_CONSOLE) {
+ COORD coord = {80,999};
+ if(console_allocated = AllocConsole())
+ SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),coord);
+ else
+ log_warning("Unable to allocate debugging console!");
+ } else if(*(srvi->keys[StopAction].data.bytes) ||
+ srvi->keys[DebugType].data.value != DEBUG_TYPE_NO_DEBUG){
+ pipe_security.nLength = sizeof(pipe_security);
+ pipe_security.lpSecurityDescriptor = NULL;
+ pipe_security.bInheritHandle = TRUE;
+ if(!CreatePipe(&read_pipe,&write_pipe,&pipe_security,0)){
+ log_error("Could not create pipe for erlang service.");
+ if(my_environ)
+ free(my_environ);
+ return FALSE;
+ }
+ if(srvi->keys[DebugType].data.value != DEBUG_TYPE_NO_DEBUG){
+ char *filename;
+ if(*(srvi->keys[WorkDir].data.bytes)){
+ filename = malloc(strlen(srvi->keys[WorkDir].data.bytes) + 1 +
+ strlen(service_name)+strlen(".debug")+1);
+ sprintf(filename,"%s\\%s.debug",
+ srvi->keys[WorkDir].data.bytes,
+ service_name);
+ } else {
+ filename = malloc(strlen(service_name)+strlen(".debug")+1);
+ sprintf(filename,"%s.debug",service_name);
+ }
+ log_debug(filename);
+
+ if(srvi->keys[DebugType].data.value == DEBUG_TYPE_NEW){
+ char *tmpfn = get_next_debug_file(filename);
+ if(tmpfn){
+ free(filename);
+ filename = tmpfn;
+ } else {
+ log_warning("Number of debug files exceeds system defined "
+ "limit, reverting to DebugType: reuse. ");
+ }
+ }
+
+
+ nul = CreateFile(filename,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &pipe_security,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ free(filename);
+ } else { /* Not debugging */
+ nul = CreateFile("NUL",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &pipe_security,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ }
+ if(nul == NULL){
+ log_error((srvi->keys[DebugType].data.value != DEBUG_TYPE_NO_DEBUG)
+ ? "Could not create debug file. "
+ "(Working directory not valid?)"
+ : "Cold not open NUL!");
+ start.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+ start.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+ }
+ start.hStdOutput = nul;
+ start.hStdError = nul;
+ start.hStdInput = read_pipe;
+ start.dwFlags |= STARTF_USESTDHANDLES;
+ }
+
+ attr.nLength = sizeof(attr);
+ attr.lpSecurityDescriptor = NULL;
+ attr.bInheritHandle = TRUE;
+
+ new_acl(&save_acl);
+
+ if(!CreateProcess(NULL,
+ execbuff,
+ &attr,
+ NULL,
+ (read_pipe != NULL),
+ CREATE_DEFAULT_ERROR_MODE |
+ (srvi->keys[Priority].data.value),
+ my_environ,
+ (*(srvi->keys[WorkDir].data.bytes)) ?
+ srvi->keys[WorkDir].data.bytes : NULL,
+ &start,
+ &(srvi->info))){
+ sprintf(errbuff,"Could not start erlang service"
+ "with commandline \"%s\".",
+ service_name,
+ execbuff
+ );
+ log_error(errbuff);
+ if(read_pipe != NULL){
+ CloseHandle(read_pipe);
+ CloseHandle(write_pipe);
+ if(nul != NULL)
+ CloseHandle(nul);
+ }
+ if(console_allocated)
+ FreeConsole();
+ reset_acl(&save_acl);
+ if(my_environ)
+ free(my_environ);
+ return FALSE;
+ }
+ if(console_allocated)
+ FreeConsole();
+#ifdef HARDDEBUG
+ sprintf(errbuff,
+ "Started %s with the following commandline: "
+ "%s",service_name,execbuff);
+ log_debug(errbuff);
+#endif
+ if(read_pipe != NULL){
+ CloseHandle(read_pipe);
+ if(nul != NULL)
+ CloseHandle(nul);
+ srvi->erl_stdin = write_pipe;
+ }
+
+ reset_acl(&save_acl);
+ if(my_environ)
+ free(my_environ);
+ return TRUE;
+}
+
+static HANDLE create_erlang_event(char *event_name)
+{
+ HANDLE e;
+ if ((e = OpenEvent(EVENT_ALL_ACCESS,FALSE,event_name)) == NULL) {
+ if ((e = CreateEvent(NULL, TRUE, FALSE, event_name)) == NULL) {
+ log_warning("Could not create or access erlang termination event");
+ }
+ } else {
+ if (!ResetEvent(e)) {
+ log_warning("Could not reset erlang termination event.");
+ }
+ }
+ return e;
+}
+
+static BOOL stop_erlang(ServerInfo *srvi, int waithint,
+ int *checkpoint){
+ DWORD written = 0;
+ char *action = srvi->keys[StopAction].data.bytes;
+ DWORD towrite = strlen(action)+1;
+ char *toerl;
+ DWORD exitcode;
+ int i;
+ int kill;
+
+ if(towrite > 2 && srvi->erl_stdin != NULL){
+ toerl = malloc(towrite+1);
+ strcpy(toerl,action);
+ strcat(toerl,"\n");
+ WriteFile(srvi->erl_stdin, toerl, towrite, &written,0);
+ free(toerl);
+ /* Give it 45 seconds to terminate */
+ for(i=0;i<45;++i){
+ if(WaitForSingleObject(srvi->info.hProcess, 1000) ==
+ WAIT_OBJECT_0){
+ GetExitCodeProcess(srvi->info.hProcess,&exitcode);
+ CloseHandle(srvi->info.hProcess);
+ CloseHandle(srvi->info.hThread);
+ return TRUE;
+ }
+ ++(*checkpoint);
+ set_stop_pending(waithint,*checkpoint);
+ }
+ log_warning("StopAction did not terminate erlang. Trying forced kill.");
+ }
+ log_debug("Terminating erlang...");
+ kill = 1;
+ if(eventKillErlang != NULL && SetEvent(eventKillErlang) != 0){
+ for(i=0;i<10;++i){
+ if(WaitForSingleObject(srvi->info.hProcess, 1000) == WAIT_OBJECT_0){
+ kill = 0;
+ break;
+ }
+ ++(*checkpoint);
+ set_stop_pending(waithint,*checkpoint);
+ }
+ } else {
+#ifdef HARDDEBUG
+ {
+ char *mes;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &mes,
+ 0,
+ NULL );
+ log_info(mes);
+ LocalFree(mes);
+ }
+#endif
+ log_debug("Could not send control event to Erlang process");
+ }
+ if(kill){
+ log_warning("Using TerminateProcess to kill erlang.");
+ if(!TerminateProcess(srvi->info.hProcess,NO_ERROR))
+ log_error("TerminateProcess failed");
+ }
+ GetExitCodeProcess(srvi->info.hProcess,&exitcode);
+ CloseHandle(srvi->info.hProcess);
+ CloseHandle(srvi->info.hThread);
+ if (eventKillErlang != NULL) {
+ ResetEvent(eventKillErlang);
+ }
+ return TRUE;
+}
+
+static BOOL enable_privilege(void) {
+ HANDLE ProcessHandle;
+ DWORD DesiredAccess = TOKEN_ADJUST_PRIVILEGES;
+ HANDLE TokenHandle;
+ TOKEN_PRIVILEGES Tpriv;
+ LUID luid;
+ ProcessHandle = GetCurrentProcess();
+ OpenProcessToken(ProcessHandle, DesiredAccess, &TokenHandle);
+ LookupPrivilegeValue(0,SE_SHUTDOWN_NAME,&luid);
+ Tpriv.PrivilegeCount = 1;
+ Tpriv.Privileges[0].Luid = luid;
+ Tpriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ return AdjustTokenPrivileges(TokenHandle,FALSE,&Tpriv,0,0,0);
+}
+
+static BOOL pull_service_name(void){
+ SC_HANDLE scm;
+ DWORD sz = 1024;
+ static char service_name_buff[1024];
+ if((scm = OpenSCManager(NULL,
+ NULL,
+ GENERIC_READ))
+ == NULL){
+ return FALSE;
+ }
+ if(!GetServiceDisplayName(scm,real_service_name,service_name_buff,&sz))
+ return FALSE;
+ CloseServiceHandle(scm);
+ service_name = service_name_buff;
+ return TRUE;
+}
+
+
+static VOID WINAPI service_main_loop(DWORD argc, char **argv){
+ int waithint = 30000;
+ int checkpoint = 1;
+ RegEntry *keys;
+ RegEntry *save_keys;
+ ServerInfo srvi;
+ HANDLE harr[2];
+ FILETIME creationt,exitt,kernelt,usert;
+ LONGLONG creationl,exitl,diffl;
+ char event_name[MAX_PATH] = "ErlSrv_";
+ char executable_name[MAX_PATH];
+#ifdef DEBUG
+ char errorbuff[2048]; /* FIXME... */
+#endif
+ int success_wait = NO_SUCCESS_WAIT;
+
+ real_service_name = argv[0];
+ if(!pull_service_name()){
+ log_error("Could not get Display name of erlang service.");
+ set_stopped(ERROR_CANTREAD);
+ return;
+ }
+
+ SetEnvironmentVariable((LPCTSTR) SERVICE_ENV, (LPCTSTR) service_name);
+
+ strncat(event_name, service_name, MAX_PATH - strlen(event_name));
+ event_name[MAX_PATH - 1] = '\0';
+
+ if(!GetModuleFileName(NULL, executable_name, MAX_PATH)){
+ log_error("Unable to retrieve module file name, " EXECUTABLE_ENV
+ " will not be set.");
+ } else {
+ char quoted_exe_name[MAX_PATH+4];
+ sprintf(quoted_exe_name, "\"%s\"", executable_name);
+ SetEnvironmentVariable((LPCTSTR) EXECUTABLE_ENV,
+ (LPCTSTR) quoted_exe_name);
+ }
+
+ log_debug("Here we go, service_main_loop...");
+ currentState = SERVICE_START_PENDING;
+ InitializeCriticalSection(&crit);
+ eventStop = CreateEvent(NULL,FALSE,FALSE,NULL);
+ if ((eventKillErlang = create_erlang_event(event_name)) != NULL) {
+ srvi.event_name = event_name;
+ } else {
+ srvi.event_name = NULL;
+ }
+ statusHandle = RegisterServiceCtrlHandler(real_service_name, &handler);
+ if(!statusHandle)
+ return;
+ set_start_pending(waithint,checkpoint);
+ keys = get_keys(service_name);
+ if(!keys){
+ log_error("Could not get registry keys for erlang service.");
+ set_stopped(ERROR_CANTREAD);
+ return;
+ }
+ srvi.keys = keys;
+ srvi.erl_stdin = NULL;
+
+ ++checkpoint;
+ if(!start_a_service(&srvi)){
+ log_error("Could not start erlang machine");
+ set_stopped(ERROR_PROCESS_ABORTED);
+ if (eventKillErlang != NULL) {
+ CloseHandle(eventKillErlang);
+ }
+ free_keys(keys);
+ return;
+ }
+ set_start_pending(waithint,checkpoint);
+ set_running();
+ success_wait = INITIAL_SUCCESS_WAIT;
+ harr[0] = srvi.info.hProcess;
+ harr[1] = eventStop;
+ for(;;){
+ DWORD ret;
+ ret = WaitForMultipleObjects((DWORD) 2,
+ harr,
+ FALSE,
+ (success_wait == NO_SUCCESS_WAIT) ?
+ INFINITE :
+ SUCCESS_WAIT_TIME);
+ if(ret == WAIT_TIMEOUT){
+ /* Just do the "success reporting" and continue */
+ if(success_wait == INITIAL_SUCCESS_WAIT){
+ log_info("Erlang service started successfully.");
+ } else {
+ log_warning("Erlang service restarted");
+ }
+ success_wait = NO_SUCCESS_WAIT;
+ continue;
+ }
+ if(ret == WAIT_FAILED || (int)(ret-WAIT_OBJECT_0) >= 2){
+ set_stopped(WAIT_FAILED);
+ log_error("Internal error, could not wait for objects.");
+ if (eventKillErlang != NULL) {
+ CloseHandle(eventKillErlang);
+ }
+ free_keys(keys);
+ return;
+ }
+ ret -= WAIT_OBJECT_0;
+ if(((int) ret) == 1){
+ /* Stop service... */
+ checkpoint = 2; /* 1 is taken by the handler */
+ set_stop_pending(waithint,checkpoint);
+ if(stop_erlang(&srvi,waithint,&checkpoint)){
+ log_debug("Erlang machine is stopped");
+ CloseHandle(eventStop);
+ if (eventKillErlang != NULL) {
+ CloseHandle(eventKillErlang);
+ }
+ set_stopped(NO_ERROR);
+ if(srvi.erl_stdin)
+ CloseHandle(srvi.erl_stdin);
+ free_keys(keys);
+ return;
+ } else {
+ log_warning("Unable to stop erlang service.");
+ set_running();
+ continue;
+ }
+ }
+ /* Reload the registry keys, they may have changed. */
+ save_keys = keys;
+ keys = get_keys(service_name);
+ if(!keys){
+ log_error("Could not reload registry keys.");
+ keys = srvi.keys = save_keys;
+ } else {
+#ifdef HARDDEBUG
+ sprintf(errorbuff,"Reloaded the registry keys because %s stopped.",
+ service_name);
+ log_debug(errorbuff);
+#endif /* HARDDEBUG */
+ free_keys(save_keys);
+ srvi.keys = keys;
+ }
+ if(srvi.keys[OnFail].data.value == ON_FAIL_RESTART ||
+ srvi.keys[OnFail].data.value == ON_FAIL_RESTART_ALWAYS){
+ if(!GetProcessTimes(srvi.info.hProcess,&creationt,
+ &exitt,&kernelt,&usert)){
+ DWORD rcode = GetLastError();
+ log_error("Could not get process time of terminated process.");
+ CloseHandle(srvi.info.hProcess);
+ CloseHandle(srvi.info.hThread);
+ CloseHandle(eventStop);
+ if(srvi.erl_stdin)
+ CloseHandle(srvi.erl_stdin);
+ set_stopped(rcode);
+ if (eventKillErlang != NULL) {
+ CloseHandle(eventKillErlang);
+ }
+ free_keys(keys);
+ return;
+ }
+ CloseHandle(srvi.info.hProcess);
+ CloseHandle(srvi.info.hThread);
+ if(srvi.erl_stdin)
+ CloseHandle(srvi.erl_stdin);
+ srvi.erl_stdin = NULL;
+ memcpy(&creationl,&creationt,sizeof(FILETIME));
+ memcpy(&exitl,&exitt,sizeof(FILETIME));
+ diffl = exitl - creationl;
+ diffl /= 10000000;
+#ifdef DEBUG
+ sprintf(errorbuff,"Process lived for %d seconds", (int) diffl);
+ log_debug(errorbuff);
+#endif
+
+ if(diffl > CYCLIC_RESTART_LIMIT ||
+ srvi.keys[OnFail].data.value == ON_FAIL_RESTART_ALWAYS){
+ if(!start_a_service(&srvi)){
+ log_error("Unable to restart failed erlang service, "
+ "aborting.");
+ CloseHandle(eventStop);
+ set_stopped(ERROR_PROCESS_ABORTED);
+ if (eventKillErlang != NULL) {
+ CloseHandle(eventKillErlang);
+ }
+ free_keys(keys);
+ return;
+ }
+ log_warning("Restarted erlang machine.");
+ if(diffl <= CYCLIC_RESTART_LIMIT)
+ log_warning("Possible cyclic restarting of erlang machine.");
+ success_wait = RESTART_SUCCESS_WAIT;
+ harr[0] = srvi.info.hProcess;
+ } else {
+ if(success_wait == INITIAL_SUCCESS_WAIT){
+ log_error("Erlang machine stopped instantly "
+ "(distribution name conflict?). "
+ "The service is not restarted, ignoring OnFail option.");
+ } else {
+ log_error("Erlang machine seems to die "
+ "continously, not restarted.");
+ }
+ CloseHandle(eventStop);
+ set_stopped(ERROR_PROCESS_ABORTED);
+ if (eventKillErlang != NULL) {
+ CloseHandle(eventKillErlang);
+ }
+ free_keys(keys);
+ return;
+ }
+ } else if(srvi.keys[OnFail].data.value == ON_FAIL_REBOOT){
+ log_error("Rebooting because erlang machine stopped.");
+ enable_privilege();
+ if(!InitiateSystemShutdown("",NULL,0,TRUE,TRUE)){
+ log_error("Failed to reboot!");
+#ifdef HARDDEBUG
+ {
+ char *mes;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &mes,
+ 0,
+ NULL );
+ log_debug(mes);
+ LocalFree(mes);
+ }
+#endif
+ CloseHandle(srvi.info.hProcess);
+ CloseHandle(eventStop);
+ if(srvi.erl_stdin != NULL)
+ CloseHandle(srvi.erl_stdin);
+ set_stopped(NO_ERROR);
+ if (eventKillErlang != NULL) {
+ CloseHandle(eventKillErlang);
+ }
+ free_keys(keys);
+ return;
+ }
+ } else {
+ DWORD ecode = NO_ERROR;
+ if(success_wait == NO_SUCCESS_WAIT){
+ log_warning("Erlang machine volountarily stopped. "
+ "The service is not restarted as OnFail "
+ "is set to ignore.");
+ } else {
+ log_error("Erlang machine stopped instantly "
+ "(distribution name conflict?). "
+ "The service is not restarted as OnFail is set to ignore.");
+ ecode = ERROR_PROCESS_ABORTED;
+ }
+ CloseHandle(srvi.info.hProcess);
+ CloseHandle(eventStop);
+ if(srvi.erl_stdin != NULL)
+ CloseHandle(srvi.erl_stdin);
+ set_stopped(ecode);
+ if (eventKillErlang != NULL) {
+ CloseHandle(eventKillErlang);
+ }
+ free_keys(keys);
+ return;
+ }
+ }
+}
+
+int service_main(int argc, char **argv){
+ char dummy_name[] = "";
+ SERVICE_TABLE_ENTRY serviceTable[] =
+ {
+ { dummy_name,
+ (LPSERVICE_MAIN_FUNCTION) service_main_loop},
+ { NULL, NULL }
+ };
+ BOOL success;
+ success =
+ StartServiceCtrlDispatcher(serviceTable);
+ if (!success)
+ log_error("Could not initiate service");
+ log_debug("service_main done its job");
+ return 0;
+}
+
diff --git a/erts/etc/win32/erlsrv/erlsrv_service.h b/erts/etc/win32/erlsrv/erlsrv_service.h
new file mode 100644
index 0000000000..3eab275836
--- /dev/null
+++ b/erts/etc/win32/erlsrv/erlsrv_service.h
@@ -0,0 +1,32 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifndef _ERLSRV_SERVICE_H
+#define _ERLSRV_SERVICE_H
+
+#define CYCLIC_RESTART_LIMIT 10 /* Seconds */
+#define SUCCESS_WAIT_TIME (10*1000) /* Wait 5 s before reporting a service
+ as really started */
+#define NO_SUCCESS_WAIT 0
+#define INITIAL_SUCCESS_WAIT 1
+#define RESTART_SUCCESS_WAIT 2
+
+
+int service_main(int argc, char **argv);
+
+#endif /* _ERLSRV_SERVICE_H */
diff --git a/erts/etc/win32/erlsrv/erlsrv_util.c b/erts/etc/win32/erlsrv/erlsrv_util.c
new file mode 100644
index 0000000000..da3c6f5ef7
--- /dev/null
+++ b/erts/etc/win32/erlsrv/erlsrv_util.c
@@ -0,0 +1,154 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#include <windows.h>
+#include <winsvc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "erlsrv_global.h"
+#include "erlsrv_util.h"
+#include "erlsrv_logmess.h"
+
+char *service_name = "";
+char *real_service_name = "";
+
+void log_warning(char *mess){
+ HANDLE logh;
+ char *strings[] = {service_name, mess , NULL};
+
+ if(!(logh = RegisterEventSource(NULL,APP_NAME)))
+ return;
+ ReportEvent(logh, EVENTLOG_WARNING_TYPE, 0, MSG_WARNING,
+ NULL, 2, 0, strings, NULL);
+ DeregisterEventSource(logh);
+}
+
+void log_error(char *mess){
+ HANDLE logh;
+ char *strings[] = {service_name, mess , NULL};
+
+ if(!(logh = RegisterEventSource(NULL,APP_NAME)))
+ return;
+ ReportEvent(logh, EVENTLOG_ERROR_TYPE, 0, MSG_ERROR,
+ NULL, 2, 0, strings, NULL);
+ DeregisterEventSource(logh);
+}
+
+void log_info(char *mess){
+ HANDLE logh;
+ char *strings[] = {service_name, mess , NULL};
+
+ if(!(logh = RegisterEventSource(NULL,APP_NAME)))
+ return;
+ ReportEvent(logh, EVENTLOG_INFORMATION_TYPE, 0, MSG_INFO,
+ NULL, 2, 0, strings, NULL);
+ DeregisterEventSource(logh);
+}
+
+#ifndef NDEBUG
+void log_debug(char *mess){
+ char *buff=malloc(strlen(mess)+100);
+ sprintf(buff,"DEBUG! %s",mess);
+ log_info(buff);
+ free(buff);
+}
+#endif
+
+char *envdup(char *env){
+ char *tmp;
+ int len;
+ for(tmp = env; *tmp != '\0'; tmp += strlen(tmp)+1)
+ ;
+ len = (tmp - env) + 1;
+ if(len == 1)
+ ++len;
+ tmp = malloc(len);
+ memcpy(tmp,env,len);
+ return tmp;
+}
+
+char **env_to_arg(char *env){
+ char **ret;
+ char *tmp;
+ int i;
+ int num_strings = 0;
+ for(tmp = env; *tmp != '\0'; tmp += strlen(tmp)+1)
+ ++num_strings;
+ /* malloc enough to insert ONE string */
+ ret = malloc(sizeof(char *) * (num_strings + 2));
+ i = 0;
+ for(tmp = env; *tmp != '\0'; tmp += strlen(tmp)+1){
+ ret[i++] = strdup(tmp);
+ }
+ ret[i] = NULL;
+ free(env);
+ return ret;
+}
+
+static int compare(const void *a, const void *b){
+ char *s1 = *((char **) a);
+ char *s2 = *((char **) b);
+ char *e1 = strchr(s1,'=');
+ char *e2 = strchr(s2,'=');
+ int ret;
+ int len;
+
+ if(!e1)
+ e1 = s1 + strlen(s1);
+ if(!e2)
+ e2 = s2 + strlen(s2);
+
+ if((e1 - s1) > (e2 - s2))
+ len = (e2 - s2);
+ else
+ len = (e1 - s1);
+
+ ret = _strnicmp(s1,s2,len);
+ if(ret == 0)
+ return ((e1 - s1) - (e2 - s2));
+ else
+ return ret;
+}
+
+char *arg_to_env(char **arg){
+ char *block;
+ char *pek;
+ int i;
+ int totlen = 1; /* extra '\0' */
+
+ for(i=0;arg[i] != NULL;++i)
+ totlen += strlen(arg[i])+1;
+ /* sort the environment vector */
+ qsort(arg,i,sizeof(char *),&compare);
+ if(totlen == 1){
+ block = malloc(2);
+ block[0] = block[1] = '\0';
+ } else {
+ block = malloc(totlen);
+ pek = block;
+ for(i=0; arg[i] != NULL; ++i){
+ strcpy(pek, arg[i]);
+ free(arg[i]);
+ pek += strlen(pek)+1;
+ }
+ *pek = '\0';
+ }
+ free(arg);
+ return block;
+}
diff --git a/erts/etc/win32/erlsrv/erlsrv_util.h b/erts/etc/win32/erlsrv/erlsrv_util.h
new file mode 100644
index 0000000000..b98a6cd3ef
--- /dev/null
+++ b/erts/etc/win32/erlsrv/erlsrv_util.h
@@ -0,0 +1,50 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifndef _ERLSRV_UTIL_H
+#define _ERLSRV_UTIL_H
+
+extern char *service_name;
+extern char *real_service_name;
+void log_warning(char *mess);
+void log_error(char *mess);
+void log_info(char *mess);
+
+char *envdup(char *env);
+/*
+** Call before env_to_arg to get a 'freeable' environment block.
+*/
+
+char *arg_to_env(char **arg);
+/*
+** Frees the argument list before returning!
+*/
+
+char **env_to_arg(char *env);
+/*
+** Frees the environment block before returning!
+*/
+
+
+#ifndef NDEBUG
+void log_debug(char *mess);
+#else
+#define log_debug(mess) /* Debug removed */
+#endif
+
+#endif /* _ERLSRV_UTIL_H */
diff --git a/erts/etc/win32/hrl_icon.ico b/erts/etc/win32/hrl_icon.ico
new file mode 100644
index 0000000000..d22abb396b
--- /dev/null
+++ b/erts/etc/win32/hrl_icon.ico
Binary files differ
diff --git a/erts/etc/win32/init_file.c b/erts/etc/win32/init_file.c
new file mode 100644
index 0000000000..52f6c41d1d
--- /dev/null
+++ b/erts/etc/win32/init_file.c
@@ -0,0 +1,565 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2003-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "init_file.h"
+
+#define ALLOC malloc
+#define REALLOC realloc
+#define FREE free
+
+#define CONTEXT_BUFFER_SIZE 1024
+
+typedef struct {
+ HANDLE fd;
+ int eof;
+ int num;
+ int pos;
+ char buff[CONTEXT_BUFFER_SIZE];
+} FileContext;
+
+static char *read_one_line(FileContext *fc)
+{
+ char *buff = ALLOC(10);
+ int size = 10;
+ int num = 0;
+ int skipping;
+ int escaped;
+
+#define PUSH(Char) \
+ do { \
+ if (num == size) { \
+ size += 10; \
+ buff = REALLOC(buff,size); \
+ } \
+ buff[num++] = (Char); \
+ } while(0)
+
+#define POP() (buff[--num])
+#define TOP() (buff[(num-1)])
+
+ skipping = 0;
+ escaped = 0;
+ for(;;) {
+ char current;
+ if (fc->eof) {
+ break;
+ }
+ if (fc->pos == fc->num) {
+ if (!ReadFile(fc->fd, fc->buff, CONTEXT_BUFFER_SIZE,
+ &(fc->num), NULL) || !(fc->num)) {
+ fc->eof = 1;
+ break;
+ }
+ fc->pos = 0;
+ }
+ current = fc->buff[fc->pos];
+ ++(fc->pos);
+ switch (current) {
+ case ' ':
+ if (!skipping && num) {
+ PUSH(current);
+ }
+ escaped = 0;
+ break;
+ case ';':
+ if (!skipping) {
+ if (!escaped) {
+ skipping = 1;
+ } else {
+ PUSH(current);
+ }
+ }
+ escaped = 0;
+ break;
+ case '\\':
+ if (!skipping) {
+ if (!escaped) {
+ escaped = 1;
+ } else {
+ PUSH(current);
+ escaped = 0;
+ }
+ }
+ break;
+ case '\r':
+ break;
+ case '\n':
+ if (!escaped) {
+ while (num && TOP() == ' ') {
+ POP();
+ }
+ if (num) {
+ goto done;
+ }
+ }
+ skipping = 0;
+ escaped = 0;
+ break;
+ default:
+ if (!skipping) {
+ PUSH(current);
+ }
+ escaped = 0;
+ break;
+ }
+ }
+ /* EOF comes here */
+ while (num && TOP() == ' ') {
+ POP();
+ }
+ if (!num) {
+ FREE(buff);
+ return NULL;
+ }
+ done:
+ PUSH('\0');
+ return buff;
+#undef PUSH
+#undef POP
+#undef TOP
+}
+
+static int is_section_header(char *line)
+{
+ int x = strlen(line);
+ return (x > 2 && *line == '[' && line[x-1] == ']');
+}
+
+static int is_key_value(char *line)
+{
+ char *p = strchr(line,'=');
+
+ return (p != NULL && p > line);
+}
+
+static char *digout_section_name(char *line)
+ /* Moving it because it shall later be freed. */
+{
+ int x = strlen(line);
+ memmove(line,line+1,x-1);
+ line[x-2] = '\0';
+ return line;
+}
+
+static void digout_key_value(char *line, char **key, char **value)
+{
+ char *e = strchr(line,'=');
+ *key = line;
+ *value = (e+1);
+ *e = '\0';
+ while (*(--e) == ' ') {
+ *e = '\0';
+ }
+ while (**value == ' ') {
+ ++(*value);
+ }
+}
+
+InitFile *load_init_file(char *filename)
+{
+ HANDLE infile;
+ InitFile *inif;
+ InitSection *inis;
+ InitEntry *inie;
+ FileContext fc;
+ char *line;
+ char **lines;
+ int size_lines;
+ int num_lines;
+
+ int i;
+
+ if ( (infile = CreateFile(filename,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL)) == INVALID_HANDLE_VALUE) {
+ return NULL;
+ }
+
+ size_lines = 10;
+ num_lines = 0;
+ lines = ALLOC(size_lines * sizeof(char *));
+
+ fc.fd = infile;
+ fc.eof = 0;
+ fc.num = 0;
+ fc.pos = 0;
+ while ((line = read_one_line(&fc)) != NULL) {
+ if (num_lines == size_lines) {
+ size_lines += 10;
+ lines = REALLOC(lines,size_lines * sizeof(char *));
+ }
+ lines[num_lines] = line;
+ ++num_lines;
+ }
+ CloseHandle(infile);
+ /* Now check the lines before doing anything else, so that
+ we don't need any error handling while creating the data
+ structures */
+ /*
+ The file should contain:
+ [section]
+ Key=Value
+ ...
+ [section]
+ ...
+ */
+ i = 0;
+ while (i < num_lines && is_section_header(lines[i])) {
+ ++i;
+ while (i < num_lines && is_key_value(lines[i])) {
+ ++i;
+ }
+ }
+ if (i < num_lines) {
+ for (i = 0; i < num_lines; ++i) {
+ FREE(lines[i]);
+ }
+ FREE(lines);
+ return NULL;
+ }
+
+ /* So, now we know it's consistent... */
+ i = 0;
+ inif = ALLOC(sizeof(InitFile));
+ inif->num_sections = 0;
+ inif->size_sections = 10;
+ inif->sections = ALLOC(sizeof(InitSection *) * 10);
+ while (i < num_lines) {
+ inis = ALLOC(sizeof(InitSection));
+ inis->num_entries = 0;
+ inis->size_entries = 10;
+ inis->section_name = digout_section_name(lines[i]);
+ inis->entries = ALLOC(sizeof(InitEntry *) * 10);
+ ++i;
+ while (i < num_lines && is_key_value(lines[i])) {
+ inie = ALLOC(sizeof(InitEntry));
+ digout_key_value(lines[i], &(inie->key), &(inie->value));
+ if (inis->num_entries == inis->size_entries) {
+ inis->size_entries += 10;
+ inis->entries =
+ REALLOC(inis->entries,
+ sizeof(InitEntry *) * inis->size_entries);
+ }
+ inis->entries[inis->num_entries] = inie;
+ ++(inis->num_entries);
+ ++i;
+ }
+ if (inif->num_sections == inif->size_sections) {
+ inif->size_sections += 10;
+ inif->sections =
+ REALLOC(inif->sections,
+ sizeof(InitSection *) * inif->size_sections);
+ }
+ inif->sections[inif->num_sections] = inis;
+ ++(inif->num_sections);
+ }
+ FREE(lines); /* Only the array of strings, not the actual strings, they
+ are kept in the data structures. */
+ return inif;
+}
+
+int store_init_file(InitFile *inif, char *filename)
+{
+ char *buff;
+ int size = 10;
+ int num = 0;
+ int i,j;
+ HANDLE outfile;
+
+#define PUSH(Char) \
+ do { \
+ if (num == size) { \
+ size += 10; \
+ buff = REALLOC(buff,size); \
+ } \
+ buff[num++] = (Char); \
+ } while(0)
+
+ if ( (outfile = CreateFile(filename,
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL)) == INVALID_HANDLE_VALUE) {
+ return INIT_FILE_OPEN_ERROR;
+ }
+ buff = ALLOC(size);
+
+ for(i = 0; i < inif->num_sections; ++i) {
+ int len;
+ int written;
+ InitSection *inis = inif->sections[i];
+
+ if (!WriteFile(outfile,"[",1,&written,NULL) || written != 1) {
+ goto write_error;
+ }
+ len = strlen(inis->section_name);
+ if (!WriteFile(outfile,inis->section_name,len,&written,NULL) ||
+ written != len) {
+ goto write_error;
+ }
+ if (!WriteFile(outfile,"]\n",2,&written,NULL) || written != 2) {
+ goto write_error;
+ }
+ for (j = 0; j < inis->num_entries; ++j) {
+ InitEntry *inie = inis->entries[j];
+ char *p = inie->key;
+ num = 0;
+ for (;*p != '\0';++p) {
+ switch (*p) {
+ case '\\':
+ case ';':
+ PUSH('\\');
+ default:
+ PUSH(*p);
+ break;
+ }
+ }
+ PUSH('=');
+ p = inie->value;
+ for (;*p != '\0';++p) {
+ switch (*p) {
+ case '\\':
+ case ';':
+ PUSH('\\');
+ default:
+ PUSH(*p);
+ break;
+ }
+ }
+ PUSH('\n');
+ if (!WriteFile(outfile,buff,num,&written,NULL) || written != num) {
+ goto write_error;
+ }
+ }
+ }
+ FREE(buff);
+ CloseHandle(outfile);
+ return INIT_FILE_NO_ERROR;
+ write_error:
+ FREE(buff);
+ CloseHandle(outfile);
+ return INIT_FILE_WRITE_ERROR;
+#undef PUSH
+}
+
+InitFile *create_init_file(void)
+{
+ InitFile *inif = ALLOC(sizeof(InitFile));
+ inif->num_sections = 0;
+ inif->size_sections = 10;
+ inif->sections = ALLOC(sizeof(InitSection *) * 10);
+ return inif;
+}
+
+InitSection *create_init_section(char *section_name)
+{
+ InitSection *inis = ALLOC(sizeof(InitSection));
+ inis->num_entries = 0;
+ inis->section_name = ALLOC(sizeof(char) * (strlen(section_name) + 1));
+ strcpy(inis->section_name, section_name);
+ inis->size_entries = 10;
+ inis->entries = ALLOC(sizeof(InitEntry *) * 10);
+ return inis;
+}
+
+static void free_init_entry(InitEntry *inie)
+{
+ FREE(inie->key);
+ /* Value is part of the same buffer */
+ FREE(inie);
+}
+
+void free_init_section(InitSection *inis)
+{
+ int i;
+ for (i = 0;i < inis->num_entries; ++i) {
+ free_init_entry(inis->entries[i]);
+ }
+ FREE(inis->entries);
+ FREE(inis->section_name);
+ FREE(inis);
+}
+
+void free_init_file(InitFile *inif)
+{
+ int i;
+ for (i = 0; i < inif->num_sections; ++i) {
+ free_init_section(inif->sections[i]);
+ }
+ FREE(inif->sections);
+ FREE(inif);
+}
+
+static int find_init_section(InitFile *inif, char *section_name)
+{
+ int i;
+ for (i = 0; i < inif->num_sections; ++i) {
+ if (!strcmp(inif->sections[i]->section_name, section_name)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int delete_init_section(InitFile *inif, char *section_name)
+{
+ int i;
+
+ if ((i = find_init_section(inif, section_name)) < 0) {
+ return INIT_FILE_NOT_PRESENT;
+ }
+
+ free_init_section(inif->sections[i]);
+ --(inif->num_sections);
+ inif->sections[i] = inif->sections[inif->num_sections];
+
+ return INIT_FILE_PRESENT;
+}
+
+int add_init_section(InitFile *inif, InitSection *inis)
+{
+ int i;
+ InitSection *oinis;
+ if ((i = find_init_section(inif, inis->section_name)) >= 0) {
+ oinis = inif->sections[i];
+ inif->sections[i] = inis;
+ free_init_section(oinis);
+ return INIT_FILE_PRESENT;
+ }
+ if (inif->num_sections == inif->size_sections) {
+ inif->size_sections += 10;
+ inif->sections = REALLOC(inif->sections,
+ sizeof(InitSection *) * inif->size_sections);
+ }
+ inif->sections[inif->num_sections] = inis;
+ ++(inif->num_sections);
+ return INIT_FILE_NOT_PRESENT;
+}
+
+InitSection *lookup_init_section(InitFile *inif, char *section_name)
+{
+ int i;
+ if ((i = find_init_section(inif,section_name)) < 0) {
+ return NULL;
+ }
+ return inif->sections[i];
+}
+
+char *nth_init_section_name(InitFile *inif, int n)
+{
+ if (n >= inif->num_sections) {
+ return NULL;
+ }
+ return inif->sections[n]->section_name;
+}
+
+/* Inefficient... */
+InitSection *copy_init_section(InitSection *inis, char *new_name)
+{
+ int i;
+ char *key;
+ InitSection *ninis = create_init_section(new_name);
+ i = 0;
+ while ((key = nth_init_entry_key(inis,i)) != NULL) {
+ add_init_entry(ninis, key, lookup_init_entry(inis, key));
+ ++i;
+ }
+ return ninis;
+}
+
+static int find_init_entry(InitSection *inis, char *key)
+{
+ int i;
+ for (i = 0; i < inis->num_entries; ++i) {
+ if (!strcmp(inis->entries[i]->key,key)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int add_init_entry(InitSection *inis, char *key, char *value)
+{
+ int keylen = strlen(key);
+ char *buff = ALLOC(sizeof(char) * (keylen + strlen(value) + 2));
+ InitEntry *inie;
+ char *obuff;
+ int i;
+
+ strcpy(buff,key);
+ strcpy(buff+keylen+1,value);
+
+ if ((i = find_init_entry(inis,key)) >= 0) {
+ inie = inis->entries[i];
+ FREE(inie->key);
+ inie->key = buff;
+ inie->value = buff+keylen+1;
+ return INIT_FILE_PRESENT;
+ }
+ inie = ALLOC(sizeof(InitEntry));
+ inie->key = buff;
+ inie->value = buff+keylen+1;
+ if (inis->num_entries == inis->size_entries) {
+ inis->size_entries += 10;
+ inis->entries = REALLOC(inis->entries,
+ sizeof(InitEntry *) * inis->size_entries);
+ }
+ inis->entries[inis->num_entries] = inie;
+ ++(inis->num_entries);
+ return INIT_FILE_NOT_PRESENT;
+}
+
+char *lookup_init_entry(InitSection *inis, char *key)
+{
+ int i;
+ if ((i = find_init_entry(inis,key)) < 0) {
+ return NULL;
+ }
+ return inis->entries[i]->value;
+}
+
+char *nth_init_entry_key(InitSection *inis, int n)
+{
+ if (n >= inis->num_entries) {
+ return NULL;
+ }
+ return inis->entries[n]->key;
+}
+
+int delete_init_entry(InitSection *inis, char *key)
+{
+ int i;
+ InitEntry *inie;
+ if ((i = find_init_entry(inis, key)) < 0) {
+ return INIT_FILE_NOT_PRESENT;
+ }
+ free_init_entry(inis->entries[i]);
+ --(inis->num_entries);
+ inis->entries[i] = inis->entries[inis->num_entries];
+ return INIT_FILE_PRESENT;
+}
+
diff --git a/erts/etc/win32/init_file.h b/erts/etc/win32/init_file.h
new file mode 100644
index 0000000000..48d2d2df62
--- /dev/null
+++ b/erts/etc/win32/init_file.h
@@ -0,0 +1,93 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2003-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+typedef struct {
+ char *key;
+ char *value; /* Key and value points into same buffer */
+} InitEntry;
+
+typedef struct {
+ int num_entries;
+ int size_entries;
+ char *section_name;
+ InitEntry **entries;
+} InitSection;
+
+typedef struct {
+ int num_sections;
+ int size_sections;
+ InitSection **sections;
+} InitFile;
+
+/* Load a file structure from a disk file */
+InitFile *load_init_file(char *filename);
+
+/* Stores a file structure into a disk file */
+int store_init_file(InitFile *inif, char *filename);
+
+/* Create an empty file structure */
+InitFile *create_init_file(void);
+
+/* Free a file structure and everything associateed (including sections,keys
+ and values and anything looked up but not copied) */
+void free_init_file(InitFile *inif);
+
+/* Create empty section */
+InitSection *create_init_section(char *section_name);
+
+/* Add section to file Overwrites and destroys old sections with same key */
+int add_init_section(InitFile *inif, InitSection *inis);
+
+/* Kills a named section from a file. Destroys so that previously looked up
+ sections (with this key) need to be copied before the delete */
+int delete_init_section(InitFile *inif, char *section_name);
+
+/* lookup returns pointer into existing data. If data is to be preserved
+ across deletes or overwrites, it has to be copied */
+InitSection *lookup_init_section(InitFile *inif, char *section_name);
+
+/* Returns the name of the nth init section, n is >= 0, ret NULL when done */
+char *nth_init_section_name(InitFile *inif, int n);
+
+/* To save an init section so that delete or overwrite does not destroy it,
+ one needs to copy it */
+InitSection *copy_init_section(InitSection *inis, char *new_name);
+
+/* Frees up everything in the section, keys and values as well. */
+void free_init_section(InitSection *inis);
+
+/* Key and value are copied in add_entry */
+int add_init_entry(InitSection *inis, char *key, char *value);
+
+/* Returns pointer into internal string, use strcpy to save across
+ updates/deletes */
+char *lookup_init_entry(InitSection *inis, char *key);
+
+/* Returns the name of the nth entry key, n is >= 0, ret NULL when done */
+char *nth_init_entry_key(InitSection *inis, int n);
+
+/* Destroys entry, prevoiusly looked up entries need be
+ copied before deleted */
+int delete_init_entry(InitSection *inis, char *key);
+
+#define INIT_FILE_NO_ERROR 0
+#define INIT_FILE_OPEN_ERROR -1
+#define INIT_FILE_WRITE_ERROR -2
+#define INIT_FILE_PRESENT 0
+#define INIT_FILE_NOT_PRESENT 1
diff --git a/erts/etc/win32/nsis/Makefile b/erts/etc/win32/nsis/Makefile
new file mode 100644
index 0000000000..ebb3ad9a96
--- /dev/null
+++ b/erts/etc/win32/nsis/Makefile
@@ -0,0 +1,88 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2003-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+include $(ERL_TOP)/erts/vsn.mk
+
+VERSION_HEADER = erlang.nsh
+MAKENSIS = makensis
+MAKENSISFLAGS = /V2
+CUSTOM_MODERN=custom_modern.exe
+
+# This is not the way we usually do in our makefiles,
+# but making release is the ONLY thing we do with this one,
+# Its not called during ordinary recursive make.
+all: release
+
+opt debug depend:
+ @echo Nothing to do for "'"$@"'" on $(TARGET)
+
+clean:
+ rm -f $(VERSION_HEADER)
+
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+TARGET_DIR = $(RELEASE_PATH)
+WTESTROOT=$(shell (cygpath -d $(RELEASE_PATH) 2>/dev/null || cygpath -w $(RELEASE_PATH)))
+WTARGET_DIR=$(shell (cygpath -d $(TARGET_DIR) 2>/dev/null || cygpath -d $(TARGET_DIR)))
+
+REDIST_FILE=$(shell (sh ./find_redist.sh || echo ""))
+REDIST_DLL_VERSION=$(shell (sh ./dll_version_helper.sh || echo ""))
+
+release_spec:
+ @NSIS_VER=`makensis /hdrinfo | head -1 | awk '{print $$2}'`; \
+ case $$NSIS_VER in \
+ v2.0b*) \
+ echo '!define MUI_VERSION "$(SYSTEM_VSN)"' > $(VERSION_HEADER);\
+ echo '!define ERTS_VERSION "$(VSN)"' >> $(VERSION_HEADER);\
+ echo '!define TESTROOT "$(WTESTROOT)"' >> $(VERSION_HEADER);\
+ echo '!define OUTFILEDIR "$(WTARGET_DIR)"' >> $(VERSION_HEADER);\
+ if [ -f $(RELEASE_PATH)/docs/doc/index.html ];\
+ then\
+ echo '!define HAVE_DOCS 1' >> $(VERSION_HEADER); \
+ fi;\
+ $(MAKENSIS) erlang.nsi;;\
+ v2.*) \
+ echo '!define OTP_VERSION "$(SYSTEM_VSN)"' > $(VERSION_HEADER);\
+ echo '!define ERTS_VERSION "$(VSN)"' >> $(VERSION_HEADER);\
+ echo '!define TESTROOT "$(WTESTROOT)"' >> $(VERSION_HEADER);\
+ echo '!define OUTFILEDIR "$(WTARGET_DIR)"' >> $(VERSION_HEADER);\
+ if [ -f $(CUSTOM_MODERN) ];\
+ then \
+ echo '!define HAVE_CUSTOM_MODERN 1' >> $(VERSION_HEADER); \
+ fi;\
+ if [ '!' -z "$(REDIST_FILE)" -a '!' -z "$(REDIST_DLL_VERSION)" ];\
+ then \
+ cp $(REDIST_FILE) $(RELEASE_PATH)/vcredist_x86.exe;\
+ echo '!define HAVE_REDIST_FILE 1' >> $(VERSION_HEADER); \
+ echo '!define REDIST_DLL_VERSION "$(REDIST_DLL_VERSION)"' >> $(VERSION_HEADER);\
+ fi;\
+ if [ -f $(RELEASE_PATH)/docs/doc/index.html ];\
+ then \
+ echo '!define HAVE_DOCS 1' >> $(VERSION_HEADER); \
+ fi;\
+ echo "Running $(MAKENSIS) $(MAKENSISFLAGS) erlang20.nsi";\
+ $(MAKENSIS) $(MAKENSISFLAGS) erlang20.nsi;;\
+ *) \
+ echo 'Unsupported NSIS version';;\
+ esac
+
+release_docs release_docs_spec docs:
+
diff --git a/erts/etc/win32/nsis/custom_modern.exe b/erts/etc/win32/nsis/custom_modern.exe
new file mode 100755
index 0000000000..0f56b8b239
--- /dev/null
+++ b/erts/etc/win32/nsis/custom_modern.exe
Binary files differ
diff --git a/erts/etc/win32/nsis/dll_version_helper.sh b/erts/etc/win32/nsis/dll_version_helper.sh
new file mode 100755
index 0000000000..e0047dea8b
--- /dev/null
+++ b/erts/etc/win32/nsis/dll_version_helper.sh
@@ -0,0 +1,49 @@
+#! /bin/sh
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2007-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+# This little helper digs out the current version of microsoft CRT
+# by compiling hello world and "parsing" the manifest file...
+
+# To debug using a fake version:
+
+# echo "8.0.50727.763"
+# exit 0
+
+cat > hello.c <<EOF
+#include <stdio.h>
+
+int main(void)
+{
+ printf("Hello world\n");
+ return 0;
+}
+
+EOF
+cl /MD hello.c > /dev/null 2>&1
+if [ '!' -f hello.exe.manifest ]; then
+ echo "This compiler does not generate manifest files - OK if using mingw" >&2
+ exit 0
+fi
+VERSION=`grep '<assemblyIdentity' hello.exe.manifest | sed 's,.*version=.\([0-9\.]*\).*,\1,g' | grep -v '<'`
+rm -f hello.c hello.obj hello.exe hello.exe.manifest
+if [ -z "$VERSION" ]; then
+ exit 1
+fi
+echo $VERSION
+exit 0
diff --git a/erts/etc/win32/nsis/erlang.nsi b/erts/etc/win32/nsis/erlang.nsi
new file mode 100644
index 0000000000..f4fd2b4cdb
--- /dev/null
+++ b/erts/etc/win32/nsis/erlang.nsi
@@ -0,0 +1,386 @@
+; NSIS Modern User Interface version 1.63
+; Erlang OTP installation script based on "Start Menu Folder Selection
+; Example Script"
+; Original example written by Joost Verburg
+; Modified for Erlang by Patrik
+
+; Verbosity does not come naturally with MUI, have to set it back now and then.
+ !verbose 1
+ !define MUI_MANUALVERBOSE 1
+
+ !define MUI_PRODUCT "Erlang OTP"
+
+ !include "erlang.nsh" ; All release specific parameters come from this
+
+
+ !include "MUI.nsh"
+
+;--------------------------------
+;Configuration
+
+ ;SetCompressor bzip2
+
+;General
+ OutFile "${OUTFILEDIR}\otp_win32_${MUI_VERSION}.exe"
+
+;Folder selection page
+ InstallDir "$PROGRAMFILES\erl${ERTS_VERSION}"
+
+;Remember install folder
+ InstallDirRegKey HKLM "SOFTWARE\Ericsson\Erlang\${ERTS_VERSION}" ""
+
+;$9 is being used to store the Start Menu Folder.
+;Do not use this variable in your script (or Push/Pop it)!
+
+;To change this variable, use MUI_STARTMENUPAGE_VARIABLE.
+;Have a look at the Readme for info about other options (default folder,
+;registry).
+
+; Set the default start menu folder
+
+ !define MUI_STARTMENUPAGE_DEFAULTFOLDER "${MUI_PRODUCT} ${MUI_VERSION}"
+
+; Registry keys where start menu folder is stored
+ !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM"
+ !define MUI_STARTMENUPAGE_REGISTRY_KEY \
+ "SOFTWARE\Ericsson\Erlang\${ERTS_VERSION}"
+ !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
+
+; Temporary variable used here and there...
+ !define TEMP $R0
+
+;--------------------------------
+;Modern UI Configuration
+ !define MUI_ICON "erlang_inst.ico"
+ !define MUI_UNICON "erlang_uninst.ico"
+ !define MUI_WELCOMEPAGE
+ !define MUI_COMPONENTSPAGE
+ !define MUI_DIRECTORYPAGE
+ !define MUI_STARTMENUPAGE
+
+ !define MUI_ABORTWARNING
+
+ !define MUI_UNINSTALLER
+ !define MUI_UNCONFIRMPAGE
+
+;--------------------------------
+;Languages
+
+ !insertmacro MUI_LANGUAGE "English"
+
+;--------------------------------
+;Language Strings
+
+;Description
+ LangString DESC_SecErlang ${LANG_ENGLISH} "Erlang OTP."
+ LangString DESC_SecErlangDev ${LANG_ENGLISH} \
+ "Erlang OTP development environment (required)."
+ LangString DESC_SecErlangAssoc ${LANG_ENGLISH} \
+ "Erlang filetype associations (.erl, .hrl, .beam)."
+!ifdef HAVE_DOCS
+ LangString DESC_SecErlangDoc ${LANG_ENGLISH} "Documentation."
+!endif
+;--------------------------------
+;Installer Sections
+
+SubSection /e "Erlang" SecErlang
+Section "Development" SecErlangDev
+SectionIn 1 RO
+
+ StrCmp ${MUI_STARTMENUPAGE_VARIABLE} "" 0 skip_silent_mode
+ StrCpy ${MUI_STARTMENUPAGE_VARIABLE} \
+ "${MUI_STARTMENUPAGE_DEFAULTFOLDER}"
+skip_silent_mode:
+
+ SetOutPath "$INSTDIR"
+ File "${TESTROOT}\Install.ini"
+ File "${TESTROOT}\Install.exe"
+ File /r "${TESTROOT}\releases"
+ File /r "${TESTROOT}\lib"
+ File /r "${TESTROOT}\erts-${ERTS_VERSION}"
+ File /r "${TESTROOT}\usr"
+
+;Store install folder
+ WriteRegStr HKLM "SOFTWARE\Ericsson\Erlang\${ERTS_VERSION}" "" $INSTDIR
+
+; Run the setup program
+ ExecWait '"$INSTDIR\Install.exe" -s'
+
+; The startmenu stuff
+ !insertmacro MUI_STARTMENU_WRITE_BEGIN
+; Set back verbosity...
+ !verbose 1
+; Try to use the Common startmenu...
+ SetShellVarContext All
+ ClearErrors
+ CreateDirectory "$SMPROGRAMS\${MUI_STARTMENUPAGE_VARIABLE}"
+ IfErrors 0 continue_create
+ ;MessageBox MB_OK "Error creating file"
+ SetShellVarContext current
+ CreateDirectory "$SMPROGRAMS\${MUI_STARTMENUPAGE_VARIABLE}"
+continue_create:
+ WriteUninstaller "$INSTDIR\Uninstall.exe"
+ CreateShortCut "$SMPROGRAMS\${MUI_STARTMENUPAGE_VARIABLE}\Erlang.lnk" \
+ "$INSTDIR\bin\werl.exe"
+ CreateShortCut \
+ "$SMPROGRAMS\${MUI_STARTMENUPAGE_VARIABLE}\Uninstall.lnk" \
+ "$INSTDIR\Uninstall.exe" "" "$INSTDIR\Uninstall.exe" 0
+
+ !insertmacro MUI_STARTMENU_WRITE_END
+; And once again, the verbosity...
+ !verbose 1
+;Create uninstaller
+; WriteUninstaller "$INSTDIR\Uninstall.exe"
+
+ WriteRegStr HKLM \
+ "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${MUI_VERSION} (${ERTS_VERSION})" \
+ "DisplayName" "Erlang OTP ${MUI_VERSION} (${ERTS_VERSION})"
+ WriteRegStr HKLM \
+ "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${MUI_VERSION} (${ERTS_VERSION})" \
+ "UninstallString" "$INSTDIR\Uninstall.exe"
+ WriteRegDWORD HKLM \
+ "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${MUI_VERSION} (${ERTS_VERSION})" \
+ "NoModify" 1
+ WriteRegDWORD HKLM \
+ "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${MUI_VERSION} (${ERTS_VERSION})" \
+ "NoRepair" 1
+
+; Check that the registry could be written, we only check one key,
+; but it should be sufficient...
+ ReadRegStr ${TEMP} "${MUI_STARTMENUPAGE_REGISTRY_ROOT}" \
+ "${MUI_STARTMENUPAGE_REGISTRY_KEY}" \
+ "${MUI_STARTMENUPAGE_REGISTRY_VALUENAME}"
+
+ StrCmp ${TEMP} "" 0 done
+
+; Now we're done if we are a superuser. If the registry stuff failed, we
+; do the things below...
+
+ WriteRegStr HKCU "Software\Ericsson\Erlang\${ERTS_VERSION}" \
+ "" $INSTDIR
+ WriteRegStr HKCU "${MUI_STARTMENUPAGE_REGISTRY_KEY}" \
+ "${MUI_STARTMENUPAGE_REGISTRY_VALUENAME}" \
+ "${MUI_STARTMENUPAGE_VARIABLE}"
+ WriteRegStr HKCU \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${MUI_VERSION} (${ERTS_VERSION})" \
+ "DisplayName" "Erlang OTP ${MUI_VERSION} (${ERTS_VERSION})"
+ WriteRegStr HKCU \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${MUI_VERSION} (${ERTS_VERSION})" \
+ "UninstallString" "$INSTDIR\Uninstall.exe"
+ WriteRegDWORD HKCU \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${MUI_VERSION} (${ERTS_VERSION})" \
+ "NoModify" 1
+ WriteRegDWORD HKCU \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${MUI_VERSION} (${ERTS_VERSION})" \
+ "NoRepair" 1
+
+done:
+SectionEnd ; SecErlangDev
+
+Section "Associations" SecErlangAssoc
+
+ ;File /r "${TESTROOT}\usr\lib\icons"
+
+; .erl
+ ; back up old value of .erl
+ ReadRegStr $1 HKCR ".erl" ""
+ StrCmp $1 "" OwnErl
+ StrCmp $1 "ErlangSource" OwnErl
+ WriteRegStr HKCR ".erl" "backup_val" $1
+OwnErl:
+ WriteRegStr HKCR ".erl" "" "ErlangSource"
+ ReadRegStr $0 HKCR "ErlangSource" ""
+ StrCmp $0 "" 0 skipErlAssoc
+ WriteRegStr HKCR "ErlangSource" "" "Erlang source file"
+ WriteRegStr HKCR "ErlangSource\shell" "" "open"
+ WriteRegStr HKCR "ErlangSource\shell\compile" "" "Compile"
+ WriteRegStr HKCR "ErlangSource\shell\compile\command" "" \
+ '"$INSTDIR\bin\erlc.exe" "%1"'
+ WriteRegStr HKCR "ErlangSource\DefaultIcon" "" \
+ $INSTDIR\usr\lib\icons\erl_icon.ico
+ WriteRegStr HKCR "ErlangSource\shell\open\command" \
+ "" 'write.exe "%1"'
+skipErlAssoc:
+
+; .hrl
+ ; back up old value of .hrl
+ ReadRegStr $1 HKCR ".hrl" ""
+ StrCmp $1 "" OwnHrl
+ StrCmp $1 "ErlangHeader" OwnHrl
+ WriteRegStr HKCR ".hrl" "backup_val" $1
+OwnHrl:
+ WriteRegStr HKCR ".hrl" "" "ErlangHeader"
+ ReadRegStr $0 HKCR "ErlangHeader" ""
+ StrCmp $0 "" 0 skipHrlAssoc
+ WriteRegStr HKCR "ErlangHeader" "" "Erlang header file"
+ WriteRegStr HKCR "ErlangHeader\shell" "" "open"
+ WriteRegStr HKCR "ErlangHeader\DefaultIcon" "" \
+ $INSTDIR\usr\lib\icons\hrl_icon.ico
+ WriteRegStr HKCR "ErlangHeader\shell\open\command" \
+ "" 'write.exe "%1"'
+skipHrlAssoc:
+
+; .beam
+ ; back up old value of .beam
+ ReadRegStr $1 HKCR ".beam" ""
+ StrCmp $1 "" OwnBeam
+ StrCmp $1 "ErlangBeam" OwnBeam
+ WriteRegStr HKCR ".beam" "backup_val" $1
+OwnBeam:
+ WriteRegStr HKCR ".beam" "" "ErlangBeam"
+ ReadRegStr $0 HKCR "ErlangBeam" ""
+ StrCmp $0 "" 0 skipBeamAssoc
+ WriteRegStr HKCR "ErlangBeam" "" "Erlang beam code"
+ WriteRegStr HKCR "ErlangBeam\DefaultIcon" "" \
+ $INSTDIR\usr\lib\icons\beam_icon.ico
+skipBeamAssoc:
+
+SectionEnd ; SecErlangAssoc
+SubSectionEnd
+
+!ifdef HAVE_DOCS
+Section "Erlang Documentation" SecErlangDoc
+
+ SetOutPath "$INSTDIR"
+ File /r "${TESTROOT}\docs\*"
+
+; The startmenu stuff
+ !insertmacro MUI_STARTMENU_WRITE_BEGIN
+; Set back verbosity...
+ !verbose 1
+; Try to use the Common startmenu...
+ SetShellVarContext All
+ ClearErrors
+ CreateShortCut "$SMPROGRAMS\${MUI_STARTMENUPAGE_VARIABLE}\Erlang Documentation.lnk" \
+ "$INSTDIR\doc\index.html"
+ IfErrors 0 continue_create
+ ;MessageBox MB_OK "Error creating file"
+ SetShellVarContext current
+ CreateShortCut \
+ "$SMPROGRAMS\${MUI_STARTMENUPAGE_VARIABLE}\Erlang Documentation.lnk" \
+ "$INSTDIR\doc\index.html"
+continue_create:
+
+ !insertmacro MUI_STARTMENU_WRITE_END
+; And once again, the verbosity...
+ !verbose 1
+SectionEnd ; ErlangDoc
+!endif
+
+
+;Display the Finish header
+;Insert this macro after the sections if you are not using a finish page
+ !insertmacro MUI_SECTIONS_FINISHHEADER
+
+;--------------------------------
+;Descriptions
+
+ !insertmacro MUI_FUNCTIONS_DESCRIPTION_BEGIN
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecErlang} $(DESC_SecErlang)
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecErlangDev} $(DESC_SecErlangDev)
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecErlangAssoc} \
+ $(DESC_SecErlangAssoc)
+!ifdef HAVE_DOCS
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecErlangDoc} $(DESC_SecErlangDoc)
+!endif
+ !insertmacro MUI_FUNCTIONS_DESCRIPTION_END
+
+;--------------------------------
+;Uninstaller Section
+
+Section "Uninstall"
+
+ RMDir /r "$INSTDIR"
+
+;Remove shortcut
+ ReadRegStr ${TEMP} "${MUI_STARTMENUPAGE_REGISTRY_ROOT}" \
+ "${MUI_STARTMENUPAGE_REGISTRY_KEY}" \
+ "${MUI_STARTMENUPAGE_REGISTRY_VALUENAME}"
+ StrCmp ${TEMP} "" 0 end_try
+; Try HKCU instead...
+ ReadRegStr ${TEMP} HKCU \
+ "${MUI_STARTMENUPAGE_REGISTRY_KEY}" \
+ "${MUI_STARTMENUPAGE_REGISTRY_VALUENAME}"
+; If this failed to, we have no shortcuts (eh?)
+ StrCmp ${TEMP} "" noshortcuts
+end_try:
+ SetShellVarContext All
+ ClearErrors
+; If we cannot find the shortcut, switch to current user context
+ GetFileTime "$SMPROGRAMS\${TEMP}\Erlang.lnk" $R1 $R2
+ IfErrors 0 continue_delete
+ ;MessageBox MB_OK "Error removing file"
+ SetShellVarContext current
+continue_delete:
+ Delete "$SMPROGRAMS\${TEMP}\Erlang.lnk"
+ Delete "$SMPROGRAMS\${TEMP}\Uninstall.lnk"
+ Delete "$SMPROGRAMS\${TEMP}\Erlang Documentation.lnk"
+ RMDir "$SMPROGRAMS\${TEMP}" ;Only if empty
+
+noshortcuts:
+; We delete both in HKCU and HKLM, we don't really know were they might be...
+ DeleteRegKey /ifempty HKLM "SOFTWARE\Ericsson\Erlang\${ERTS_VERSION}"
+ DeleteRegKey /ifempty HKCU "SOFTWARE\Ericsson\Erlang\${ERTS_VERSION}"
+ DeleteRegKey HKLM \
+ "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${MUI_VERSION} (${ERTS_VERSION})"
+ DeleteRegKey HKCU \
+ "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${MUI_VERSION} (${ERTS_VERSION})"
+
+
+; Now remove shell/file associations we'we made...
+; .erl
+ ReadRegStr $1 HKCR ".erl" ""
+ StrCmp $1 "ErlangSource" 0 NoOwnSourceExt
+ ReadRegStr $1 HKCR ".erl" "backup_val"
+ StrCmp $1 "" 0 RestoreBackupSource
+ DeleteRegKey HKCR ".erl"
+ Goto NoOwnSourceExt
+RestoreBackupSource:
+ WriteRegStr HKCR ".erl" "" $1
+ DeleteRegValue HKCR ".erl" "backup_val"
+NoOwnSourceExt:
+
+ ReadRegStr $1 HKCR "ErlangSource\DefaultIcon" ""
+ StrCmp $1 "$INSTDIR\usr\lib\icons\erl_icon.ico" 0 NoOwnSource
+ DeleteRegKey HKCR "ErlangSource"
+NoOwnSource:
+
+;.hrl
+ ReadRegStr $1 HKCR ".hrl" ""
+ StrCmp $1 "ErlangHeader" 0 NoOwnHeaderExt
+ ReadRegStr $1 HKCR ".hrl" "backup_val"
+ StrCmp $1 "" 0 RestoreBackupHeader
+ DeleteRegKey HKCR ".hrl"
+ Goto NoOwnHeaderExt
+RestoreBackupHeader:
+ WriteRegStr HKCR ".hrl" "" $1
+ DeleteRegValue HKCR ".hrl" "backup_val"
+NoOwnHeaderExt:
+
+ ReadRegStr $1 HKCR "ErlangHeader\DefaultIcon" ""
+ StrCmp $1 "$INSTDIR\usr\lib\icons\hrl_icon.ico" 0 NoOwnHeader
+ DeleteRegKey HKCR "ErlangHeader"
+NoOwnHeader:
+
+;.beam
+ ReadRegStr $1 HKCR ".beam" ""
+ StrCmp $1 "ErlangBeam" 0 NoOwnBeamExt
+ ReadRegStr $1 HKCR ".beam" "backup_val"
+ StrCmp $1 "" 0 RestoreBackupBeam
+ DeleteRegKey HKCR ".beam"
+ Goto NoOwnBeamExt
+RestoreBackupBeam:
+ WriteRegStr HKCR ".beam" "" $1
+ DeleteRegValue HKCR ".beam" "backup_val"
+NoOwnBeamExt:
+
+ ReadRegStr $1 HKCR "ErlangBeam\DefaultIcon" ""
+ StrCmp $1 "$INSTDIR\usr\lib\icons\beam_icon.ico" 0 NoOwnBeam
+ DeleteRegKey HKCR "ErlangBeam"
+NoOwnBeam:
+
+;Display the Finish header
+ !insertmacro MUI_UNFINISHHEADER
+
+SectionEnd
+ !verbose 3
diff --git a/erts/etc/win32/nsis/erlang20.nsi b/erts/etc/win32/nsis/erlang20.nsi
new file mode 100644
index 0000000000..43e5d91604
--- /dev/null
+++ b/erts/etc/win32/nsis/erlang20.nsi
@@ -0,0 +1,440 @@
+; NSIS Modern User Interface version 1.63
+; Erlang OTP installation script based on "Start Menu Folder Selection
+; Example Script"
+; Original example written by Joost Verburg
+; Modified for Erlang by Patrik
+
+; Verbosity does not come naturally with MUI, have to set it back now and then.
+ !verbose 1
+ !define MUI_MANUALVERBOSE 1
+
+ !define OTP_PRODUCT "Erlang OTP"
+
+ !include "erlang.nsh" ; All release specific parameters come from this
+
+ Name "${OTP_PRODUCT} ${OTP_VERSION}"
+
+ !include "MUI.nsh"
+ !include "WordFunc.nsh"
+;--------------------------------
+;Configuration
+
+ SetCompressor bzip2
+
+Var MYTEMP
+;Var MUI_TEMP
+Var STARTMENU_FOLDER
+
+
+!define MY_STARTMENUPAGE_REGISTRY_ROOT HKLM
+!define MY_STARTMENUPAGE_REGISTRY_KEY "SOFTWARE\Ericsson\Erlang\${ERTS_VERSION}"
+!define MY_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
+
+;General
+ OutFile "${OUTFILEDIR}\otp_win32_${OTP_VERSION}.exe"
+
+;Folder selection page
+ InstallDir "$PROGRAMFILES\erl${ERTS_VERSION}"
+
+;Remember install folder
+ InstallDirRegKey HKLM "SOFTWARE\Ericsson\Erlang\${ERTS_VERSION}" ""
+
+; Set the default start menu folder
+
+ !define MUI_STARTMENUPAGE_DEFAULTFOLDER "${OTP_PRODUCT} ${OTP_VERSION}"
+
+;--------------------------------
+;Modern UI Configuration
+!ifdef HAVE_CUSTOM_MODERN
+ !define MUI_UI "custom_modern.exe"
+!endif
+ !define MUI_ICON "erlang_inst.ico"
+ !define MUI_UNICON "erlang_uninst.ico"
+
+ !insertmacro MUI_PAGE_COMPONENTS
+ !insertmacro MUI_PAGE_DIRECTORY
+; Registry keys where start menu folder is stored
+
+ !define MUI_STARTMENUPAGE_REGISTRY_ROOT ${MY_STARTMENUPAGE_REGISTRY_ROOT}
+ !define MUI_STARTMENUPAGE_REGISTRY_KEY "${MY_STARTMENUPAGE_REGISTRY_KEY}"
+ !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "${MY_STARTMENUPAGE_REGISTRY_VALUENAME}"
+
+ !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER
+
+ !insertmacro MUI_PAGE_INSTFILES
+
+ !insertmacro MUI_UNPAGE_CONFIRM
+ !insertmacro MUI_UNPAGE_INSTFILES
+
+;--------------------------------
+;Languages
+
+ !insertmacro MUI_LANGUAGE "English"
+
+;--------------------------------
+;Language Strings
+
+;Description
+ LangString DESC_SecErlang ${LANG_ENGLISH} "Erlang OTP."
+ LangString DESC_SecErlangDev ${LANG_ENGLISH} \
+ "Erlang OTP development environment (required)."
+ LangString DESC_SecErlangAssoc ${LANG_ENGLISH} \
+ "Erlang filetype associations (.erl, .hrl, .beam)."
+!ifdef HAVE_DOCS
+ LangString DESC_SecErlangDoc ${LANG_ENGLISH} "Documentation."
+!endif
+!ifdef HAVE_REDIST_FILE
+ LangString DESC_SecMSRedist ${LANG_ENGLISH} "Microsoft redistributable C runtime libraries, these are mandatory for Erlang runtime and development. Always installed if not already present."
+!endif
+;--------------------------------
+; WordFunc
+!ifdef HAVE_REDIST_FILE
+ !insertmacro VersionCompare
+!endif
+;--------------------------------
+;Installer Sections
+
+!ifdef HAVE_REDIST_FILE
+Section "Microsoft redistributable libraries." SecMSRedist
+
+ SetOutPath "$INSTDIR"
+ File "${TESTROOT}\vcredist_x86.exe"
+
+; Set back verbosity...
+ !verbose 1
+; Run the setup program
+ ExecWait '"$INSTDIR\vcredist_x86.exe"'
+
+ !verbose 1
+SectionEnd ; MSRedist
+!endif
+
+SubSection /e "Erlang" SecErlang
+Section "Development" SecErlangDev
+SectionIn 1 RO
+
+ SetOutPath "$INSTDIR"
+ File "${TESTROOT}\Install.ini"
+ File "${TESTROOT}\Install.exe"
+ SetOutPath "$INSTDIR\releases"
+ File /r "${TESTROOT}\releases\"
+ SetOutPath "$INSTDIR\lib"
+ File /r "${TESTROOT}\lib\"
+ SetOutPath "$INSTDIR\erts-${ERTS_VERSION}"
+ File /r "${TESTROOT}\erts-${ERTS_VERSION}\"
+ SetOutPath "$INSTDIR\usr"
+ File /r "${TESTROOT}\usr\"
+
+;Store install folder
+ WriteRegStr HKLM "SOFTWARE\Ericsson\Erlang\${ERTS_VERSION}" "" $INSTDIR
+
+; Run the setup program
+ Exec '"$INSTDIR\Install.exe" -s'
+
+; The startmenu stuff
+ !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
+; Set back verbosity...
+ !verbose 1
+; Try to use the Common startmenu...
+ SetShellVarContext All
+ ClearErrors
+ CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER"
+ IfErrors 0 continue_create
+ ;MessageBox MB_OK "Error creating file"
+ SetShellVarContext current
+ CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER"
+continue_create:
+ CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Erlang.lnk" \
+ "$INSTDIR\bin\werl.exe"
+
+ !insertmacro MUI_STARTMENU_WRITE_END
+; And once again, the verbosity...
+ !verbose 1
+; Check that the registry could be written, we only check one key,
+; but it should be sufficient...
+ ReadRegStr $MYTEMP ${MY_STARTMENUPAGE_REGISTRY_ROOT} "${MY_STARTMENUPAGE_REGISTRY_KEY}" "${MY_STARTMENUPAGE_REGISTRY_VALUENAME}"
+
+ StrCmp $MYTEMP "" 0 done_startmenu
+
+; If startmenu was skipped, this might be unnecessary, but wont hurt...
+ WriteRegStr HKCU "Software\Ericsson\Erlang\${ERTS_VERSION}" \
+ "" $INSTDIR
+ WriteRegStr HKCU "${MY_STARTMENUPAGE_REGISTRY_KEY}" \
+ "${MY_STARTMENUPAGE_REGISTRY_VALUENAME}" \
+ "$STARTMENU_FOLDER"
+
+
+done_startmenu:
+;Create uninstaller
+ WriteUninstaller "$INSTDIR\Uninstall.exe"
+
+ WriteRegStr HKLM \
+ "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
+ "DisplayName" "Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})"
+ WriteRegStr HKLM \
+ "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
+ "UninstallString" "$INSTDIR\Uninstall.exe"
+ WriteRegDWORD HKLM \
+ "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
+ "NoModify" 1
+ WriteRegDWORD HKLM \
+ "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
+ "NoRepair" 1
+
+; Check that the registry could be written, we only check one key,
+; but it should be sufficient...
+ ReadRegStr $MYTEMP HKLM \
+ "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
+ "NoRepair"
+
+ StrCmp $MYTEMP "" 0 done
+
+; Now we're done if we are a superuser. If the registry stuff failed, we
+; do the things below...
+
+ WriteRegStr HKCU \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
+ "DisplayName" "Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})"
+ WriteRegStr HKCU \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
+ "UninstallString" "$INSTDIR\Uninstall.exe"
+ WriteRegDWORD HKCU \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
+ "NoModify" 1
+ WriteRegDWORD HKCU \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
+ "NoRepair" 1
+
+done:
+SectionEnd ; SecErlangDev
+
+Section "Associations" SecErlangAssoc
+
+ ;File /r "${TESTROOT}\usr\lib\icons"
+
+; .erl
+ DeleteRegKey HKCR ".erl"
+ DeleteRegKey HKCR "ErlangSource"
+ WriteRegStr HKCR ".erl" "" "ErlangSource"
+ WriteRegStr HKCR "ErlangSource" "" "Erlang source file"
+ WriteRegStr HKCR "ErlangSource\shell\compile" "" "Compile"
+ WriteRegStr HKCR "ErlangSource\shell\compile\command" "" \
+ '"$INSTDIR\bin\erlc.exe" "%1"'
+ WriteRegStr HKCR "ErlangSource\DefaultIcon" "" \
+ $INSTDIR\usr\lib\icons\erl_icon.ico
+; .hrl
+ DeleteRegKey HKCR ".hrl"
+ DeleteRegKey HKCR "ErlangHeader"
+ WriteRegStr HKCR ".hrl" "" "ErlangHeader"
+ WriteRegStr HKCR "ErlangHeader" "" "Erlang header file"
+ WriteRegStr HKCR "ErlangHeader\DefaultIcon" "" \
+ $INSTDIR\usr\lib\icons\hrl_icon.ico
+
+; .beam
+ DeleteRegKey HKCR ".beam"
+ DeleteRegKey HKCR "ErlangBeam"
+ WriteRegStr HKCR ".beam" "" "ErlangBeam"
+ WriteRegStr HKCR "ErlangBeam" "" "Erlang beam code"
+ WriteRegStr HKCR "ErlangBeam\DefaultIcon" "" \
+ $INSTDIR\usr\lib\icons\beam_icon.ico
+
+
+ SearchPath $1 "write.exe"
+ StrCmp $1 "" writeNotFound
+ WriteRegStr HKCR "ErlangSource\shell" "" "Open"
+ WriteRegStr HKCR "ErlangSource\shell\open\command" "" \
+ '"$1" "%1"'
+ WriteRegStr HKCR "ErlangHeader\shell" "" "Open"
+ WriteRegStr HKCR "ErlangHeader\shell\open\command" "" \
+ '"$1" "%1"'
+
+
+writeNotFound:
+SectionEnd ; SecErlangAssoc
+SubSectionEnd
+
+!ifdef HAVE_DOCS
+Section "Erlang Documentation" SecErlangDoc
+
+ SetOutPath "$INSTDIR"
+ File /r "${TESTROOT}\docs\*"
+
+; The startmenu stuff
+ !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
+; Set back verbosity...
+ !verbose 1
+; Try to use the Common startmenu...
+ SetShellVarContext All
+ ClearErrors
+ CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Erlang Documentation.lnk" \
+ "$INSTDIR\doc\index.html"
+ IfErrors 0 continue_create
+ ;MessageBox MB_OK "Error creating file"
+ SetShellVarContext current
+ CreateShortCut \
+ "$SMPROGRAMS\$STARTMENU_FOLDER\Erlang Documentation.lnk" \
+ "$INSTDIR\doc\index.html"
+continue_create:
+
+ !insertmacro MUI_STARTMENU_WRITE_END
+; And once again, the verbosity...
+ !verbose 1
+SectionEnd ; ErlangDoc
+!endif
+
+!ifdef HAVE_REDIST_FILE
+Function DllVersionGoodEnough
+ IntCmp 0 $R0 normal0 normal0 negative0
+ normal0:
+ IntOp $R2 $R0 >> 16
+ Goto continue0
+ negative0:
+ IntOp $R2 $R0 & 0x7FFF0000
+ IntOp $R2 $R2 >> 16
+ IntOp $R2 $R2 | 0x8000
+ continue0:
+ IntOp $R3 $R0 & 0x0000FFFF
+ IntCmp 0 $R1 normal1 normal1 negative1
+ normal1:
+ IntOp $R4 $R1 >> 16
+ Goto continue1
+ negative1:
+ IntOp $R4 $R1 & 0x7FFF0000
+ IntOp $R4 $R4 >> 16
+ IntOp $R4 $R4 | 0x8000
+ continue1:
+ IntOp $R5 $R1 & 0x0000FFFF
+ StrCpy $2 "$R2.$R3.$R4.$R5"
+ ${VersionCompare} $2 ${REDIST_DLL_VERSION} $R0
+ Return
+FunctionEnd
+
+Function .onInit
+ SectionGetFlags 0 $MYTEMP
+; MessageBox MB_YESNO "Found $SYSDIR\msvcr80.dll" IDYES FoundLbl
+ IfFileExists $SYSDIR\msvcr80.dll MaybeFoundInSystemLbl
+ SearchSxsLbl:
+ FindFirst $0 $1 $WINDIR\WinSxS\x86*
+ LoopLbl:
+ StrCmp $1 "" NotFoundLbl
+ IfFileExists $WINDIR\WinSxS\$1\msvcr80.dll MaybeFoundInSxsLbl
+ FindNext $0 $1
+ Goto LoopLbl
+ MaybeFoundInSxsLbl:
+ GetDllVersion $WINDIR\WinSxS\$1\msvcr80.dll $R0 $R1
+ Call DllVersionGoodEnough
+ FindNext $0 $1
+ IntCmp 2 $R0 LoopLbl
+ Goto FoundLbl
+ MaybeFoundInSystemLbl:
+ GetDllVersion $SYSDIR\msvcr80.dll $R0 $R1
+ Call DllVersionGoodEnough
+ IntCmp 2 $R0 SearchSxSLbl
+ FoundLbl:
+ IntOp $MYTEMP $MYTEMP & 4294967294
+ SectionSetFlags 0 $MYTEMP
+ SectionSetText 0 "Microsoft DLL's (present)"
+ Return
+ NotFoundLbl:
+ IntOp $MYTEMP $MYTEMP | 16
+ SectionSetFlags 0 $MYTEMP
+ SectionSetText 0 "Microsoft DLL's (needed)"
+ Return
+FunctionEnd
+!endif
+
+
+;Display the Finish header
+;Insert this macro after the sections if you are not using a finish page
+; !insertmacro MUI_SECTIONS_FINISHHEADER
+
+;--------------------------------
+;Descriptions
+
+ !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecErlang} $(DESC_SecErlang)
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecErlangDev} $(DESC_SecErlangDev)
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecErlangAssoc} \
+ $(DESC_SecErlangAssoc)
+!ifdef HAVE_DOCS
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecErlangDoc} $(DESC_SecErlangDoc)
+!endif
+!ifdef HAVE_REDIST_FILE
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecMSRedist} $(DESC_SecMSRedist)
+!endif
+ !insertmacro MUI_FUNCTION_DESCRIPTION_END
+
+;--------------------------------
+;Uninstaller Section
+
+Section "Uninstall"
+
+ RMDir /r "$INSTDIR"
+
+;Remove shortcut
+ ReadRegStr $MYTEMP "${MY_STARTMENUPAGE_REGISTRY_ROOT}" \
+ "${MY_STARTMENUPAGE_REGISTRY_KEY}" \
+ "${MY_STARTMENUPAGE_REGISTRY_VALUENAME}"
+ StrCmp $MYTEMP "" 0 end_try
+; Try HKCU instead...
+ ReadRegStr $MYTEMP "${MY_STARTMENUPAGE_REGISTRY_ROOT}" \
+ "${MY_STARTMENUPAGE_REGISTRY_KEY}" \
+ "${MY_STARTMENUPAGE_REGISTRY_VALUENAME}"
+; If this failed to, we have no shortcuts (eh?)
+ StrCmp $MYTEMP "" noshortcuts
+end_try:
+ SetShellVarContext All
+ ClearErrors
+; If we cannot find the shortcut, switch to current user context
+ GetFileTime "$SMPROGRAMS\$MYTEMP\Erlang.lnk" $R1 $R2
+ IfErrors 0 continue_delete
+ ;MessageBox MB_OK "Error removing file"
+ SetShellVarContext current
+continue_delete:
+ Delete "$SMPROGRAMS\$MYTEMP\Erlang.lnk"
+ Delete "$SMPROGRAMS\$MYTEMP\Uninstall.lnk"
+ Delete "$SMPROGRAMS\$MYTEMP\Erlang Documentation.lnk"
+ RMDir "$SMPROGRAMS\$MYTEMP" ;Only if empty
+
+noshortcuts:
+; We delete both in HKCU and HKLM, we don't really know were they might be...
+ DeleteRegKey /ifempty HKLM "SOFTWARE\Ericsson\Erlang\${ERTS_VERSION}"
+ DeleteRegKey /ifempty HKCU "SOFTWARE\Ericsson\Erlang\${ERTS_VERSION}"
+ DeleteRegKey HKLM \
+ "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})"
+ DeleteRegKey HKCU \
+ "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})"
+
+
+; Now remove shell/file associations we'we made...
+; .erl
+ ReadRegStr $1 HKCR ".erl" ""
+ StrCmp $1 "ErlangSource" 0 NoOwnSource
+ ReadRegStr $1 HKCR "ErlangSource\DefaultIcon" ""
+ StrCmp $1 "$INSTDIR\usr\lib\icons\erl_icon.ico" 0 NoOwnSource
+ DeleteRegKey HKCR ".erl"
+ DeleteRegKey HKCR "ErlangSource"
+NoOwnSource:
+; .hrl
+ ReadRegStr $1 HKCR ".hrl" ""
+ StrCmp $1 "ErlangHeader" 0 NoOwnHeader
+ ReadRegStr $1 HKCR "ErlangHeader\DefaultIcon" ""
+ StrCmp $1 "$INSTDIR\usr\lib\icons\hrl_icon.ico" 0 NoOwnHeader
+ DeleteRegKey HKCR ".hrl"
+ DeleteRegKey HKCR "ErlangHeader"
+NoOwnHeader:
+
+; .beam
+ ReadRegStr $1 HKCR ".beam" ""
+ StrCmp $1 "ErlangBeam" 0 NoOwnBeam
+ ReadRegStr $1 HKCR "ErlangBeam\DefaultIcon" ""
+ StrCmp $1 "$INSTDIR\usr\lib\icons\beam_icon.ico" 0 NoOwnBeam
+ DeleteRegKey HKCR ".beam"
+ DeleteRegKey HKCR "ErlangBeam"
+NoOwnBeam:
+
+;Display the Finish header
+; !insertmacro MUI_UNFINISHHEADER
+
+SectionEnd
+ !verbose 3
diff --git a/erts/etc/win32/nsis/erlang_inst.ico b/erts/etc/win32/nsis/erlang_inst.ico
new file mode 100644
index 0000000000..edbd8a6f2c
--- /dev/null
+++ b/erts/etc/win32/nsis/erlang_inst.ico
Binary files differ
diff --git a/erts/etc/win32/nsis/erlang_uninst.ico b/erts/etc/win32/nsis/erlang_uninst.ico
new file mode 100755
index 0000000000..edbd8a6f2c
--- /dev/null
+++ b/erts/etc/win32/nsis/erlang_uninst.ico
Binary files differ
diff --git a/erts/etc/win32/nsis/find_redist.sh b/erts/etc/win32/nsis/find_redist.sh
new file mode 100755
index 0000000000..c5572839c5
--- /dev/null
+++ b/erts/etc/win32/nsis/find_redist.sh
@@ -0,0 +1,122 @@
+#! /bin/sh
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2007-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+
+# first find some tool we know exists, i.e. cl.exe
+lookup_prog_in_path ()
+{
+ PROG=$1
+ save_ifs=$IFS
+ IFS=:
+ for p in $PATH; do
+ # In cygwin the programs are not always executable and have .exe suffix...
+ if [ "X$TARGET" = "Xwin32" ]; then
+ if [ -f $p/$PROG.exe ]; then
+ echo $p/$PROG
+ break;
+ fi
+ else
+ if [ -x $p/$PROG ]; then
+ echo $p/$PROG
+ break;
+ fi
+ fi
+ done
+ IFS=$save_ifs
+}
+
+remove_path_element()
+{
+ EL=$1
+ PA=$2
+ ACC=""
+ save_ifs=$IFS
+ IFS=/
+ set $PA
+ N=$#
+ while [ $N -gt 1 ]; do
+ if [ '!' -z "$1" ]; then
+ ACC="${ACC}/$1"
+ fi
+ N=`expr $N - 1`
+ shift
+ done
+ UP=`echo $1 | tr [:lower:] [:upper:]`
+ ELUP=`echo $EL | tr [:lower:] [:upper:]`
+ IFS=$save_ifs
+ if [ "$UP" = "$ELUP" ]; then
+ echo "$ACC"
+ else
+ echo "${ACC}/$1"
+ fi
+
+ #echo "ACC=$ACC" >&2
+ #echo "1=$1" >&2
+}
+
+add_path_element()
+{
+ EL=$1
+ PA=$2
+
+ ELUP=`echo $EL | tr [:lower:] [:upper:]`
+ #echo "PA=$PA" >&2
+ for x in ${PA}/*; do
+ #echo "X=$x" >&2
+ UP=`basename "$x" | tr [:lower:] [:upper:]`
+ #echo "UP=$UP" >&2
+ if [ "$UP" = "$ELUP" ]; then
+ echo "$x"
+ return 0;
+ fi
+ done
+ echo "$PA"
+}
+
+CLPATH=`lookup_prog_in_path cl`
+
+if [ -z "$CLPATH" ]; then
+ echo "Can not locate cl.exe and vcredist_x86.exe - OK if using mingw" >&2
+ exit 1
+fi
+
+#echo $CLPATH
+BPATH=$CLPATH
+for x in cl bin vc; do
+ #echo $x
+ NBPATH=`remove_path_element $x "$BPATH"`
+ if [ "$NBPATH" = "$BPATH" ]; then
+ echo "Failed to locate vcredist_x86.exe because cl.exe was in an unexpected location" >&2
+ exit 2
+ fi
+ BPATH="$NBPATH"
+done
+#echo $BPATH
+for x in sdk v2.0 bootstrapper packages vcredist_x86 vcredist_x86.exe; do
+ #echo "x=$x"
+ #echo "BPATH=$BPATH"
+ NBPATH=`add_path_element $x "$BPATH"`
+ if [ "$NBPATH" = "$BPATH" ]; then
+ echo "Failed to locate vcredist_x86.exe because directory structure was unexpected" >&2
+ exit 3
+ fi
+ BPATH="$NBPATH"
+done
+echo $BPATH
+exit 0 \ No newline at end of file
diff --git a/erts/etc/win32/port_entry.c b/erts/etc/win32/port_entry.c
new file mode 100644
index 0000000000..49b5ad2f34
--- /dev/null
+++ b/erts/etc/win32/port_entry.c
@@ -0,0 +1,75 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+/*
+** This is an entry point for port programs,
+** it is used to set the console control handler of the process when
+** erlang process is run as a service.
+** Note that this entry point is only for
+** Console programs, Windowing programs can just route the WM_QUERYENDSESSION
+** and WM_ENDSESSION to the default window procedure to aquire the same
+** functionality.
+**
+** Creator Patrik Nyblom
+**
+** Notes:
+** You would really not want to use ANY of the standard library in this
+** routine, the standard library is not yet initiated...
+*/
+#include <windows.h>
+
+/*
+** The runtime libraries startup routine in the Microsoft Visual C CRT
+*/
+extern void mainCRTStartup(void);
+
+/*
+** A Console control handler that ignores the logoff events,
+** and lets the default handler take care of other events.
+*/
+BOOL WINAPI erl_port_default_handler(DWORD ctrl){
+ if(ctrl == CTRL_LOGOFF_EVENT)
+ return TRUE;
+ return FALSE;
+}
+
+/*
+** This is the entry point, it takes no parameters and never returns.
+*/
+void erl_port_entry(void){
+ char buffer[2];
+ /*
+ * We assume we're running as a service if this environment variable
+ * is defined
+ */
+ if(GetEnvironmentVariable("ERLSRV_SERVICE_NAME",buffer,(DWORD) 2)){
+#ifdef HARDDEBUG
+ DWORD dummy;
+ WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),
+ "Setting handler\r\n",17,&dummy, NULL);
+#endif /* HARDDEBUG */
+ /*
+ ** Actually set the control handler
+ */
+ SetConsoleCtrlHandler(&erl_port_default_handler, TRUE);
+ }
+ /*
+ ** Call the CRT's real startup routine.
+ */
+ mainCRTStartup();
+}
diff --git a/erts/etc/win32/resource.h b/erts/etc/win32/resource.h
new file mode 100644
index 0000000000..697931952a
--- /dev/null
+++ b/erts/etc/win32/resource.h
@@ -0,0 +1,33 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1997-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#define IDR_CONMENU 101
+#define IDMENU_STARTLOG 40001
+#define IDMENU_STOPLOG 40002
+#define IDMENU_EXIT 40003
+#define IDMENU_COPY 40004
+#define IDMENU_PASTE 40005
+#define IDMENU_FONT 40006
+#define IDMENU_TOOLBAR 40007
+#define IDMENU_ABOUT 40008
+#define IDMENU_SELALL 40009
+#define IDMENU_SELECTBKG 40010
+#define ID_BREAK 40011
+#define ID_VERSIONSTRING 40000
+#define ID_COMBOBOX 3
+
diff --git a/erts/etc/win32/start_erl.c b/erts/etc/win32/start_erl.c
new file mode 100644
index 0000000000..dcf8c8b281
--- /dev/null
+++ b/erts/etc/win32/start_erl.c
@@ -0,0 +1,677 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+/*
+ * start_erl.c - Windows NT start_erl
+ *
+ * Author: Mattias Nilsson
+ */
+
+#define WIN32_LEAN_AND_MEAN
+#define STRICT
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <windows.h>
+#include <assert.h>
+
+char *progname;
+
+/*
+ * If CASE_SENSITIVE_OPTIONS is specified, options are case sensitive
+ * (lower case).
+ * The reason for this switch is that _strnicmp is Microsoft specific.
+ */
+#ifndef CASE_SENSITIVE_OPTIONS
+#define strnicmp strncmp
+#else
+#define strnicmp _strnicmp
+#endif
+
+#define RELEASE_SUBDIR "\\releases"
+#define REGISTRY_BASE "Software\\Ericsson\\Erlang\\"
+#define DEFAULT_DATAFILE "start_erl.data"
+
+/* Global variables holding option values and command lines */
+char *CommandLineStart = NULL;
+char *ErlCommandLine = NULL;
+char *MyCommandLine = NULL;
+char *DataFileName = NULL;
+char *RelDir = NULL;
+char *BootFlagsFile = NULL;
+char *BootFlags = NULL;
+char *RegistryKey = NULL;
+char *BinDir = NULL;
+char *RootDir = NULL;
+char *VsnDir = NULL;
+char *Version = NULL;
+char *Release = NULL;
+BOOL NoConfig=FALSE;
+PROCESS_INFORMATION ErlProcessInfo;
+
+/*
+ * Error reason printout 'the microsoft way'
+ */
+void ShowLastError(void)
+{
+ LPVOID lpMsgBuf;
+ DWORD dwErr;
+
+ dwErr = GetLastError();
+ if( dwErr == ERROR_SUCCESS )
+ return;
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ dwErr,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL
+ );
+ fprintf(stderr, lpMsgBuf);
+ LocalFree( lpMsgBuf );
+}
+
+/*
+ * Exit the program and give a nice and firm explanation of why
+ * and how you can avoid it.
+ */
+void exit_help(char *err)
+{
+ ShowLastError();
+ fprintf(stderr, "** Error: %s\n", err);
+
+ printf("Usage:\n%s\n"
+ " [<erlang options>] ++\n"
+ " [-data <datafile>]\n"
+ " [-reldir <releasedir>]\n"
+ " [-bootflags <bootflagsfile>]\n"
+ " [-noconfig]\n", progname);
+
+ exit(0);
+}
+
+
+/*
+ * Splits the command line into two strings:
+ * 1. Options to the Erlang node (ErlCommandLine)
+ * 2. Options to this program (MyCommandLine)
+ */
+void split_commandline(void)
+{
+ char *cmdline = CommandLineStart;
+
+ progname=cmdline;
+
+ /* Remove the first (quoted) string (our program name) */
+ if(*cmdline == '"') {
+ cmdline++; /* Skip " */
+ while( (*cmdline != '\0') && (*cmdline++) != '"' )
+ ;
+ } else {
+ while( (*cmdline != '\0') && (*cmdline++) != ' ' )
+ ;
+ }
+
+ while( (*cmdline) == ' ' )
+ cmdline++;
+
+ if( *cmdline == '\0') {
+ ErlCommandLine = "";
+ MyCommandLine = "";
+ return;
+ }
+
+ cmdline[-1] = '\0';
+
+ /* Start from the end of the string and search for "++ "
+ (PLUS PLUS SPACE) */
+ ErlCommandLine = cmdline;
+ if(strncmp(cmdline,"++ ",3))
+ cmdline = strstr(cmdline," ++ ");
+ if( cmdline == NULL ) {
+ MyCommandLine = "";
+ return;
+ }
+ /* Terminate the ErlCommandLine where MyCommandLine starts */
+ *cmdline++ = '\0';
+
+ /* Skip 'whitespace--whitespace' (WHITESPACE MINUS MINUS WHITESPACE) */
+ while( (*cmdline) == ' ' )
+ cmdline++;
+ while( (*cmdline) == '+' )
+ cmdline++;
+ while( (*cmdline) == ' ' )
+ cmdline++;
+
+ MyCommandLine = cmdline;
+
+#ifdef _DEBUG
+ fprintf(stderr, "ErlCommandLine: '%s'\n", ErlCommandLine);
+ fprintf(stderr, "MyCommandLine: '%s'\n", MyCommandLine);
+#endif
+}
+
+
+/*
+ * 'Smart' unquoting of a string: \" becomes " and " becomes (nothing)
+ * Skips any leading spaces and parses up to NULL or end of quoted string.
+ * Calls exit_help() if an unterminated quote is detected.
+ */
+char * unquote_optionarg(char *str, char **strp)
+{
+ char *newstr = (char *)malloc(strlen(str)+1); /* This one is realloc:ed later */
+ int i=0, inquote=0;
+
+ assert(newstr);
+ assert(str);
+
+ /* Skip leading spaces */
+ while( *str == ' ' )
+ str++;
+
+ /* Loop while in quote or until EOS or unquoted space
+ */
+ while( (inquote==1) || ( (*str!=0) && (*str!=' ') ) ) {
+ switch( *str ) {
+ case '\\':
+ /* If we are inside a quoted string we should convert \c to c */
+ if( inquote && str[1] == '"' )
+ str++;
+ newstr[i++]=*str++;
+ break;
+ case '"':
+ inquote = 1-inquote;
+ *str++;
+ break;
+ default:
+ newstr[i++]=*str++;
+ break;
+ }
+
+ if( (*str == 0) && (inquote==1) ) {
+ exit_help("Unterminated quote.");
+ }
+ }
+ newstr[i++] = 0x00;
+
+ /* Update the supplied pointer (used for continued parsing of options) */
+ *strp = str;
+
+ /* Adjust memblock of newstr */
+ newstr = (char *)realloc(newstr, i);
+ assert(newstr);
+ return(newstr);
+}
+
+
+/*
+ * Parses MyCommandLine and tries to fill in all the required option variables
+ * (one way or another).
+ */
+void parse_commandline(void)
+{
+ char *cmdline = MyCommandLine;
+
+ while( *cmdline != '\0' ) {
+ switch( *cmdline ) {
+ case '-': /* Handle both -arg and /arg */
+ case '/':
+ *cmdline++;
+ if( strnicmp(cmdline, "data", 4) == 0) {
+ DataFileName = unquote_optionarg(cmdline+4, &cmdline);
+ } else if( strnicmp(cmdline, "reldir", 6) == 0) {
+ RelDir = unquote_optionarg(cmdline+6, &cmdline);
+#ifdef _DEBUG
+ fprintf(stderr, "RelDir: '%s'\n", RelDir);
+#endif
+ } else if( strnicmp(cmdline, "bootflags", 9) == 0) {
+ BootFlagsFile = unquote_optionarg(cmdline+9, &cmdline);
+ } else if( strnicmp(cmdline, "noconfig", 8) == 0) {
+ NoConfig=TRUE;
+#ifdef _DEBUG
+ fprintf(stderr, "NoConfig=TRUE\n");
+#endif
+ } else {
+ fprintf(stderr, "Unkown option: '%s'\n", cmdline);
+ exit_help("Unknown command line option");
+ }
+ break;
+ default:
+ cmdline++;
+ break;
+ }
+ }
+}
+
+
+/*
+ * Read the data file specified and get the version and release number
+ * from it.
+ *
+ * This function also construct the correct RegistryKey from the version information
+ * retrieved.
+ */
+void read_datafile(void)
+{
+ FILE *fp;
+ char *newname;
+ long size;
+
+ if(!DataFileName){
+ DataFileName = malloc(strlen(DEFAULT_DATAFILE) + 1);
+ strcpy(DataFileName,DEFAULT_DATAFILE);
+ }
+ /* Is DataFileName relative or absolute ? */
+ if( (DataFileName[0] != '\\') && (strncmp(DataFileName+1, ":\\", 2)!=0) ) {
+ /* Relative name, we have to prepend RelDir to it. */
+ if( !RelDir ) {
+ exit_help("Need -reldir when -data filename has relative path.");
+ } else {
+ newname = (char *)malloc(strlen(DataFileName)+strlen(RelDir)+2);
+ assert(newname);
+ sprintf(newname, "%s\\%s", RelDir, DataFileName);
+ free(DataFileName);
+ DataFileName=newname;
+ }
+ }
+
+#ifdef _DEBUG
+ fprintf(stderr, "DataFileName: '%s'\n", DataFileName);
+#endif
+
+ if( (fp=fopen(DataFileName, "rb")) == NULL) {
+ exit_help("Cannot find the datafile.");
+ }
+
+ fseek(fp, 0, SEEK_END);
+ size=ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ Version = (char *)malloc(size+1);
+ Release = (char *)malloc(size+1);
+ assert(Version);
+ assert(Release);
+
+ if( (fscanf(fp, "%s %s", Version, Release)) == 0) {
+ fclose(fp);
+ exit_help("Format error in datafile.");
+ }
+
+ fclose(fp);
+
+#ifdef _DEBUG
+ fprintf(stderr, "DataFile version: '%s'\n", Version);
+ fprintf(stderr, "DataFile release: '%s'\n", Release);
+#endif
+}
+
+
+/*
+ * Read the registry keys we need
+ */
+void read_registry_keys(void)
+{
+ HKEY hReg;
+ ULONG lLen;
+
+ /* Create the RegistryKey name */
+ RegistryKey = (char *) malloc(strlen(REGISTRY_BASE) +
+ strlen(Version) + 1);
+ assert(RegistryKey);
+ sprintf(RegistryKey, REGISTRY_BASE "%s", Version);
+
+ /* We always need to find BinDir */
+ if( (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ RegistryKey,
+ 0,
+ KEY_READ,
+ &hReg)) != ERROR_SUCCESS ) {
+ exit_help("Could not open registry key.");
+ }
+
+ /* First query size of data */
+ if( (RegQueryValueEx(hReg,
+ "Bindir",
+ NULL,
+ NULL,
+ NULL,
+ &lLen)) != ERROR_SUCCESS) {
+ exit_help("Failed to query BinDir of release.\n");
+ }
+
+ /* Allocate enough space */
+ BinDir = (char *)malloc(lLen+1);
+ assert(BinDir);
+ /* Retrieve the value */
+ if( (RegQueryValueEx(hReg,
+ "Bindir",
+ NULL,
+ NULL,
+ (unsigned char *) BinDir,
+ &lLen)) != ERROR_SUCCESS) {
+ exit_help("Failed to query BinDir of release (2).\n");
+ }
+
+#ifdef _DEBUG
+ fprintf(stderr, "Bindir: '%s'\n", BinDir);
+#endif
+
+ /* We also need the rootdir, in case we need to build RelDir later */
+
+ /* First query size of data */
+ if( (RegQueryValueEx(hReg,
+ "Rootdir",
+ NULL,
+ NULL,
+ NULL,
+ &lLen)) != ERROR_SUCCESS) {
+ exit_help("Failed to query RootDir of release.\n");
+ }
+
+ /* Allocate enough space */
+ RootDir = (char *) malloc(lLen+1);
+ assert(RootDir);
+ /* Retrieve the value */
+ if( (RegQueryValueEx(hReg,
+ "Rootdir",
+ NULL,
+ NULL,
+ (unsigned char *) RootDir,
+ &lLen)) != ERROR_SUCCESS) {
+ exit_help("Failed to query RootDir of release (2).\n");
+ }
+
+#ifdef _DEBUG
+ fprintf(stderr, "Rootdir: '%s'\n", RootDir);
+#endif
+
+ RegCloseKey(hReg);
+}
+
+/*
+ * Read the bootflags. This file contains extra command line options to erl.exe
+ */
+void read_bootflags(void)
+{
+ FILE *fp;
+ long fsize;
+ char *newname;
+
+ if(BootFlagsFile) {
+ /* Is BootFlagsFile relative or absolute ? */
+ if( (BootFlagsFile[0] != '\\') &&
+ (strncmp(BootFlagsFile+1, ":\\", 2)!=0) ) {
+ /* Relative name, we have to prepend RelDir\\Version to it. */
+ if( !RelDir ) {
+ exit_help("Need -reldir when -bootflags "
+ "filename has relative path.");
+ } else {
+ newname = (char *)malloc(strlen(BootFlagsFile)+strlen(RelDir)+strlen(Release)+3);
+ assert(newname);
+ sprintf(newname, "%s\\%s\\%s", RelDir, Release, BootFlagsFile);
+ free(BootFlagsFile);
+ BootFlagsFile=newname;
+ }
+ }
+
+#ifdef _DEBUG
+ fprintf(stderr, "BootFlagsFile: '%s'\n", BootFlagsFile);
+#endif
+
+
+
+ if( (fp=fopen(BootFlagsFile, "rb")) == NULL) {
+ exit_help("Could not open BootFlags file.");
+ }
+
+ fseek(fp, 0, SEEK_END);
+ fsize=ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ BootFlags = (char *)malloc(fsize+1);
+ assert(BootFlags);
+ if( (fgets(BootFlags, fsize+1, fp)) == NULL) {
+ exit_help("Error while reading BootFlags file");
+ }
+ fclose(fp);
+
+ /* Adjust buffer size */
+ BootFlags = (char *)realloc(BootFlags, strlen(BootFlags)+1);
+ assert(BootFlags);
+
+ /* Strip \r\n from BootFlags */
+ fsize = strlen(BootFlags);
+ while( fsize > 0 &&
+ ( (BootFlags[fsize-1] == '\r') ||
+ (BootFlags[fsize-1] == '\n') ) ) {
+ BootFlags[--fsize]=0;
+ }
+
+ } else {
+ /* Set empty BootFlags */
+ BootFlags = "";
+ }
+
+#ifdef _DEBUG
+ fprintf(stderr, "BootFlags: '%s'\n", BootFlags);
+#endif
+}
+
+
+long start_new_node(void)
+{
+ char *CommandLine;
+ unsigned long i;
+ STARTUPINFO si;
+ DWORD dwExitCode;
+
+ i = strlen(RelDir) + strlen(Release) + 4;
+ VsnDir = (char *)malloc(i);
+ assert(VsnDir);
+ sprintf(VsnDir, "%s\\%s", RelDir, Release);
+
+ if( NoConfig ) {
+ i = strlen(BinDir) + strlen(ErlCommandLine) +
+ strlen(BootFlags) + 64;
+ CommandLine = (char *)malloc(i);
+ assert(CommandLine);
+ sprintf(CommandLine,
+ "\"%s\\erl.exe\" -boot \"%s\\start\" %s %s",
+ BinDir,
+ VsnDir,
+ ErlCommandLine,
+ BootFlags);
+ } else {
+ i = strlen(BinDir) + strlen(ErlCommandLine)
+ + strlen(BootFlags) + strlen(VsnDir)*2 + 64;
+ CommandLine = (char *)malloc(i);
+ assert(CommandLine);
+ sprintf(CommandLine,
+ "\"%s\\erl.exe\" -boot \"%s\\start\" -config \"%s\\sys\" %s %s",
+ BinDir,
+ VsnDir,
+ VsnDir,
+ ErlCommandLine,
+ BootFlags);
+ }
+
+#ifdef _DEBUG
+ fprintf(stderr, "CommandLine: '%s'\n", CommandLine);
+#endif
+
+ /* Initialize the STARTUPINFO structure. */
+ memset(&si, 0, sizeof(STARTUPINFO));
+ si.cb = sizeof(STARTUPINFO);
+ si.lpTitle = NULL;
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+ si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+
+ /* Create the new Erlang process */
+ if( (CreateProcess(
+ NULL, /* pointer to name of executable module */
+ CommandLine, /* pointer to command line string */
+ NULL, /* pointer to process security attributes */
+ NULL, /* pointer to thread security attributes */
+ TRUE, /* handle inheritance flag */
+ GetPriorityClass(GetCurrentProcess()),
+ /* creation flags */
+ NULL, /* pointer to new environment block */
+ BinDir,/* pointer to current directory name */
+ &si, /* pointer to STARTUPINFO */
+ &ErlProcessInfo /* pointer to PROCESS_INFORMATION */
+ )) == FALSE) {
+ ShowLastError();
+ exit_help("Failed to start new node");
+ }
+
+#ifdef _DEBUG
+ fprintf(stderr, "Waiting for Erlang to terminate.\n");
+#endif
+ if(MsgWaitForMultipleObjects(1,&ErlProcessInfo.hProcess, FALSE,
+ INFINITE, QS_POSTMESSAGE) == WAIT_OBJECT_0+1){
+ if(PostThreadMessage(ErlProcessInfo.dwThreadId,
+ WM_USER,
+ (WPARAM) 0,
+ (LPARAM) 0)){
+ /* Wait 10 seconds for erl process to die, elsee terminate it. */
+ if(WaitForSingleObject(ErlProcessInfo.hProcess, 10000)
+ != WAIT_OBJECT_0){
+ TerminateProcess(ErlProcessInfo.hProcess,0);
+ }
+ } else {
+ TerminateProcess(ErlProcessInfo.hProcess,0);
+ }
+ }
+ GetExitCodeProcess(ErlProcessInfo.hProcess, &dwExitCode);
+#ifdef _DEBUG
+ fprintf(stderr, "Erlang terminated.\n");
+#endif
+
+ free(CommandLine);
+ return(dwExitCode);
+}
+
+
+/*
+ * Try to make the needed options complete by looking through the data file,
+ * environment variables and registry entries.
+ */
+void complete_options(void)
+{
+ /* Try to find a descent RelDir */
+ if( !RelDir ) {
+ DWORD sz = 32;
+ while (1) {
+ DWORD nsz;
+ if (RelDir)
+ free(RelDir);
+ RelDir = malloc(sz);
+ if (!RelDir) {
+ fprintf(stderr, "** Error : failed to allocate memory\n");
+ exit(1);
+ }
+ SetLastError(0);
+ nsz = GetEnvironmentVariable((LPCTSTR) "RELDIR",
+ (LPTSTR) RelDir,
+ sz);
+ if (nsz == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
+ free(RelDir);
+ RelDir = NULL;
+ break;
+ }
+ else if (nsz <= sz)
+ break;
+ else
+ sz = nsz;
+ }
+ if (RelDir == NULL) {
+ if(DataFileName){
+ /* Needs to be absolute for this to work, but we
+ can try... */
+ read_datafile();
+ read_registry_keys();
+ } else {
+ /* Impossible to find all data... */
+ exit_help("Need either Release directory or an absolute "
+ "datafile name.");
+ }
+ /* Ok, construct our own RelDir from RootDir */
+ RelDir = (char *) malloc(strlen(RootDir)+strlen(RELEASE_SUBDIR)+1);
+ assert(RelDir);
+ sprintf(RelDir, "%s" RELEASE_SUBDIR, RootDir);
+ } else {
+ read_datafile();
+ read_registry_keys();
+ }
+ } else {
+ read_datafile();
+ read_registry_keys();
+ }
+ read_bootflags();
+
+#ifdef _DEBUG
+ fprintf(stderr, "RelDir: '%s'\n", RelDir);
+#endif
+}
+
+
+
+
+BOOL WINAPI LogoffHandlerRoutine( DWORD dwCtrlType )
+{
+ if(dwCtrlType == CTRL_LOGOFF_EVENT) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+
+int main(void)
+{
+ DWORD dwExitCode;
+ char *cmdline;
+
+ /* Make sure a logoff does not distrurb us. */
+ SetConsoleCtrlHandler(LogoffHandlerRoutine, TRUE);
+
+ cmdline = GetCommandLine();
+ assert(cmdline);
+
+ CommandLineStart = (char *) malloc(strlen(cmdline) + 1);
+ assert(CommandLineStart);
+ strcpy(CommandLineStart,cmdline);
+
+ split_commandline();
+ parse_commandline();
+ complete_options();
+
+ /* We now have all the options we need in order to fire up a new node.. */
+ dwExitCode = start_new_node();
+
+ return( (int) dwExitCode );
+}
+
+
diff --git a/erts/etc/win32/toolbar.bmp b/erts/etc/win32/toolbar.bmp
new file mode 100644
index 0000000000..e0df8454fd
--- /dev/null
+++ b/erts/etc/win32/toolbar.bmp
Binary files differ
diff --git a/erts/etc/win32/win_erlexec.c b/erts/etc/win32/win_erlexec.c
new file mode 100644
index 0000000000..0eed8e28b9
--- /dev/null
+++ b/erts/etc/win32/win_erlexec.c
@@ -0,0 +1,405 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1997-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+/*
+ * Extra support for running the emulator on Windows.
+ * Most of this only used when beam is run as a separate process.
+ */
+
+#pragma comment(linker,"/manifestdependency:\"type='win32' "\
+ "name='Microsoft.Windows.Common-Controls' "\
+ "version='6.0.0.0' processorArchitecture='*' "\
+ "publicKeyToken='6595b64144ccf1df' language='*'\"")
+
+#include <windows.h>
+#include <winuser.h>
+#include <wincon.h>
+#include <process.h>
+#include "sys.h"
+#include "erl_driver.h"
+
+extern int nohup;
+extern int keep_window;
+void error(char* format, ...);
+
+/*
+ * Local functions.
+ */
+#define LOAD_BEAM_DYNAMICALLY 1
+static int start(char* emu, char** argv);
+static void start_winsock(void);
+static char* last_error(void);
+static char* last_wsa_error(void);
+static char* win32_errorstr(int error);
+static int has_console(void);
+static char** fnuttify_argv(char **argv);
+static void free_fnuttified(char **v);
+static int windowed = 0;
+
+#ifdef LOAD_BEAM_DYNAMICALLY
+typedef int SysGetKeyFunction(int);
+typedef void ErlStartFunction(int, char **);
+typedef void SysPrimitiveInitFunction(HMODULE);
+static SysGetKeyFunction *sys_get_key_p;
+static ErlStartFunction *erl_start_p;
+static SysPrimitiveInitFunction *sys_primitive_init_p;
+
+static HMODULE load_win_beam_dll(char *name)
+{
+ HMODULE beam_module;
+ beam_module=LoadLibrary(name);
+ if (beam_module == INVALID_HANDLE_VALUE || beam_module == NULL) {
+ error("Unable to load emulator DLL\n(%s)",name);
+ return NULL;
+ }
+ sys_get_key_p = (SysGetKeyFunction *)
+ GetProcAddress(beam_module, "sys_get_key");
+ erl_start_p = (ErlStartFunction *)
+ GetProcAddress(beam_module, "erl_start");
+ sys_primitive_init_p = (SysPrimitiveInitFunction *)
+ GetProcAddress(beam_module, "sys_primitive_init");
+ return beam_module;
+}
+#endif
+
+#define DLL_ENV "ERL_EMULATOR_DLL"
+
+static void
+set_env(char *key, char *value)
+{
+ if (!SetEnvironmentVariable((LPCTSTR) key, (LPCTSTR) value))
+ error("SetEnvironmentVariable(\"%s\", \"%s\") failed!", key, value);
+}
+
+static char *
+get_env(char *key)
+{
+ DWORD size = 32;
+ char *value = NULL;
+ while (1) {
+ DWORD nsz;
+ if (value)
+ free(value);
+ value = malloc(size);
+ if (!value)
+ error("GetEnvironmentVariable(\"%s\") failed", key);
+ SetLastError(0);
+ nsz = GetEnvironmentVariable((LPCTSTR) key, (LPTSTR) value, size);
+ if (nsz == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
+ free(value);
+ return NULL;
+ }
+ if (nsz <= size)
+ return value;
+ size = nsz;
+ }
+}
+
+free_env_val(char *value)
+{
+ if (value)
+ free(value);
+}
+
+
+int
+start_win_emulator(char* emu, char *start_prog, char** argv, int start_detached)
+{
+ int result;
+
+ windowed = 1;
+ if (start_detached) {
+ char *buff;
+ close(0);
+ close(1);
+ close(2);
+
+ set_env("ERL_CONSOLE_MODE", "detached");
+ set_env(DLL_ENV, emu);
+
+ argv[0] = start_prog;
+ argv = fnuttify_argv(argv);
+ result = spawnv(_P_DETACH, start_prog, argv);
+ free_fnuttified(argv);
+ } else {
+ int argc = 0;
+#ifdef LOAD_BEAM_DYNAMICALLY
+ HMODULE beam_module = load_win_beam_dll(emu);
+#endif
+ set_env("ERL_CONSOLE_MODE", "window");
+ while (argv[argc] != NULL) {
+ ++argc;
+ }
+#ifdef ARGS_HARDDEBUG
+ {
+ char sbuf[2048] = "";
+ int i;
+ for (i = 0; i < argc; ++i) {
+ strcat(sbuf,"|");
+ strcat(sbuf, argv[i]);
+ strcat(sbuf,"| ");
+ }
+ MessageBox(NULL, sbuf, "Werl", MB_OK|MB_ICONERROR);
+ }
+#endif
+#ifdef LOAD_BEAM_DYNAMICALLY
+ (*sys_primitive_init_p)(beam_module);
+ (*erl_start_p)(argc,argv);
+#else
+ erl_start(argc, argv);
+#endif
+ result = 0;
+ }
+ if (result == -1) {
+ error("Failed to execute %s: %s", emu, win32_errorstr(_doserrno));
+ }
+ return 0;
+}
+
+void __cdecl
+do_keep_window(void)
+{
+ printf("\nPress any key to close window.\n");
+#ifdef LOAD_BEAM_DYNAMICALLY
+ (*sys_get_key_p)(0);
+#else
+ sys_get_key(0);
+#endif
+}
+
+int
+start_emulator(char* emu, char *start_prog, char** argv, int start_detached)
+{
+ int result;
+ static char console_mode[] = "tty:ccc";
+ char* fd_type;
+ char* title;
+
+#ifdef HARDDEBUG
+ fprintf(stderr,"emu = %s, start_prog = %s\n",emu, start_prog);
+#endif
+
+ fd_type = strchr(console_mode, ':');
+ fd_type++;
+ _flushall();
+
+ /*
+ * If no console, we will spawn the emulator detached.
+ */
+
+ if (start_detached) {
+ char *buff;
+ close(0);
+ close(1);
+ close(2);
+ set_env("ERL_CONSOLE_MODE", "detached");
+ set_env(DLL_ENV, emu);
+
+ argv[0] = start_prog;
+ argv = fnuttify_argv(argv);
+#ifdef ARGS_HARDDEBUG
+ {
+ char buffer[2048];
+ int i;
+ sprintf(buffer,"Start detached [%s]\n",start_prog);
+ for(i=0;argv[i] != NULL;++i) {
+ strcat(buffer,"|");
+ strcat(buffer,argv[i]);
+ strcat(buffer,"|\n");
+ }
+ MessageBox(NULL, buffer,"Start detached",MB_OK);
+ }
+#endif
+ result = spawnv(_P_DETACH, start_prog, argv);
+ free_fnuttified(argv);
+ if (result == -1) {
+#ifdef ARGS_HARDDEBUG
+ MessageBox(NULL, "_spawnv failed","Start detached",MB_OK);
+#endif
+ return 1;
+ }
+ SetPriorityClass((HANDLE) result, GetPriorityClass(GetCurrentProcess()));
+ } else {
+ int argc = 0;
+#ifdef LOAD_BEAM_DYNAMICALLY
+ HMODULE beam_module = load_win_beam_dll(emu);
+#endif
+
+ /*
+ * Start the emulator.
+ */
+
+ title = get_env("ERL_WINDOW_TITLE");
+ if (title) {
+ SetConsoleTitle(title);
+ }
+ free_env_val(title);
+
+ set_env("ERL_CONSOLE_MODE", console_mode);
+ while (argv[argc] != NULL) {
+ ++argc;
+ }
+ if (keep_window) {
+ atexit(do_keep_window);
+ }
+#ifdef ARGS_HARDDEBUG
+ {
+ char sbuf[2048] = "";
+ int i;
+ for (i = 0; i < argc; ++i) {
+ strcat(sbuf,"|");
+ strcat(sbuf, argv[i]);
+ strcat(sbuf,"|\n");
+ }
+ MessageBox(NULL, sbuf, "erl", MB_OK);
+ }
+#endif
+#ifdef LOAD_BEAM_DYNAMICALLY
+ (*sys_primitive_init_p)(beam_module);
+ (*erl_start_p)(argc,argv);
+#else
+ erl_start(argc, argv);
+#endif
+ }
+ return 0;
+}
+
+void
+error(char* format, ...)
+{
+ char sbuf[2048];
+ va_list ap;
+
+ va_start(ap, format);
+ vsprintf(sbuf, format, ap);
+ va_end(ap);
+
+ if (!windowed && has_console()) {
+ fprintf(stderr, "%s\n", sbuf);
+ } else {
+ MessageBox(NULL, sbuf, "Werl", MB_OK|MB_ICONERROR);
+ }
+ exit(1);
+}
+
+static char*
+last_error(void)
+{
+ return win32_errorstr(GetLastError());
+}
+
+/*
+ * Returns a human-readable description of the last error.
+ * The returned pointer will be valid only as long as last-error()
+ * isn't called again.
+ */
+
+static char*
+win32_errorstr(int error)
+{
+ static LPTSTR lpBufPtr = NULL;
+
+ if (lpBufPtr)
+ LocalFree(lpBufPtr);
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ error,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpBufPtr,
+ 0,
+ NULL);
+ SetLastError(error);
+ return lpBufPtr;
+}
+
+static int
+has_console(void)
+{
+ HANDLE handle = CreateFile("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static char** fnuttify_argv(char **argv)
+{
+ char **v;
+ char *p;
+ char *q;
+ int c;
+ int i;
+ int n;
+ int m;
+
+ for (c = 0; argv[c]; ++c)
+ ;
+
+ v = malloc(sizeof(char *) * (c+1));
+ v[c] = NULL;
+ for (i = 0; i < c; ++i) {
+ p = argv[i];
+ n = m = 0;
+ while (*p) {
+ if (*p == ' ') {
+ m = 2;
+ } else if (*p == '"') {
+ m = 2;
+ ++n;
+ }
+ ++p;
+ }
+ v[i] = malloc((p - argv[i]) + 1 + n + m);
+ p = argv[i];
+ q = v[i];
+ if (n || m) {
+ if (m) {
+ *q++ = '"';
+ }
+ while (*p) {
+ if (*p == '"') {
+ *q++ = '\\';
+ }
+ *q++ = *p++;
+ }
+ if (m) {
+ *q++ = '"';
+ }
+ *q = '\0';
+ } else {
+ strcpy(q,p);
+ }
+ }
+ return v;
+}
+
+static void free_fnuttified(char **v)
+{
+ char **t = v;
+
+ while(*t) {
+ free(*t);
+ ++t;
+ }
+ free(v);
+}