Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTorbjörn Svensson2020-06-21 14:52:00 +0000
committerJonah Graham2020-08-07 00:55:42 +0000
commit00a52086c9e3c7457be830ee38626c2af0225c23 (patch)
tree43dbb2af7ea6945ed40d567c48fe40b03da3d955 /core/org.eclipse.cdt.core.native
parent69acfe4819bcde20d20598ede0be1a6d33a560e3 (diff)
downloadorg.eclipse.cdt-00a52086c9e3c7457be830ee38626c2af0225c23.tar.gz
org.eclipse.cdt-00a52086c9e3c7457be830ee38626c2af0225c23.tar.xz
org.eclipse.cdt-00a52086c9e3c7457be830ee38626c2af0225c23.zip
Bug 521515: Adopt native build support on jenkins
Change-Id: I6aee7a7c94f93375d3a2ddb0171602a27a6873e7 Signed-off-by: Torbjörn Svensson <azoff@svenskalinuxforeningen.se>
Diffstat (limited to 'core/org.eclipse.cdt.core.native')
-rw-r--r--core/org.eclipse.cdt.core.native/build.properties3
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/Makefile140
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/include/PTY.h45
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/include/PTYInputStream.h31
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/include/PTYOutputStream.h29
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/include/Spawner.h78
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/include/SpawnerInputStream.h50
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/include/SpawnerOutputStream.h46
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/unix/exec0.h32
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/unix/exec_pty.c189
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/unix/exec_unix.c161
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/unix/io.c117
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/unix/openpty.c137
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/unix/openpty.h21
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/unix/pfind.c112
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/unix/pty.c74
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/unix/ptyio.c120
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/unix/spawner.c305
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/win/Win32ProcessEx.c1018
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/win/iostream.c279
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/win/raise.c194
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/win/spawner.c60
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/win/starter.c527
-rw-r--r--core/org.eclipse.cdt.core.native/pom.xml108
24 files changed, 3875 insertions, 1 deletions
diff --git a/core/org.eclipse.cdt.core.native/build.properties b/core/org.eclipse.cdt.core.native/build.properties
index 2e7a449116e..006a08c7bcb 100644
--- a/core/org.eclipse.cdt.core.native/build.properties
+++ b/core/org.eclipse.cdt.core.native/build.properties
@@ -22,7 +22,8 @@ bin.includes = plugin.properties,\
about.properties,\
plugin.xml
src.includes = about.html,\
- schema/
+ schema/,\
+ native_src/
javadoc.packages = org.eclipse.cdt.utils.*,\
org.eclipse.cdt.utils.pty.*,\
org.eclipse.cdt.utils.spawner.*
diff --git a/core/org.eclipse.cdt.core.native/native_src/Makefile b/core/org.eclipse.cdt.core.native/native_src/Makefile
new file mode 100644
index 00000000000..36324b888bd
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/Makefile
@@ -0,0 +1,140 @@
+#*******************************************************************************
+# Copyright (c) 2002, 2015, 2020 QNX Software Systems and others.
+#
+# This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License 2.0
+# which accompanies this distribution, and is available at
+# https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+#
+# Contributors:
+# QNX Software Systems - initial API and implementation
+# Torbjörn Svensson - Bug 521515 - Adopted jenkins build
+#*******************************************************************************/
+
+ifeq ($(JAVA_HOME),)
+$(error JAVA_HOME not set in environment)
+endif
+
+OS_DIR_WIN32_X86_64 := ../../org.eclipse.cdt.core.win32.x86_64/os/win32/x86_64
+OS_DIR_LINUX_X86_64 := ../../org.eclipse.cdt.core.linux.x86_64/os/linux/x86_64
+OS_DIR_LINUX_PPC64LE := ../../org.eclipse.cdt.core.linux.ppc64le/os/linux/ppc64le
+OS_DIR_MACOS_X86_64 := ../../org.eclipse.cdt.core.macosx/os/macosx/x86_64
+OS_DIR_MACOS_X86 := ../../org.eclipse.cdt.core.macosx/os/macosx/x86
+
+
+UNAME = $(shell uname)
+ifeq ($(UNAME),Linux)
+LIBS = \
+ $(OS_DIR_WIN32_X86_64)/starter.exe \
+ $(OS_DIR_WIN32_X86_64)/spawner.dll \
+ $(OS_DIR_LINUX_X86_64)/libspawner.so \
+ $(OS_DIR_LINUX_X86_64)/libpty.so \
+ $(OS_DIR_MACOS_X86_64)/libspawner.jnilib \
+ $(OS_DIR_MACOS_X86_64)/libpty.jnilib \
+ $(OS_DIR_MACOS_X86)/libspawner.jnilib \
+ $(OS_DIR_MACOS_X86)/libpty.jnilib
+else
+ifeq ($(UNAME),Darwin)
+LIBS = \
+ $(OS_DIR_MACOS_X86_64)/libspawner.jnilib \
+ $(OS_DIR_MACOS_X86_64)/libpty.jnilib \
+ $(OS_DIR_MACOS_X86)/libspawner.jnilib \
+ $(OS_DIR_MACOS_X86)/libpty.jnilib
+else
+LIBS = \
+ $(OS_DIR_WIN32_X86_64)/starter.exe \
+ $(OS_DIR_WIN32_X86_64)/spawner.dll
+endif
+endif
+
+all: $(LIBS)
+
+clean :
+ $(RM) $(LIBS)
+
+rebuild: clean all
+
+
+# Windows x86_64
+# Windows DLLs have a build timestamp in them. This makes it impossible to have reproducible builds.
+# However, x86_64-w64-mingw32-ld on Debian/Ubuntu has a patch that overrides the current date
+# using the SOURCE_DATE_EPOCH environment variable. Therefore we set SOURCE_DATE_EPOCH to a
+# consistent timestamp that can be reproduced. We base it off of the commit timestamp of the
+# most recent git commit in this directory.
+$(OS_DIR_WIN32_X86_64)/starter.exe: win/starter.c
+ mkdir -p $(dir $@) && \
+ SOURCE_DATE_EPOCH=$(shell git log -1 --pretty=format:%ct -- .) \
+ x86_64-w64-mingw32-gcc -o $@ -Iinclude -I"$(JAVA_HOME)/include" -I"$(JAVA_HOME)/include/win32" \
+ -DUNICODE \
+ win/starter.c \
+ -lpsapi
+
+$(OS_DIR_WIN32_X86_64)/spawner.dll: win/iostream.c win/raise.c win/spawner.c win/Win32ProcessEx.c
+ mkdir -p $(dir $@) && \
+ SOURCE_DATE_EPOCH=$(shell git log -1 --pretty=format:%ct -- .) \
+ x86_64-w64-mingw32-gcc -o $@ -Iinclude -I"$(JAVA_HOME)/include" -I"$(JAVA_HOME)/include/win32" \
+ -DUNICODE \
+ win/iostream.c win/raise.c win/spawner.c win/Win32ProcessEx.c \
+ -Wl,--kill-at --shared
+
+# Linux x86_64
+$(OS_DIR_LINUX_X86_64)/libspawner.so: unix/spawner.c unix/io.c unix/exec_unix.c unix/exec_pty.c unix/openpty.c unix/pfind.c
+ mkdir -p $(dir $@) && \
+ gcc -m64 -o $@ -Wl,-soname,$(notdir $@) -Iinclude -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -fpic \
+ -D_REENTRANT -D_GNU_SOURCE \
+ unix/spawner.c unix/io.c unix/exec_unix.c unix/exec_pty.c unix/openpty.c unix/pfind.c \
+ -shared -lc
+
+$(OS_DIR_LINUX_X86_64)/libpty.so: unix/openpty.c unix/pty.c unix/ptyio.c
+ mkdir -p $(dir $@) && \
+ gcc -m64 -o $@ -Wl,-soname,$(notdir $@) -Iinclude -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -fpic \
+ -D_REENTRANT -D_GNU_SOURCE \
+ unix/openpty.c unix/pty.c unix/ptyio.c \
+ -shared -lc
+
+# Linux ppc64le
+$(OS_DIR_LINUX_PPC64LE)/libspawner.so: unix/spawner.c unix/io.c unix/exec_unix.c unix/exec_pty.c unix/openpty.c unix/pfind.c
+ mkdir -p $(dir $@) && \
+ gcc -m64 -o $@ -Wl,-soname,$(notdir $@) -Iinclude -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -fpic \
+ -D_REENTRANT -D_GNU_SOURCE \
+ unix/spawner.c unix/io.c unix/exec_unix.c unix/exec_pty.c unix/openpty.c unix/pfind.c \
+ -shared -lc
+
+$(OS_DIR_LINUX_PPC64LE)/libpty.so: unix/openpty.c unix/pty.c unix/ptyio.c
+ mkdir -p $(dir $@) && \
+ gcc -m64 -o $@ -Wl,-soname,$(notdir $@) -Iinclude -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -fpic \
+ -D_REENTRANT -D_GNU_SOURCE \
+ unix/openpty.c unix/pty.c unix/ptyio.c \
+ -shared -lc
+
+# macos x86_64
+$(OS_DIR_MACOS_X86_64)/libspawner.jnilib: unix/spawner.c unix/io.c unix/exec_unix.c unix/exec_pty.c unix/openpty.c unix/pfind.c
+ mkdir -p $(dir $@) && \
+ x86_64-apple-darwin17-clang -o $@ -arch x86_64 -Iinclude -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/darwin -fPIC \
+ -D_REENTRANT \
+ unix/spawner.c unix/io.c unix/exec_unix.c unix/exec_pty.c unix/openpty.c unix/pfind.c \
+ -dynamiclib -lc -framework JavaVM
+
+$(OS_DIR_MACOS_X86_64)/libpty.jnilib: unix/openpty.c unix/pty.c unix/ptyio.c
+ mkdir -p $(dir $@) && \
+ x86_64-apple-darwin17-clang -o $@ -arch x86_64 -Iinclude -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/darwin -fPIC \
+ -D_REENTRANT \
+ unix/openpty.c unix/pty.c unix/ptyio.c \
+ -dynamiclib -lc -framework JavaVM
+
+# macos x86
+$(OS_DIR_MACOS_X86)/libspawner.jnilib: unix/spawner.c unix/io.c unix/exec_unix.c unix/exec_pty.c unix/openpty.c unix/pfind.c
+ mkdir -p $(dir $@) && \
+ x86_64-apple-darwin17-clang -o $@ -arch i386 -Iinclude -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/darwin -fPIC \
+ -D_REENTRANT \
+ unix/spawner.c unix/io.c unix/exec_unix.c unix/exec_pty.c unix/openpty.c unix/pfind.c \
+ -dynamiclib -lc -framework JavaVM
+
+$(OS_DIR_MACOS_X86)/libpty.jnilib: unix/openpty.c unix/pty.c unix/ptyio.c
+ mkdir -p $(dir $@) && \
+ x86_64-apple-darwin17-clang -o $@ -arch i386 -Iinclude -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/darwin -fPIC \
+ -D_REENTRANT \
+ unix/openpty.c unix/pty.c unix/ptyio.c \
+ -dynamiclib -lc -framework JavaVM
diff --git a/core/org.eclipse.cdt.core.native/native_src/include/PTY.h b/core/org.eclipse.cdt.core.native/native_src/include/PTY.h
new file mode 100644
index 00000000000..d73d5c00e16
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/include/PTY.h
@@ -0,0 +1,45 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_eclipse_cdt_utils_pty_PTY */
+
+#ifndef _Included_org_eclipse_cdt_utils_pty_PTY
+#define _Included_org_eclipse_cdt_utils_pty_PTY
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: org_eclipse_cdt_utils_pty_PTY
+ * Method: openMaster
+ * Signature: (Z)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_eclipse_cdt_utils_pty_PTY_openMaster
+ (JNIEnv *, jobject, jboolean);
+
+/*
+ * Class: org_eclipse_cdt_utils_pty_PTY
+ * Method: change_window_size
+ * Signature: (III)I
+ */
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_pty_PTY_change_1window_1size
+ (JNIEnv *, jobject, jint, jint, jint);
+
+/*
+ * Class: org_eclipse_cdt_utils_pty_PTY
+ * Method: exec2
+ * Signature: ([Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[ILjava/lang/String;IZ)I
+ */
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_pty_PTY_exec2
+ (JNIEnv *, jobject, jobjectArray, jobjectArray, jstring, jintArray, jstring, jint, jboolean);
+
+/*
+ * Class: org_eclipse_cdt_utils_pty_PTY
+ * Method: waitFor
+ * Signature: (II)I
+ */
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_pty_PTY_waitFor
+ (JNIEnv *, jobject, jint, jint);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/core/org.eclipse.cdt.core.native/native_src/include/PTYInputStream.h b/core/org.eclipse.cdt.core.native/native_src/include/PTYInputStream.h
new file mode 100644
index 00000000000..7767be6bd8c
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/include/PTYInputStream.h
@@ -0,0 +1,31 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_eclipse_cdt_utils_pty_PTYInputStream */
+
+#ifndef _Included_org_eclipse_cdt_utils_pty_PTYInputStream
+#define _Included_org_eclipse_cdt_utils_pty_PTYInputStream
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef org_eclipse_cdt_utils_pty_PTYInputStream_MAX_SKIP_BUFFER_SIZE
+#define org_eclipse_cdt_utils_pty_PTYInputStream_MAX_SKIP_BUFFER_SIZE 2048L
+/*
+ * Class: org_eclipse_cdt_utils_pty_PTYInputStream
+ * Method: read0
+ * Signature: (I[BI)I
+ */
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_pty_PTYInputStream_read0
+ (JNIEnv *, jobject, jint, jbyteArray, jint);
+
+/*
+ * Class: org_eclipse_cdt_utils_pty_PTYInputStream
+ * Method: close0
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_pty_PTYInputStream_close0
+ (JNIEnv *, jobject, jint);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/core/org.eclipse.cdt.core.native/native_src/include/PTYOutputStream.h b/core/org.eclipse.cdt.core.native/native_src/include/PTYOutputStream.h
new file mode 100644
index 00000000000..fb28491060e
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/include/PTYOutputStream.h
@@ -0,0 +1,29 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_eclipse_cdt_utils_pty_PTYOutputStream */
+
+#ifndef _Included_org_eclipse_cdt_utils_pty_PTYOutputStream
+#define _Included_org_eclipse_cdt_utils_pty_PTYOutputStream
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: org_eclipse_cdt_utils_pty_PTYOutputStream
+ * Method: write0
+ * Signature: (I[BI)I
+ */
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_pty_PTYOutputStream_write0
+ (JNIEnv *, jobject, jint, jbyteArray, jint);
+
+/*
+ * Class: org_eclipse_cdt_utils_pty_PTYOutputStream
+ * Method: close0
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_pty_PTYOutputStream_close0
+ (JNIEnv *, jobject, jint);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/core/org.eclipse.cdt.core.native/native_src/include/Spawner.h b/core/org.eclipse.cdt.core.native/native_src/include/Spawner.h
new file mode 100644
index 00000000000..10750f2e202
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/include/Spawner.h
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2010 QNX Software Systems and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *
+ * Spawner.h
+ *
+ * This is a part of JNI implementation of spawner
+ *******************************************************************************/
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_eclipse_cdt_utils_spawner_Spawner */
+
+#ifndef _Included_org_eclipse_cdt_utils_spawner_Spawner
+#define _Included_org_eclipse_cdt_utils_spawner_Spawner
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: org_eclipse_cdt_utils_spawner_Spawner
+ * Method: exec0
+ * Signature: ([Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[I)I
+ */
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
+ (JNIEnv *, jobject, jobjectArray, jobjectArray, jstring, jintArray);
+
+/*
+ * Class: org_eclipse_cdt_utils_spawner_Spawner
+ * Method: exec1
+ * Signature: ([Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec1
+ (JNIEnv *, jobject, jobjectArray, jobjectArray, jstring);
+
+/*
+ * Class: org_eclipse_cdt_utils_spawner_Spawner
+ * Method: exec2
+ * Signature: ([Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[ILjava/lang/String;IZ)I
+ */
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec2
+ (JNIEnv *, jobject, jobjectArray, jobjectArray, jstring, jintArray, jstring, jint, jboolean);
+
+/*
+ * Class: org_eclipse_cdt_utils_spawner_Spawner
+ * Method: raise
+ * Signature: (II)I
+ */
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_raise
+ (JNIEnv *, jobject, jint, jint);
+
+/*
+ * Class: org_eclipse_cdt_utils_spawner_Spawner
+ * Method: waitFor
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_waitFor
+ (JNIEnv *, jobject, jint);
+
+// #define DEBUG_MONITOR
+
+int interruptProcess(int pid);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+// #define DEBUG_MONITOR
+
+#endif
diff --git a/core/org.eclipse.cdt.core.native/native_src/include/SpawnerInputStream.h b/core/org.eclipse.cdt.core.native/native_src/include/SpawnerInputStream.h
new file mode 100644
index 00000000000..653c5659524
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/include/SpawnerInputStream.h
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2007 QNX Software Systems and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *
+ * SpawnerInputStream.h
+ *
+ * This is a part of JNI implementation of spawner
+ *******************************************************************************/
+
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_qnx_tools_utils_spawner_SpawnerInputStream */
+
+#ifndef _Included_com_qnx_tools_utils_spawner_SpawnerInputStream
+#define _Included_com_qnx_tools_utils_spawner_SpawnerInputStream
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef com_qnx_tools_utils_spawner_SpawnerInputStream_SKIP_BUFFER_SIZE
+#define com_qnx_tools_utils_spawner_SpawnerInputStream_SKIP_BUFFER_SIZE 2048L
+/* Inaccessible static: skipBuffer */
+/*
+ * Class: org_elipse_cdt_utils_spawner_SpawnerInputStream
+ * Method: read0
+ * Signature: (I[BI)I
+ */
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_read0
+ (JNIEnv *, jobject, jint, jbyteArray, jint);
+
+/*
+ * Class: org_eclipse_cdt_utils_spawner_SpawnerInputStream
+ * Method: close0
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_close0
+ (JNIEnv *, jobject, jint);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/core/org.eclipse.cdt.core.native/native_src/include/SpawnerOutputStream.h b/core/org.eclipse.cdt.core.native/native_src/include/SpawnerOutputStream.h
new file mode 100644
index 00000000000..fb3e0354e88
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/include/SpawnerOutputStream.h
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2007 QNX Software Systems and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *
+ * SpawnerOutputStream.h
+ *
+ * This is a part of JNI implementation of spawner
+ *******************************************************************************/
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_qnx_tools_utils_spawner_SpawnerOutputStream */
+
+#ifndef _Included_com_qnx_tools_utils_spawner_SpawnerOutputStream
+#define _Included_com_qnx_tools_utils_spawner_SpawnerOutputStream
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: org_eclipse_cdt_utils_spawner_SpawnerOutputStream
+ * Method: write0
+ * Signature: (I[BI)I
+ */
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_write0
+ (JNIEnv *, jobject, jint, jbyteArray, jint);
+
+/*
+ * Class: org_eclipse_cdt_utils_spawner_SpawnerOutputStream
+ * Method: close0
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_close0
+ (JNIEnv *, jobject, jint);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/core/org.eclipse.cdt.core.native/native_src/unix/exec0.h b/core/org.eclipse.cdt.core.native/native_src/unix/exec0.h
new file mode 100644
index 00000000000..04f363d5e53
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/unix/exec0.h
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2010 QNX Software Systems and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ * Wind River Systems, Inc.
+ * Mikhail Zabaluev (Nokia) - bug 82744
+ *******************************************************************************/
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <errno.h>
+
+extern pid_t exec0(const char *path, char *const argv[],
+ char *const envp[], const char *dirpath,
+ int channels[3]);
+
+
+extern pid_t exec_pty(const char *path, char *const argv[],
+ char *const envp[], const char *dirpath,
+ int channels[3], const char *pts_name, int fdm,
+ int console);
+
+extern int wait0(pid_t pid);
diff --git a/core/org.eclipse.cdt.core.native/native_src/unix/exec_pty.c b/core/org.eclipse.cdt.core.native/native_src/unix/exec_pty.c
new file mode 100644
index 00000000000..e020053db41
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/unix/exec_pty.c
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2010 QNX Software Systems and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ * Wind River Systems, Inc.
+ * Mikhail Zabaluev (Nokia) - bug 82744
+ * Mikhail Sennikovsky - bug 145737
+ *******************************************************************************/
+#include "exec0.h"
+#include "openpty.h"
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <termios.h>
+
+/* from pfind.c */
+extern char *pfind(const char *name, char * const envp[]);
+
+pid_t
+exec_pty(const char *path, char *const argv[], char *const envp[],
+ const char *dirpath, int channels[3], const char *pts_name, int fdm, int console)
+{
+ int pipe2[2];
+ pid_t childpid;
+ char *full_path;
+
+ /*
+ * We use pfind() to check that the program exists and is an executable.
+ * If not pass the error up. Also execve() wants a full path.
+ */
+ full_path = pfind(path, envp);
+ if (full_path == NULL) {
+ fprintf(stderr, "Unable to find full path for \"%s\"\n", (path) ? path : "");
+ return -1;
+ }
+
+ /*
+ * Make sure we can create our pipes before forking.
+ */
+ if (channels != NULL && console) {
+ if (pipe(pipe2) < 0) {
+ fprintf(stderr, "%s(%d): returning due to error: %s\n", __FUNCTION__, __LINE__, strerror(errno));
+ free(full_path);
+ return -1;
+ }
+ }
+
+ childpid = fork();
+
+ if (childpid < 0) {
+ fprintf(stderr, "%s(%d): returning due to error: %s\n", __FUNCTION__, __LINE__, strerror(errno));
+ free(full_path);
+ return -1;
+ } else if (childpid == 0) { /* child */
+
+ chdir(dirpath);
+
+ if (channels != NULL) {
+ int fds;
+
+ if (!console && setsid() < 0) {
+ perror("setsid()");
+ return -1;
+ }
+
+ fds = ptys_open(fdm, pts_name);
+ if (fds < 0) {
+ fprintf(stderr, "%s(%d): returning due to error: %s\n", __FUNCTION__, __LINE__, strerror(errno));
+ return -1;
+ }
+
+ /* Close the read end of pipe2 */
+ if (console && close(pipe2[0]) == -1) {
+ perror("close(pipe2[0]))");
+ }
+
+ /* close the master, no need in the child */
+ close(fdm);
+
+ if (console) {
+ set_noecho(fds);
+ if (setpgid(getpid(), getpid()) < 0) {
+ perror("setpgid()");
+ return -1;
+ }
+ }
+
+ /* redirections */
+ dup2(fds, STDIN_FILENO); /* dup stdin */
+ dup2(fds, STDOUT_FILENO); /* dup stdout */
+ if (console) {
+ dup2(pipe2[1], STDERR_FILENO); /* dup stderr */
+ } else {
+ dup2(fds, STDERR_FILENO); /* dup stderr */
+ }
+ close(fds); /* done with fds. */
+ }
+
+ /* Close all the fd's in the child */
+ {
+ int fdlimit = sysconf(_SC_OPEN_MAX);
+ int fd = 3;
+
+ while (fd < fdlimit)
+ close(fd++);
+ }
+
+ if (envp[0] == NULL) {
+ execv(full_path, argv);
+ } else {
+ execve(full_path, argv, envp);
+ }
+
+ _exit(127);
+
+ } else if (childpid != 0) { /* parent */
+ if (console) {
+ set_noecho(fdm);
+ }
+ if (channels != NULL) {
+ channels[0] = fdm; /* Input Stream. */
+ channels[1] = fdm; /* Output Stream. */
+ if (console) {
+ /* close the write end of pipe1 */
+ if (close(pipe2[1]) == -1)
+ perror("close(pipe2[1])");
+ channels[2] = pipe2[0]; /* stderr Stream. */
+ } else {
+ channels[2] = fdm; /* Error Stream. */
+ }
+ }
+
+ free(full_path);
+ return childpid;
+ }
+
+ free(full_path);
+ return -1; /*NOT REACHED */
+}
+#ifdef __STAND_ALONE__
+int main(int argc, char **argv, char **envp) {
+ const char *path = "./bufferring_test";
+ int channels[3] = { -1, -1, -1};
+ int status;
+ FILE *app_stdin;
+ FILE *app_stdout;
+ FILE *app_stderr;
+ char pts_name[32];
+ int fdm;
+ char buffer[32];
+
+ fdm = ptym_open(pts_name);
+ status = exec_pty(path, argv, envp, ".", channels, pts_name, fdm);
+ if (status >= 0) {
+ app_stdin = fdopen(channels[0], "w");
+ app_stdout = fdopen(channels[1], "r");
+ app_stderr = fdopen(channels[2], "r");
+ if (app_stdout == NULL || app_stderr == NULL || app_stdin == NULL) {
+ fprintf(stderr, "PROBLEMS\n");
+ } else {
+ fputs("foo\n", app_stdin);
+ fputs("bar\n", app_stdin);
+ while(fgets(buffer, sizeof buffer, app_stdout) != NULL) {
+ fprintf(stdout, "STDOUT: %s\n", buffer);
+ }
+ while(fgets(buffer, sizeof buffer, app_stderr) != NULL) {
+ fprintf(stdout, "STDERR: %s\n", buffer);
+ }
+ }
+ }
+ fputs("bye\n", stdout);
+ close(channels[0]);
+ close(channels[1]);
+ close(channels[2]);
+ return 0;
+}
+#endif
diff --git a/core/org.eclipse.cdt.core.native/native_src/unix/exec_unix.c b/core/org.eclipse.cdt.core.native/native_src/unix/exec_unix.c
new file mode 100644
index 00000000000..4feb805f15d
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/unix/exec_unix.c
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2010 QNX Software Systems and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ * Wind River Systems, Inc.
+ * Mikhail Sennikovsky - bug 145737
+ *******************************************************************************/
+#include "exec0.h"
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <libgen.h>
+#include <stdlib.h>
+
+/* from pfind.c */
+extern char *pfind(const char *name, char * const envp[]);
+
+pid_t
+exec0(const char *path, char *const argv[], char *const envp[],
+ const char *dirpath, int channels[3])
+{
+ int pipe0[2], pipe1[2], pipe2[2];
+ pid_t childpid;
+ char *full_path;
+
+ /*
+ * We use pfind() to check that the program exists and is an executable.
+ * If not pass the error up. Also execve() wants a full path.
+ */
+ full_path = pfind(path, envp);
+ if (full_path == NULL) {
+ fprintf(stderr, "Unable to find full path for \"%s\"\n", (path) ? path : "");
+ return -1;
+ }
+
+ /*
+ * Make sure we can create our pipes before forking.
+ */
+ if (channels != NULL) {
+ if (pipe(pipe0) < 0 || pipe(pipe1) < 0 || pipe(pipe2) < 0) {
+ fprintf(stderr, "%s(%d): returning due to error.\n",
+ __FUNCTION__, __LINE__);
+ free(full_path);
+ return -1;
+ }
+ }
+
+ childpid = fork();
+
+ if (childpid < 0) {
+ fprintf(stderr, "%s(%d): returning due to error: %s\n",
+ __FUNCTION__, __LINE__, strerror(errno));
+ free(full_path);
+ return -1;
+ } else if (childpid == 0) { /* child */
+ char *ptr;
+
+ chdir(dirpath);
+
+ if (channels != NULL) {
+ /* Close the write end of pipe0 */
+ if (close(pipe0[1]) == -1)
+ perror("close(pipe0[1])");
+
+ /* Close the read end of pipe1 */
+ if (close(pipe1[0]) == -1)
+ perror("close(pipe1[0])");
+
+ /* Close the read end of pipe2 */
+ if (close(pipe2[0]) == -1)
+ perror("close(pipe2[0]))");
+
+ /* redirections */
+ dup2(pipe0[0], STDIN_FILENO); /* dup stdin */
+ dup2(pipe1[1], STDOUT_FILENO); /* dup stdout */
+ dup2(pipe2[1], STDERR_FILENO); /* dup stderr */
+ }
+
+ /* Close all the fd's in the child */
+ {
+ int fdlimit = sysconf(_SC_OPEN_MAX);
+ int fd = 3;
+
+ while (fd < fdlimit)
+ close(fd++);
+ }
+
+ setpgid(getpid(), getpid());
+
+ if (envp[0] == NULL) {
+ execv(full_path, argv);
+ } else {
+ execve(full_path, argv, envp);
+ }
+
+ _exit(127);
+
+ } else if (childpid != 0) { /* parent */
+
+ char b;
+
+ if (channels != NULL) {
+ /* close the read end of pipe1 */
+ if (close(pipe0[0]) == -1)
+ perror("close(pipe0[0])");
+
+ /* close the write end of pipe2 */
+ if (close(pipe1[1]) == -1)
+ perror("close(pipe1[1])");
+
+ /* close the write end of pipe2 */
+ if (close(pipe2[1]) == -1)
+ perror("close(pipe2[1])");
+
+ channels[0] = pipe0[1]; /* Output Stream. */
+ channels[1] = pipe1[0]; /* Input Stream. */
+ channels[2] = pipe2[0]; /* Input Stream. */
+ }
+
+ free(full_path);
+ return childpid;
+ }
+
+ free(full_path);
+ return -1; /*NOT REACHED */
+}
+
+
+int wait0(pid_t pid)
+{
+ int status;
+ int val = -1;
+
+ if (pid < 0)
+ return -1;
+
+ for (;;) {
+ if (waitpid(pid, &status, 0) < 0) {
+ if (errno == EINTR) {
+ // interrupted system call - retry
+ continue;
+ }
+ }
+ break;
+ }
+ if (WIFEXITED(status)) {
+ val = WEXITSTATUS(status);
+ }
+
+ return val;
+}
diff --git a/core/org.eclipse.cdt.core.native/native_src/unix/io.c b/core/org.eclipse.cdt.core.native/native_src/unix/io.c
new file mode 100644
index 00000000000..94f03d63935
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/unix/io.c
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2006 QNX Software Systems and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ * Wind River Systems, Inc.
+ *******************************************************************************/
+#include <jni.h>
+#include <stdio.h>
+#include <SpawnerInputStream.h>
+#include <SpawnerOutputStream.h>
+#include <unistd.h>
+
+/* Header for class _org_eclipse_cdt_utils_spawner_SpawnerInputStream */
+/* Header for class _org_eclipse_cdt_utils_spawner_SpawnerOutputStream */
+
+/*
+ * Class: org_eclipse_cdt_utils_spawner_SpawnerInputStream
+ * Method: read0
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_read0(JNIEnv * env,
+ jobject jobj,
+ jint jfd,
+ jbyteArray buf,
+ jint buf_len)
+{
+ int fd;
+ int status;
+ jbyte *data;
+ int data_len;
+
+ data = (*env)->GetByteArrayElements(env, buf, 0);
+ data_len = buf_len;
+ fd = jfd;
+
+ status = read( fd, data, data_len );
+ (*env)->ReleaseByteArrayElements(env, buf, data, 0);
+
+ if (status == 0) {
+ /* EOF. */
+ status = -1;
+ } else if (status == -1) {
+ /* Error, toss an exception */
+ jclass exception = (*env)->FindClass(env, "java/io/IOException");
+ if (exception == NULL) {
+ /* Give up. */
+ return -1;
+ }
+ (*env)->ThrowNew(env, exception, "read error");
+ }
+
+ return status;
+}
+
+
+/*
+ * Class: org_eclipse_cdt_utils_spawner_SpawnerInputStream
+ * Method: close0
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_close0(JNIEnv * env,
+ jobject jobj,
+ jint fd)
+{
+ return close(fd);
+}
+
+/*
+ * Class: org_eclipse_cdt_utils_spawner_SpawnerOutputStream
+ * Method: write0
+ * Signature: (II)I
+ */
+JNIEXPORT jint JNICALL
+Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_write0(JNIEnv * env,
+ jobject jobj,
+ jint jfd,
+ jbyteArray buf,
+ jint buf_len)
+{
+ int status;
+ int fd;
+ jbyte *data;
+ int data_len;
+
+ data = (*env)->GetByteArrayElements(env, buf, 0);
+ data_len = buf_len;
+ fd = jfd;
+
+ status = write(fd, data, data_len);
+ (*env)->ReleaseByteArrayElements(env, buf, data, 0);
+
+ return status;
+}
+
+
+/*
+ * Class: org_eclipse_cdt_utils_spawner_SpawnerOutputStream
+ * Method: close0
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_close0(JNIEnv * env,
+ jobject jobj,
+ jint fd)
+{
+ return close(fd);
+}
diff --git a/core/org.eclipse.cdt.core.native/native_src/unix/openpty.c b/core/org.eclipse.cdt.core.native/native_src/unix/openpty.c
new file mode 100644
index 00000000000..2ca02e2278c
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/unix/openpty.c
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2010 QNX Software Systems and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ * Wind River Systems, Inc.
+ * Mikhail Zabaluev (Nokia) - bug 82744
+ * Corey Ashford (IBM) - bug 272370, bug 272372
+ *******************************************************************************/
+
+/* _XOPEN_SOURCE is needed to bring in the header for ptsname */
+#define _XOPEN_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <grp.h>
+
+#include <stdlib.h>
+
+/**
+ * This is taken from R. W. Stevens book.
+ * Alain Magloire.
+ */
+
+int ptym_open (char *pts_name);
+int ptys_open (int fdm, const char * pts_name);
+void set_noecho(int fd);
+
+int
+openpty(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize *winp)
+{
+ char line[20];
+ line[0]=0;
+ *amaster = ptym_open(line);
+ if (*amaster < 0)
+ return -1;
+ *aslave = ptys_open(*amaster, line);
+ if (*aslave < 0) {
+ close(*amaster);
+ return -1;
+ }
+
+ if (name)
+ strcpy(name, line);
+#ifndef TCSAFLUSH
+#define TCSAFLUSH TCSETAF
+#endif
+ if (termp)
+ (void) tcsetattr(*aslave, TCSAFLUSH, termp);
+#ifdef TIOCSWINSZ
+ if (winp)
+ (void) ioctl(*aslave, TIOCSWINSZ, (char *)winp);
+#endif
+ return 0;
+}
+
+void
+set_noecho(int fd)
+{
+ struct termios stermios;
+ if (tcgetattr(fd, &stermios) < 0) {
+ return ;
+ }
+
+ /* turn off echo */
+ stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
+ /* Turn off the NL to CR/NL mapping ou output. */
+ /*stermios.c_oflag &= ~(ONLCR);*/
+
+ stermios.c_iflag |= (IGNCR);
+
+ tcsetattr(fd, TCSANOW, &stermios);
+}
+
+int
+ptym_open(char * pts_name)
+{
+ int fdm;
+ char *ptr;
+
+ strcpy(pts_name, "/dev/ptmx");
+#ifdef __APPLE__
+ fdm = posix_openpt(O_RDWR|O_NOCTTY);
+#else
+ fdm = getpt();
+#endif
+ if (fdm < 0)
+ return -1;
+ if (grantpt(fdm) < 0) { /* grant access to slave */
+ close(fdm);
+ return -2;
+ }
+ if (unlockpt(fdm) < 0) { /* clear slave's lock flag */
+ close(fdm);
+ return -3;
+ }
+ ptr = ptsname(fdm);
+ if (ptr == NULL) { /* get slave's name */
+ close (fdm);
+ return -4;
+ }
+ strcpy(pts_name, ptr); /* return name of slave */
+ return fdm; /* return fd of master */
+}
+
+int
+ptys_open(int fdm, const char * pts_name)
+{
+ int fds;
+ /* following should allocate controlling terminal */
+ fds = open(pts_name, O_RDWR);
+ if (fds < 0) {
+ close(fdm);
+ return -5;
+ }
+
+#if defined(TIOCSCTTY)
+ /* TIOCSCTTY is the BSD way to acquire a controlling terminal. */
+ if (ioctl(fds, TIOCSCTTY, (char *)0) < 0) {
+ // ignore error: this is expected in console-mode
+ }
+#endif
+ return fds;
+}
diff --git a/core/org.eclipse.cdt.core.native/native_src/unix/openpty.h b/core/org.eclipse.cdt.core.native/native_src/unix/openpty.h
new file mode 100644
index 00000000000..234a306415d
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/unix/openpty.h
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2010 QNX Software Systems and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ * Wind River Systems, Inc.
+ * Mikhail Zabaluev (Nokia) - bug 82744
+ *******************************************************************************/
+#ifndef _OPENPTY_H
+#define _OPENPTY_H
+int ptym_open (char *pts_name);
+int ptys_open (int fdm, const char * pts_name);
+void set_noecho(int fd);
+#endif
diff --git a/core/org.eclipse.cdt.core.native/native_src/unix/pfind.c b/core/org.eclipse.cdt.core.native/native_src/unix/pfind.c
new file mode 100644
index 00000000000..dd7abddf2f6
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/unix/pfind.c
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2010 QNX Software Systems and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ * Wind River Systems, Inc.
+ * Mikhail Sennikovsky - bug 145737
+ * Everton Rufino Constantino (IBM) - bug 237611
+ *******************************************************************************/
+/*
+ * pfind.c - Search for a binary in $PATH.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+#define PATH_DEF "PATH="
+const int path_def_len = 5; /* strlen(PATH_DEF); */
+
+char * path_val(char * const envp[])
+{
+ int i;
+ if (envp == NULL || envp[0] == NULL)
+ return getenv("PATH" );
+
+ for(i = 0; envp[i] != NULL; i++){
+ char* p = envp[i];
+ if(!strncmp(PATH_DEF, p, path_def_len)){
+ return p + path_def_len;
+ }
+ }
+
+ return NULL;
+}
+
+char * pfind(const char *name, char * const envp[])
+{
+ char *tok;
+ char *sp;
+ char *path;
+ char fullpath[PATH_MAX+1];
+
+ /* Sanity check. */
+ if (name == NULL) {
+ fprintf(stderr, "pfind(): Null argument.\n");
+ return NULL;
+ }
+
+ /* For absolute name or name with a path, check if it is an executable. */
+ if (name[0] == '/' || name[0] == '.') {
+ if (access(name, X_OK) == 0) {
+ return strdup(name);
+ }
+ return NULL;
+ }
+
+ /* Search in the PATH environment. */
+ path = path_val( envp );
+
+ if (path == NULL || strlen(path) <= 0) {
+ fprintf(stderr, "Unable to get $PATH.\n");
+ return NULL;
+ }
+
+ /* The value return by getenv() is readonly */
+ path = strdup(path);
+
+ tok = strtok_r(path, ":", &sp);
+ while (tok != NULL) {
+ snprintf(fullpath, sizeof(fullpath) - 1, "%s/%s", tok, name);
+
+ if (access(fullpath, X_OK) == 0) {
+ free(path);
+ return strdup(fullpath);
+ }
+
+ tok = strtok_r( NULL, ":", &sp );
+ }
+
+ free(path);
+ return NULL;
+}
+
+#ifdef BUILD_WITH_MAIN
+int main(int argc, char **argv)
+{
+ int i;
+ char *fullpath;
+
+ for (i=1; i<argc; i++) {
+ fullpath = pfind(argv[i], NULL);
+ if (fullpath == NULL)
+ printf("Unable to find %s in $PATH.\n", argv[i]);
+ else
+ printf("Found %s @ %s.\n", argv[i], fullpath);
+ }
+}
+#endif
diff --git a/core/org.eclipse.cdt.core.native/native_src/unix/pty.c b/core/org.eclipse.cdt.core.native/native_src/unix/pty.c
new file mode 100644
index 00000000000..edb87661eb5
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/unix/pty.c
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2010 QNX Software Systems and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ * Wind River Systems, Inc.
+ *******************************************************************************/
+#include <sys/ioctl.h>
+#include "PTY.h"
+#include "openpty.h"
+
+/*
+ * Class: org_eclipse_cdt_utils_pty_PTY
+ * Method: forkpty
+ * Signature: ()I
+ */
+JNIEXPORT jstring JNICALL
+Java_org_eclipse_cdt_utils_pty_PTY_openMaster (JNIEnv *env, jobject jobj, jboolean console) {
+ jfieldID fid; /* Store the field ID */
+ jstring jstr = NULL;
+ int master = -1;
+ char line[1024]; /* FIXME: Should be enough */
+ jclass cls;
+
+ line[0] = '\0';
+
+ master = ptym_open(line);
+ if (master >= 0) {
+ // turn off echo
+ if (console) {
+ set_noecho(master);
+ }
+
+ /* Get a reference to the obj's class */
+ cls = (*env)->GetObjectClass(env, jobj);
+
+ /* Set the master fd. */
+ fid = (*env)->GetFieldID(env, cls, "master", "I");
+ if (fid == NULL) {
+ return NULL;
+ }
+ (*env)->SetIntField(env, jobj, fid, (jint)master);
+
+ /* Create a new String for the slave. */
+ jstr = (*env)->NewStringUTF(env, line);
+ }
+ return jstr;
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_pty_PTY_change_1window_1size
+ (JNIEnv *env, jobject jobj, jint fdm, jint width, jint height)
+{
+#ifdef TIOCSWINSZ
+ struct winsize win;
+
+ win.ws_col = width;
+ win.ws_row = height;
+ win.ws_xpixel = 0;
+ win.ws_ypixel = 0;
+
+ return ioctl(fdm, TIOCSWINSZ, &win);
+#else
+#error no TIOCSWINSZ
+ return 0;
+#endif
+}
+
diff --git a/core/org.eclipse.cdt.core.native/native_src/unix/ptyio.c b/core/org.eclipse.cdt.core.native/native_src/unix/ptyio.c
new file mode 100644
index 00000000000..e022db11f99
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/unix/ptyio.c
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2002 - 2005 QNX Software Systems and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+#include <jni.h>
+#include <stdio.h>
+#include <PTYInputStream.h>
+#include <PTYOutputStream.h>
+#include <unistd.h>
+
+/* Header for class _org_eclipse_cdt_utils_pty_PTYInputStream */
+/* Header for class _org_eclipse_cdt_utils_pty_PTYOutputStream */
+
+/*
+ * Class: org_eclipse_cdt_utils_pty_PTYInputStream
+ * Method: read0
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_org_eclipse_cdt_utils_pty_PTYInputStream_read0(JNIEnv * env,
+ jobject jobj,
+ jint jfd,
+ jbyteArray buf,
+ jint buf_len)
+{
+ int fd;
+ int status;
+ jbyte *data;
+ int data_len;
+
+ data = (*env)->GetByteArrayElements(env, buf, 0);
+ data_len = buf_len;
+ fd = jfd;
+
+ status = read( fd, data, data_len );
+ (*env)->ReleaseByteArrayElements(env, buf, data, 0);
+
+ if (status == 0) {
+ /* EOF. */
+ status = -1;
+ } else if (status == -1) {
+ /* Error, toss an exception */
+ /* Ignore the error for now, the debugger will attempt
+ * to close this multiple time. */
+#if 0
+ jclass exception = (*env)->FindClass(env, "java/io/IOException");
+ if (exception == NULL) {
+ /* Give up. */
+ return -1;
+ }
+ (*env)->ThrowNew(env, exception, "read error");
+#endif
+ }
+
+ return status;
+}
+
+
+/*
+ * Class: org_eclipse_cdt_utils_pty_PTYInputStream
+ * Method: close0
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_org_eclipse_cdt_utils_pty_PTYInputStream_close0(JNIEnv * env,
+ jobject jobj,
+ jint fd)
+{
+ return close(fd);
+}
+
+/*
+ * Class: org_eclipse_cdt_utils_pty_PTYOutputStream
+ * Method: write0
+ * Signature: (II)I
+ */
+JNIEXPORT jint JNICALL
+Java_org_eclipse_cdt_utils_pty_PTYOutputStream_write0(JNIEnv * env,
+ jobject jobj,
+ jint jfd,
+ jbyteArray buf,
+ jint buf_len)
+{
+ int status;
+ int fd;
+ jbyte *data;
+ int data_len;
+
+ data = (*env)->GetByteArrayElements(env, buf, 0);
+ data_len = buf_len;
+ fd = jfd;
+
+ status = write(fd, data, data_len);
+ (*env)->ReleaseByteArrayElements(env, buf, data, 0);
+
+ return status;
+}
+
+
+/*
+ * Class: org_eclipse_cdt_utils_pty_PTYOutputStream
+ * Method: close0
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_org_eclipse_cdt_utils_pty_PTYOutputStream_close0(JNIEnv * env,
+ jobject jobj,
+ jint fd)
+{
+ return close(fd);
+}
diff --git a/core/org.eclipse.cdt.core.native/native_src/unix/spawner.c b/core/org.eclipse.cdt.core.native/native_src/unix/spawner.c
new file mode 100644
index 00000000000..623b1382cf8
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/unix/spawner.c
@@ -0,0 +1,305 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2010 QNX Software Systems and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ * Wind River Systems, Inc.
+ * Mikhail Zabaluev (Nokia) - bug 82744
+ *******************************************************************************/
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#include <jni.h>
+
+#include "exec0.h"
+#include <Spawner.h>
+
+
+#define DEBUGIT 0
+
+
+/*
+ * Header for class org_eclipse_cdt_utils_spawner_Spawner
+ */
+
+
+#if DEBUGIT
+static void print_array(char **c_array)
+{
+ if (c_array) {
+ char **p = c_array;
+ for (; *p; p++) {
+ if (*p) {
+ fprintf(stderr, " %s", *p);
+ }
+ }
+ } else {
+ fprintf(stderr, "null");
+ }
+ fprintf(stderr, "\n");
+}
+#endif
+
+
+static char **alloc_c_array(JNIEnv * env, jobjectArray j_array)
+{
+ int i;
+ jint c_array_size = (*env)->GetArrayLength(env, j_array);
+ char **c_array = calloc(c_array_size + 1, sizeof(*c_array));
+
+ if (c_array == NULL)
+ return NULL;
+
+ for (i = 0; i < c_array_size; i++) {
+ jstring j_str =
+ (jstring) (*env)->GetObjectArrayElement(env, j_array, i);
+ const char *c_str = (*env)->GetStringUTFChars(env, j_str, NULL);
+ c_array[i] = (char *) strdup(c_str);
+ (*env)->ReleaseStringUTFChars(env, j_str, c_str);
+ (*env)->DeleteLocalRef(env, j_str);
+ }
+
+ return c_array;
+}
+
+
+static void free_c_array(char **c_array)
+{
+ if (c_array) {
+ char **p = c_array;
+ for (; *p; p++) {
+ if (*p) {
+ free(*p);
+ }
+ }
+ free(c_array);
+ }
+}
+
+
+/*
+ * Class: org_eclipse_cdt_utils_spawner_Spawner
+ * Method: exec2
+ * Signature: ([Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[ILorg/eclipse/cdt/utils/pty/PTY;)I
+ */
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec2
+ (JNIEnv *env, jobject jobj, jobjectArray jcmd, jobjectArray jenv, jstring jdir, jintArray jchannels,
+ jstring jslaveName, jint masterFD, jboolean console)
+{
+ jint *channels = (*env)->GetIntArrayElements(env, jchannels, 0);
+ const char *dirpath = (*env)->GetStringUTFChars(env, jdir, NULL);
+ const char *pts_name = (*env)->GetStringUTFChars(env, jslaveName, NULL);
+ char **cmd = NULL;
+ char **envp = NULL;
+ int fd[3];
+ pid_t pid = -1;
+
+ if (channels == NULL)
+ goto bail_out;
+
+ cmd = alloc_c_array(env, jcmd);
+ if (cmd == NULL)
+ goto bail_out;
+
+ envp = alloc_c_array(env, jenv);
+ if (envp == NULL)
+ goto bail_out;
+
+#if DEBUGIT
+ fprintf(stderr, "command:");
+ print_array(cmd);
+ fprintf(stderr, "Envp:");
+ print_array(envp);
+ fprintf(stderr, "dirpath: %s\n", dirpath);
+ fprintf(stderr, "pts_name: %s\n", pts_name);
+#endif
+
+ pid = exec_pty(cmd[0], cmd, envp, dirpath, fd, pts_name, masterFD, console);
+ if (pid < 0)
+ goto bail_out;
+
+ channels[0] = fd[0];
+ channels[1] = fd[1];
+ channels[2] = fd[2];
+
+ bail_out:
+ (*env)->ReleaseIntArrayElements(env, jchannels, channels, 0);
+ (*env)->ReleaseStringUTFChars(env, jdir, dirpath);
+ (*env)->ReleaseStringUTFChars(env, jslaveName, pts_name);
+ if (cmd)
+ free_c_array(cmd);
+ if (envp)
+ free_c_array(envp);
+ return pid;
+}
+
+
+JNIEXPORT jint JNICALL
+Java_org_eclipse_cdt_utils_spawner_Spawner_exec1(JNIEnv * env, jobject jobj,
+ jobjectArray jcmd,
+ jobjectArray jenv,
+ jstring jdir)
+{
+ const char *dirpath = (*env)->GetStringUTFChars(env, jdir, NULL);
+ char **cmd = NULL;
+ char **envp = NULL;
+ pid_t pid = -1;
+
+ cmd = alloc_c_array(env, jcmd);
+ if (cmd == NULL)
+ goto bail_out;
+
+ envp = alloc_c_array(env, jenv);
+ if (envp == NULL)
+ goto bail_out;
+
+#if DEBUGIT
+ fprintf(stderr, "command:");
+ print_array(cmd);
+ fprintf(stderr, "Envp:");
+ print_array(envp);
+ fprintf(stderr, "dirpath: %s\n", dirpath);
+#endif
+
+ pid = exec0(cmd[0], cmd, envp, dirpath, NULL);
+ if (pid < 0)
+ goto bail_out;
+
+ bail_out:
+ (*env)->ReleaseStringUTFChars(env, jdir, dirpath);
+ if (cmd)
+ free_c_array(cmd);
+ if (envp)
+ free_c_array(envp);
+ return pid;
+}
+
+/*
+ * Class: org_eclipse_cdt_utils_spawner_Spawner
+ * Method: exec0
+ * Signature: ([Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[I)I
+ */
+JNIEXPORT jint JNICALL
+Java_org_eclipse_cdt_utils_spawner_Spawner_exec0(JNIEnv * env, jobject jobj,
+ jobjectArray jcmd,
+ jobjectArray jenv,
+ jstring jdir,
+ jintArray jchannels)
+{
+ jint *channels = (*env)->GetIntArrayElements(env, jchannels, 0);
+ const char *dirpath = (*env)->GetStringUTFChars(env, jdir, NULL);
+ char **cmd = NULL;
+ char **envp = NULL;
+ int fd[3];
+ pid_t pid = -1;
+
+ if (channels == NULL)
+ goto bail_out;
+
+ cmd = alloc_c_array(env, jcmd);
+ if (cmd == NULL)
+ goto bail_out;
+
+ envp = alloc_c_array(env, jenv);
+ if (envp == NULL)
+ goto bail_out;
+
+#if DEBUGIT
+ fprintf(stderr, "command:");
+ print_array(cmd);
+ fprintf(stderr, "Envp:");
+ print_array(envp);
+ fprintf(stderr, "dirpath: %s\n", dirpath);
+#endif
+
+ pid = exec0(cmd[0], cmd, envp, dirpath, fd);
+ if (pid < 0)
+ goto bail_out;
+
+ channels[0] = fd[0];
+ channels[1] = fd[1];
+ channels[2] = fd[2];
+
+ bail_out:
+ (*env)->ReleaseIntArrayElements(env, jchannels, channels, 0);
+ (*env)->ReleaseStringUTFChars(env, jdir, dirpath);
+ if (cmd)
+ free_c_array(cmd);
+ if (envp)
+ free_c_array(envp);
+ return pid;
+}
+
+/*
+ * Class: org_eclipse_cdt_utils_spawner_Spawner
+ * Method: raise
+ * Signature: (II)I
+ */
+JNIEXPORT jint JNICALL
+Java_org_eclipse_cdt_utils_spawner_Spawner_raise(JNIEnv * env, jobject jobj,
+ jint pid, jint sig)
+{
+ int status = -1;
+
+ switch (sig) {
+ case 0: /* NOOP */
+ status = killpg(pid, 0);
+ if(status == -1) {
+ status = kill(pid, 0);
+ }
+ break;
+
+ case 2: /* INTERRUPT */
+ status = killpg(pid, SIGINT);
+ if(status == -1) {
+ status = kill(pid, SIGINT);
+ }
+ break;
+
+ case 9: /* KILL */
+ status = killpg(pid, SIGKILL);
+ if(status == -1) {
+ status = kill(pid, SIGKILL);
+ }
+ break;
+
+ case 15: /* TERM */
+ status = killpg(pid, SIGTERM);
+ if(status == -1) {
+ status = kill(pid, SIGTERM);
+ }
+ break;
+
+ default:
+ status = killpg(pid, sig); /* WHAT ?? */
+ if(status == -1) {
+ status = kill(pid, sig); /* WHAT ?? */
+ }
+ break;
+ }
+
+ return status;
+}
+
+
+
+/*
+ * Class: org_eclipse_cdt_utils_spawner_Spawner
+ * Method: waitFor
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_org_eclipse_cdt_utils_spawner_Spawner_waitFor(JNIEnv * env,
+ jobject jobj, jint pid)
+{
+ return wait0(pid);
+}
diff --git a/core/org.eclipse.cdt.core.native/native_src/win/Win32ProcessEx.c b/core/org.eclipse.cdt.core.native/native_src/win/Win32ProcessEx.c
new file mode 100644
index 00000000000..7b6bcc13699
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/win/Win32ProcessEx.c
@@ -0,0 +1,1018 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2015 QNX Software Systems and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ * Wind River Systems, Inc.
+ *
+ * Win32ProcessEx.c
+ *
+ * This is a JNI implementation of spawner
+ *******************************************************************************/
+
+#include <string.h>
+#include <stdlib.h>
+#include <process.h>
+#include <tchar.h>
+#include <windows.h>
+#include <jni.h>
+
+#include "Spawner.h"
+
+#define PIPE_SIZE 512 // Size of pipe buffer
+#define MAX_CMD_SIZE 2049 // Initial size of command line
+#define MAX_ENV_SIZE 4096 // Initial size of environment block
+#define PIPE_NAME_LENGTH 100 // Size of pipe name buffer
+#define PIPE_TIMEOUT 10000 // Default time-out value, in milliseconds.
+
+#define MAX_PROCS (100) // Maximum number of simultaneously running processes
+
+
+// Process description block. Should be created for each launched process
+typedef struct _procInfo {
+ int pid; // Process ID
+ int uid; // quasi-unique process ID; we have to create it to avoid duplicated pid
+ // (actually this impossible from OS point of view but it is still possible
+ // a clash of new created and already finished process with one and the same PID.
+ // 4 events connected to this process (see starter)
+ HANDLE eventBreak; // signaled when Spawner.interrupt() is called; mildest of the terminate requests (SIGINT signal in UNIX world)
+ HANDLE eventWait;
+ HANDLE eventTerminate; // signaled when Spawner.terminate() is called; more forceful terminate request (SIGTERM signal in UNIX world)
+ HANDLE eventKill; // signaled when Spawner.kill() is called; most forceful terminate request (SIGKILL signal in UNIX world)
+ HANDLE eventCtrlc; // signaled when Spawner.interruptCTRLC() is called; like interrupt() but sends CTRL-C in all cases, even when inferior is a Cygwin program
+} procInfo_t, * pProcInfo_t;
+
+static int procCounter = 0; // Number of running processes
+
+
+// This is a VM helper
+void ThrowByName(JNIEnv *env, const char *name, const char *msg);
+
+// Creates _procInfo block for every launched process
+pProcInfo_t createProcInfo();
+
+// Find process description for this pid
+pProcInfo_t findProcInfo(int pid);
+
+// We launch separate thread for each project to trap it termination
+void _cdecl waitProcTermination(void* pv) ;
+
+// This is a helper function to prevent losing of quotation marks
+static int copyTo(wchar_t * target, const wchar_t * source, int cpyLenght, int availSpace);
+
+// Use this function to clean project descriptor and return it to the pool of available blocks.
+static void cleanUpProcBlock(pProcInfo_t pCurProcInfo);
+
+
+// Signal codes
+typedef enum {
+ SIG_NOOP,
+ SIG_HUP,
+ SIG_INT,
+ SIG_KILL = 9,
+ SIG_TERM = 15,
+ CTRLC = 1000 // special, Windows only. Sends CTRL-C in all cases, even when inferior is a Cygwin program
+} signals;
+
+extern CRITICAL_SECTION cs;
+
+
+extern wchar_t path[MAX_PATH]; // Directory where spawner.dll is located
+
+static HMODULE hVM = NULL; // VM handler
+
+
+static pProcInfo_t pInfo = NULL;
+
+static int nCounter = 0; // We use it to build unique synchronization object names
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Launcher; launchess process and traps its termination
+// Arguments: (see Spawner.java)
+// [in] cmdarray - array of command line elements
+// [in] envp - array of environment variables
+// [in] dir - working directory
+// [out] channels - streams handlers
+/////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+extern "C"
+#endif
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec2
+ (JNIEnv * env, jobject process, jobjectArray cmdarray, jobjectArray envp, jstring dir, jintArray channels, jstring slaveName, jint fdm, jboolean console)
+{
+ return -1;
+}
+
+void ensureSize(wchar_t** ptr, int* psize, int requiredLength)
+{
+ int size= *psize;
+ if (requiredLength > size) {
+ size= 2*size;
+ if (size < requiredLength) {
+ size= requiredLength;
+ }
+ *ptr= (wchar_t *)realloc(*ptr, size * sizeof(wchar_t));
+ if (NULL == *ptr) {
+ *psize= 0;
+ }
+ else {
+ *psize= size;
+ }
+ }
+}
+
+#ifdef __cplusplus
+extern "C"
+#endif
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
+ (JNIEnv * env, jobject process, jobjectArray cmdarray, jobjectArray envp, jstring dir, jintArray channels)
+{
+ HANDLE stdHandles[3];
+ PROCESS_INFORMATION pi = {0}, *piCopy;
+ STARTUPINFOW si;
+ DWORD flags = 0;
+ const wchar_t * cwd = NULL;
+ LPVOID envBlk = NULL;
+ int ret = 0;
+ int nCmdLineLength= 0;
+ wchar_t * szCmdLine= 0;
+ int nBlkSize = MAX_ENV_SIZE;
+ wchar_t * szEnvBlock = NULL;
+ jsize nCmdTokens = 0;
+ jsize nEnvVars = 0;
+ int i;
+ DWORD pid = GetCurrentProcessId();
+ int nPos;
+ pProcInfo_t pCurProcInfo;
+
+ // This needs to be big enough to contain the name of the event used when calling CreateEventW bellow.
+ // It is made of a prefix (7 characters max) plus the value of a pointer that gets output in characters.
+ // This will be bigger in the case of 64 bit.
+ static const int MAX_EVENT_NAME_LENGTH = 50;
+ wchar_t eventBreakName[MAX_EVENT_NAME_LENGTH];
+ wchar_t eventWaitName[MAX_EVENT_NAME_LENGTH];
+ wchar_t eventTerminateName[MAX_EVENT_NAME_LENGTH];
+ wchar_t eventKillName[MAX_EVENT_NAME_LENGTH];
+ wchar_t eventCtrlcName[MAX_EVENT_NAME_LENGTH];
+#ifdef DEBUG_MONITOR
+ wchar_t buffer[4000];
+#endif
+ int nLocalCounter;
+ wchar_t inPipeName[PIPE_NAME_LENGTH];
+ wchar_t outPipeName[PIPE_NAME_LENGTH];
+ wchar_t errPipeName[PIPE_NAME_LENGTH];
+
+ nCmdLineLength= MAX_CMD_SIZE;
+ szCmdLine= (wchar_t *)malloc(nCmdLineLength * sizeof(wchar_t));
+ szCmdLine[0]= _T('\0');
+ if((HIBYTE(LOWORD(GetVersion()))) & 0x80)
+ {
+ ThrowByName(env, "java/io/IOException", "Does not support Windows 3.1/95/98/Me");
+ return 0;
+ }
+
+ if (cmdarray == 0)
+ {
+ ThrowByName(env, "java/lang/NullPointerException", "No command line specified");
+ return 0;
+ }
+
+ ZeroMemory(stdHandles, sizeof(stdHandles));
+
+ // Create pipe names
+ EnterCriticalSection(&cs);
+ swprintf(inPipeName, sizeof(inPipeName)/sizeof(inPipeName[0]), L"\\\\.\\pipe\\stdin%08i%010i", pid, nCounter);
+ swprintf(outPipeName, sizeof(outPipeName)/sizeof(outPipeName[0]), L"\\\\.\\pipe\\stdout%08i%010i", pid, nCounter);
+ swprintf(errPipeName, sizeof(errPipeName)/sizeof(errPipeName[0]), L"\\\\.\\pipe\\stderr%08i%010i", pid, nCounter);
+ nLocalCounter = nCounter;
+ ++nCounter;
+ LeaveCriticalSection(&cs);
+
+ if ((INVALID_HANDLE_VALUE == (stdHandles[0] = CreateNamedPipeW(inPipeName, PIPE_ACCESS_OUTBOUND,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES, PIPE_SIZE, PIPE_SIZE, PIPE_TIMEOUT, NULL))) ||
+ (INVALID_HANDLE_VALUE == (stdHandles[1] = CreateNamedPipeW(outPipeName, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES, PIPE_SIZE, PIPE_SIZE, PIPE_TIMEOUT, NULL))) ||
+ (INVALID_HANDLE_VALUE == (stdHandles[2] = CreateNamedPipeW(errPipeName, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES, PIPE_SIZE, PIPE_SIZE, PIPE_TIMEOUT, NULL)))) {
+ CloseHandle(stdHandles[0]);
+ CloseHandle(stdHandles[1]);
+ CloseHandle(stdHandles[2]);
+ ThrowByName(env, "java/io/IOException", "CreatePipe");
+ return 0;
+ }
+
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), _T("Opened pipes: %s, %s, %s\n"), inPipeName, outPipeName, errPipeName);
+ OutputDebugStringW(buffer);
+#endif
+
+
+ nCmdTokens = (*env)->GetArrayLength(env, cmdarray);
+ nEnvVars = (*env)->GetArrayLength(env, envp);
+
+ pCurProcInfo = createProcInfo();
+
+ if(NULL == pCurProcInfo)
+ {
+ ThrowByName(env, "java/io/IOException", "Too many processes");
+ return 0;
+ }
+
+ // Construct starter's command line
+ swprintf(eventBreakName, sizeof(eventBreakName)/sizeof(eventBreakName[0]), L"SABreak%04x%08x", pid, nLocalCounter);
+ swprintf(eventWaitName, sizeof(eventWaitName)/sizeof(eventWaitName[0]), L"SAWait%04x%08x", pid, nLocalCounter);
+ swprintf(eventTerminateName, sizeof(eventTerminateName)/sizeof(eventTerminateName[0]), L"SATerm%04x%08x", pid, nLocalCounter);
+ swprintf(eventKillName, sizeof(eventKillName)/sizeof(eventKillName[0]), L"SAKill%04x%08x", pid, nLocalCounter);
+ swprintf(eventCtrlcName, sizeof(eventCtrlcName)/sizeof(eventCtrlcName[0]), L"SACtrlc%04x%08x", pid, nLocalCounter);
+
+ pCurProcInfo->eventBreak = CreateEventW(NULL, FALSE, FALSE, eventBreakName);
+ if(NULL == pCurProcInfo->eventBreak || GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ ThrowByName(env, "java/io/IOException", "Cannot create event");
+ return 0;
+ }
+ pCurProcInfo->eventWait = CreateEventW(NULL, TRUE, FALSE, eventWaitName);
+ pCurProcInfo->eventTerminate = CreateEventW(NULL, FALSE, FALSE, eventTerminateName);
+ pCurProcInfo->eventKill = CreateEventW(NULL, FALSE, FALSE, eventKillName);
+ pCurProcInfo->eventCtrlc = CreateEventW(NULL, FALSE, FALSE, eventCtrlcName);
+
+ swprintf(szCmdLine, nCmdLineLength, L"\"%sstarter.exe\" %i %i %s %s %s %s %s ", path, pid, nLocalCounter, eventBreakName, eventWaitName, eventTerminateName, eventKillName, eventCtrlcName);
+ nPos = wcslen(szCmdLine);
+
+ // Prepare command line
+ for(i = 0; i < nCmdTokens; ++i)
+ {
+ jstring item = (jstring)(*env)->GetObjectArrayElement(env, cmdarray, i);
+ jsize len = (*env)->GetStringLength(env, item);
+ int nCpyLen;
+ const wchar_t * str = (const wchar_t *)(*env)->GetStringChars(env, item, 0);
+ if(NULL != str)
+ {
+ int requiredSize= nPos+len+2;
+ if (requiredSize > 32*1024) {
+ ThrowByName(env, "java/io/IOException", "Command line too long");
+ return 0;
+ }
+ ensureSize(&szCmdLine, &nCmdLineLength, requiredSize);
+ if (NULL == szCmdLine) {
+ ThrowByName(env, "java/io/IOException", "Not enough memory");
+ return 0;
+ }
+
+ if(0 > (nCpyLen = copyTo(szCmdLine + nPos, str, len, nCmdLineLength - nPos)))
+ {
+ ThrowByName(env, "java/io/IOException", "Command line too long");
+ return 0;
+ }
+ nPos += nCpyLen;
+ szCmdLine[nPos] = _T(' ');
+ ++nPos;
+ (*env)->ReleaseStringChars(env, item, (const jchar *)str);
+ }
+ }
+ szCmdLine[nPos] = _T('\0');
+
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), _T("There are %i environment variables \n"), nEnvVars);
+ OutputDebugStringW(buffer);
+#endif
+ // Prepare environment block
+ if (nEnvVars > 0)
+ {
+ nPos = 0;
+ szEnvBlock = (wchar_t *)malloc(nBlkSize * sizeof(wchar_t));
+ for(i = 0; i < nEnvVars; ++i)
+ {
+ jstring item = (jstring)(*env)->GetObjectArrayElement(env, envp, i);
+ jsize len = (*env)->GetStringLength(env, item);
+ const wchar_t * str = (const wchar_t *)(*env)->GetStringChars(env, item, 0);
+ if(NULL != str)
+ {
+ while((nBlkSize - nPos) <= (len + 2)) // +2 for two '\0'
+ {
+ nBlkSize += MAX_ENV_SIZE;
+ szEnvBlock = (wchar_t *)realloc(szEnvBlock, nBlkSize * sizeof(wchar_t));
+ if(NULL == szEnvBlock)
+ {
+ ThrowByName(env, "java/io/IOException", "Not enough memory");
+ return 0;
+ }
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), _T("Realloc environment block; new length is %i \n"), nBlkSize);
+ OutputDebugStringW(buffer);
+#endif
+
+ }
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), _T("%s\n"), str);
+ OutputDebugStringW(buffer);
+#endif
+ wcsncpy(szEnvBlock + nPos, str, len);
+ nPos += len;
+ szEnvBlock[nPos] = _T('\0');
+ ++nPos;
+ (*env)->ReleaseStringChars(env, item, (const jchar *)str);
+ }
+ }
+ szEnvBlock[nPos] = _T('\0');
+ }
+
+
+
+ if (dir != 0)
+ {
+ const wchar_t * str = (const wchar_t *)(*env)->GetStringChars(env, dir, 0);
+ if(NULL != str)
+ {
+ cwd = wcsdup(str);
+ (*env)->ReleaseStringChars(env, dir, (const jchar *)str);
+ }
+ }
+
+
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ si.dwFlags |= STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_HIDE; // Processes in the Process Group are hidden
+
+
+
+ SetHandleInformation(stdHandles[0], HANDLE_FLAG_INHERIT, FALSE);
+ SetHandleInformation(stdHandles[1], HANDLE_FLAG_INHERIT, FALSE);
+ SetHandleInformation(stdHandles[2], HANDLE_FLAG_INHERIT, FALSE);
+
+ flags = CREATE_NEW_CONSOLE;
+ flags |= CREATE_NO_WINDOW;
+ flags |= CREATE_UNICODE_ENVIRONMENT;
+
+#ifdef DEBUG_MONITOR
+ OutputDebugStringW(szCmdLine);
+#endif
+ // launches starter; we need it to create another console group to correctly process
+ // emulation of SYSint signal (Ctrl-C)
+ ret = CreateProcessW(0, /* executable name */
+ szCmdLine, /* command line */
+ 0, /* process security attribute */
+ 0, /* thread security attribute */
+ FALSE, /* inherits system handles */
+ flags, /* normal attached process */
+ szEnvBlock, /* environment block */
+ cwd, /* change to the new current directory */
+ &si, /* (in) startup information */
+ &pi); /* (out) process information */
+
+ if(NULL != cwd)
+ free((void *)cwd);
+
+ if(NULL != szEnvBlock)
+ free(szEnvBlock);
+
+ if(NULL != szCmdLine)
+ free(szCmdLine);
+
+ if (!ret) // Launching error
+ {
+ char * lpMsgBuf;
+ CloseHandle(stdHandles[0]);
+ CloseHandle(stdHandles[1]);
+ CloseHandle(stdHandles[2]);
+ FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (char *)&lpMsgBuf,
+ 0,
+ NULL
+ );
+ ThrowByName(env, "java/io/IOException", lpMsgBuf);
+ // Free the buffer.
+ LocalFree( lpMsgBuf );
+ cleanUpProcBlock(pCurProcInfo);
+ ret = -1;
+ }
+ else
+ {
+ int file_handles[3];
+ HANDLE h[2];
+ int what;
+
+ EnterCriticalSection(&cs);
+
+ pCurProcInfo -> pid = pi.dwProcessId;
+ h[0] = pCurProcInfo -> eventWait;
+ h[1] = pi.hProcess;
+
+ what = WaitForMultipleObjects(2, h, FALSE, INFINITE);
+ if(what != WAIT_OBJECT_0) // CreateProcess failed
+ {
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), _T("Process %i failed\n"), pi.dwProcessId);
+ OutputDebugStringW(buffer);
+#endif
+ cleanUpProcBlock(pCurProcInfo);
+ ThrowByName(env, "java/io/IOException", "Launching failed");
+#ifdef DEBUG_MONITOR
+ OutputDebugStringW(_T("Process failed\n"));
+#endif
+ }
+ else
+ {
+ ret = (long)(pCurProcInfo -> uid);
+
+ // Prepare stream handlers to return to java program
+ file_handles[0] = (int)stdHandles[0];
+ file_handles[1] = (int)stdHandles[1];
+ file_handles[2] = (int)stdHandles[2];
+ (*env)->SetIntArrayRegion(env, channels, 0, 3, (jint *)file_handles);
+
+ // do the cleanup so launch the according thread
+ // create a copy of the PROCESS_INFORMATION as this might get destroyed
+ piCopy = (PROCESS_INFORMATION *)malloc(sizeof(PROCESS_INFORMATION));
+ memcpy(piCopy, &pi, sizeof(PROCESS_INFORMATION));
+ _beginthread(waitProcTermination, 0, (void *)piCopy);
+
+#ifdef DEBUG_MONITOR
+ OutputDebugStringW(_T("Process started\n"));
+#endif
+ }
+ LeaveCriticalSection(&cs);
+
+ }
+
+ CloseHandle(pi.hThread);
+
+ return ret;
+
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Launcher; just launches process and don't care about it any more
+// Arguments: (see Spawner.java)
+// [in] cmdarray - array of command line elements
+// [in] envp - array of environment variables
+// [in] dir - working directory
+/////////////////////////////////////////////////////////////////////////////////////
+#ifdef __cplusplus
+extern "C"
+#endif
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec1
+ (JNIEnv * env, jobject process, jobjectArray cmdarray, jobjectArray envp, jstring dir)
+{
+
+ SECURITY_ATTRIBUTES sa;
+ PROCESS_INFORMATION pi = {0};
+ STARTUPINFOW si;
+ DWORD flags = 0;
+ wchar_t * cwd = NULL;
+ wchar_t * envBlk = NULL;
+ int ret = 0;
+ jsize nCmdTokens = 0;
+ jsize nEnvVars = 0;
+ int i;
+ int nPos;
+ int nCmdLineLength= 0;
+ wchar_t * szCmdLine= 0;
+ int nBlkSize = MAX_ENV_SIZE;
+ wchar_t * szEnvBlock = NULL;
+
+ nCmdLineLength= MAX_CMD_SIZE;
+ szCmdLine= (wchar_t *)malloc(nCmdLineLength * sizeof(wchar_t));
+ szCmdLine[0]= 0;
+
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = 0;
+ sa.bInheritHandle = TRUE;
+
+
+ nCmdTokens = (*env)->GetArrayLength(env, cmdarray);
+ nEnvVars = (*env)->GetArrayLength(env, envp);
+
+ nPos = 0;
+
+ // Prepare command line
+ for(i = 0; i < nCmdTokens; ++i)
+ {
+ jstring item = (jstring)(*env)->GetObjectArrayElement(env, cmdarray, i);
+ jsize len = (*env)->GetStringLength(env, item);
+ int nCpyLen;
+ const wchar_t * str = (const wchar_t *)(*env)->GetStringChars(env, item, 0);
+ if(NULL != str)
+ {
+ int requiredSize= nPos+len+2;
+ if (requiredSize > 32*1024) {
+ ThrowByName(env, "java/io/IOException", "Command line too long");
+ return 0;
+ }
+ ensureSize(&szCmdLine, &nCmdLineLength, requiredSize);
+ if (NULL == szCmdLine) {
+ ThrowByName(env, "java/io/IOException", "Not enough memory");
+ return 0;
+ }
+
+ if(0 > (nCpyLen = copyTo(szCmdLine + nPos, str, len, nCmdLineLength - nPos)))
+ {
+ ThrowByName(env, "java/io/Exception", "Command line too long");
+ return 0;
+ }
+ nPos += nCpyLen;
+ szCmdLine[nPos] = _T(' ');
+ ++nPos;
+ (*env)->ReleaseStringChars(env, item, (const jchar *)str);
+ }
+ }
+
+ szCmdLine[nPos] = _T('\0');
+
+ // Prepare environment block
+ if (nEnvVars > 0)
+ {
+ szEnvBlock = (wchar_t *)malloc(nBlkSize * sizeof(wchar_t));
+ nPos = 0;
+ for(i = 0; i < nEnvVars; ++i)
+ {
+ jstring item = (jstring)(*env)->GetObjectArrayElement(env, envp, i);
+ jsize len = (*env)->GetStringLength(env, item);
+ const wchar_t * str = (const wchar_t *)(*env)->GetStringChars(env, item, 0);
+ if(NULL != str)
+ {
+ while((nBlkSize - nPos) <= (len + 2)) // +2 for two '\0'
+ {
+ nBlkSize += MAX_ENV_SIZE;
+ szEnvBlock = (wchar_t *)realloc(szEnvBlock, nBlkSize * sizeof(wchar_t));
+ if(NULL == szEnvBlock)
+ {
+ ThrowByName(env, "java/io/Exception", "Not enough memory");
+ return 0;
+ }
+ }
+ wcsncpy(szEnvBlock + nPos, str, len);
+ nPos += len;
+ szEnvBlock[nPos] = _T('\0');
+ ++nPos;
+ (*env)->ReleaseStringChars(env, item, (const jchar *)str);
+ }
+ }
+ szEnvBlock[nPos] = _T('\0');
+ envBlk = szEnvBlock;
+ }
+
+
+
+ if (dir != 0)
+ {
+ const wchar_t * str = (const wchar_t *)(*env)->GetStringChars(env, dir, 0);
+ if(NULL != str)
+ {
+ cwd = wcsdup(str);
+ (*env)->ReleaseStringChars(env, dir, (const jchar *)str);
+ }
+ }
+
+
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+
+
+
+
+
+ flags = CREATE_NEW_CONSOLE;
+ flags |= CREATE_UNICODE_ENVIRONMENT;
+ ret = CreateProcessW(0, /* executable name */
+ szCmdLine, /* command line */
+ 0, /* process security attribute */
+ 0, /* thread security attribute */
+ TRUE, /* inherits system handles */
+ flags, /* normal attached process */
+ envBlk, /* environment block */
+ cwd, /* change to the new current directory */
+ &si, /* (in) startup information */
+ &pi); /* (out) process information */
+
+
+
+ if(NULL != cwd)
+ free(cwd);
+ if(NULL != szEnvBlock)
+ free(szEnvBlock);
+ if(NULL != szCmdLine)
+ free(szCmdLine);
+
+ if (!ret) // error
+ {
+ char * lpMsgBuf;
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (wchar_t *)&lpMsgBuf,
+ 0,
+ NULL
+ );
+ ThrowByName(env, "java/io/IOException", lpMsgBuf);
+ // Free the buffer.
+ LocalFree( lpMsgBuf );
+ ret = -1;
+ }
+ else
+ {
+ // Clean-up
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+ ret = (long)pi.dwProcessId; //hProcess;
+ }
+
+
+ return ret;
+
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Emulation of the signal raising
+// Arguments: (see Spawner.java)
+// [in] uid - unique process ID
+// [in] signal - signal to raise
+/////////////////////////////////////////////////////////////////////////////////////
+#ifdef __cplusplus
+extern "C"
+#endif
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_raise
+ (JNIEnv * env, jobject process, jint uid, jint signal)
+{
+ jint ret = 0;
+
+ HANDLE hProc;
+ pProcInfo_t pCurProcInfo = findProcInfo(uid);
+#ifdef DEBUG_MONITOR
+ wchar_t buffer[100];
+#endif
+
+ if(NULL == pCurProcInfo) {
+ if(SIG_INT == signal) { // Try another way
+ return interruptProcess(uid) ;
+ }
+ return -1;
+ }
+
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), _T("Spawner received signal %i for process %i\n"), signal, pCurProcInfo -> pid);
+ OutputDebugStringW(buffer);
+#endif
+
+ hProc = OpenProcess(SYNCHRONIZE, 0, pCurProcInfo -> pid);
+
+ if(NULL == hProc)
+ return -1;
+
+ switch(signal)
+ {
+ case SIG_NOOP:
+ // Wait 0 msec -just check if the process has been still running
+ ret = ((WAIT_TIMEOUT == WaitForSingleObject(hProc, 0)) ? 0 : -1);
+ break;
+ case SIG_HUP:
+ // Temporary do nothing
+ ret = 0;
+ break;
+ case SIG_TERM:
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), _T("Spawner received TERM signal for process %i\n"),
+ pCurProcInfo -> pid);
+ OutputDebugStringW(buffer);
+#endif
+ SetEvent(pCurProcInfo -> eventTerminate);
+#ifdef DEBUG_MONITOR
+ OutputDebugStringW(_T("Spawner signaled TERM event\n"));
+#endif
+ ret = 0;
+ break;
+
+ case SIG_KILL:
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), _T("Spawner received KILL signal for process %i\n"),
+ pCurProcInfo -> pid);
+ OutputDebugStringW(buffer);
+#endif
+ SetEvent(pCurProcInfo -> eventKill);
+#ifdef DEBUG_MONITOR
+ OutputDebugStringW(_T("Spawner signaled KILL event\n"));
+#endif
+ ret = 0;
+ break;
+ case SIG_INT:
+ ResetEvent(pCurProcInfo -> eventWait);
+ SetEvent(pCurProcInfo -> eventBreak);
+ ret = (WaitForSingleObject(pCurProcInfo -> eventWait, 100) == WAIT_OBJECT_0);
+ break;
+ case CTRLC:
+ ResetEvent(pCurProcInfo -> eventWait);
+ SetEvent(pCurProcInfo -> eventCtrlc);
+ ret = (WaitForSingleObject(pCurProcInfo -> eventWait, 100) == WAIT_OBJECT_0);
+ break;
+ default:
+ break;
+ }
+
+ CloseHandle(hProc);
+ return ret;
+
+
+}
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Wait for process termination
+// Arguments: (see Spawner.java)
+// [in] uid - unique process ID
+/////////////////////////////////////////////////////////////////////////////////////
+#ifdef __cplusplus
+extern "C"
+#endif
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_waitFor
+ (JNIEnv * env, jobject process, jint uid)
+{
+ DWORD exit_code = -1;
+ int what=0;
+ HANDLE hProc;
+ pProcInfo_t pCurProcInfo = findProcInfo(uid);
+
+ if(NULL == pCurProcInfo)
+ return -1;
+
+ hProc = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, 0, pCurProcInfo -> pid);
+
+ if(NULL == hProc)
+ return -1;
+
+ what = WaitForSingleObject(hProc, INFINITE);
+
+
+ if (what == WAIT_OBJECT_0)
+ {
+ GetExitCodeProcess(hProc, &exit_code);
+ }
+
+
+ if(hProc)
+ CloseHandle(hProc);
+
+ return exit_code;
+}
+
+
+
+
+
+// Utilities
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Throws Java exception (will be trapped by VM).
+// Arguments:
+// [in] name - name of exception class
+// [in] message to assign thi event
+/////////////////////////////////////////////////////////////////////////////////////
+void ThrowByName(JNIEnv *env, const char *name, const char *msg)
+{
+ jclass cls = (*env)->FindClass(env, name);
+
+ if (cls != 0) /* Otherwise an exception has already been thrown */
+ (*env)->ThrowNew(env, cls, msg);
+
+ /* It's a good practice to clean up the local references. */
+ (*env)->DeleteLocalRef(env, cls);
+}
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Create process description block.
+// Arguments: no
+// Return : pointer to the process descriptor
+/////////////////////////////////////////////////////////////////////////////////////
+pProcInfo_t createProcInfo()
+{
+ int i;
+ pProcInfo_t p = NULL;
+
+ EnterCriticalSection(&cs);
+
+ if(NULL == pInfo)
+ {
+ pInfo = (pProcInfo_t)malloc(sizeof(procInfo_t) * MAX_PROCS);
+ ZeroMemory(pInfo, sizeof(procInfo_t) * MAX_PROCS);
+ }
+
+ for(i = 0; i < MAX_PROCS; ++i)
+ {
+ if(pInfo[i].pid == 0)
+ {
+ pInfo[i].pid = -1;
+ pInfo[i].uid = ++procCounter;
+ p = pInfo + i;
+ break;
+ }
+ }
+
+ LeaveCriticalSection(&cs);
+
+ return p;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Using unique process ID finds process descriptor
+// Arguments: no
+// Return : pointer to the process descriptor
+/////////////////////////////////////////////////////////////////////////////////////
+pProcInfo_t findProcInfo(int uid)
+{
+ int i;
+ pProcInfo_t p = NULL;
+ if(NULL == pInfo)
+ return NULL;
+
+ for(i = 0; i < MAX_PROCS; ++i)
+ {
+ if(pInfo[i].uid == uid)
+ {
+ p = pInfo + i;
+ break;
+ }
+ }
+
+ return p;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Cleans up vacant process descriptor
+// Arguments:
+// pCurProcInfo - pointer to descriptor to clean up
+// Return : no
+void cleanUpProcBlock(pProcInfo_t pCurProcInfo)
+{
+ if(0 != pCurProcInfo -> eventBreak)
+ {
+ CloseHandle(pCurProcInfo -> eventBreak);
+ pCurProcInfo -> eventBreak = 0;
+ }
+ if(0 != pCurProcInfo -> eventWait)
+ {
+ CloseHandle(pCurProcInfo -> eventWait);
+ pCurProcInfo -> eventWait = 0;
+ }
+ if(0 != pCurProcInfo -> eventTerminate)
+ {
+ CloseHandle(pCurProcInfo -> eventTerminate);
+ pCurProcInfo -> eventTerminate = 0;
+ }
+
+ if(0 != pCurProcInfo -> eventKill)
+ {
+ CloseHandle(pCurProcInfo -> eventKill);
+ pCurProcInfo -> eventKill = 0;
+ }
+
+ if(0 != pCurProcInfo -> eventCtrlc)
+ {
+ CloseHandle(pCurProcInfo -> eventCtrlc);
+ pCurProcInfo -> eventCtrlc = 0;
+ }
+
+ pCurProcInfo -> pid = 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Running in separate thread and waiting for the process termination
+// Arguments:
+// pv - pointer to PROCESS_INFORMATION struct
+// Return : no
+/////////////////////////////////////////////////////////////////////////////////////
+void _cdecl waitProcTermination(void* pv)
+{
+ PROCESS_INFORMATION *pi = (PROCESS_INFORMATION *)pv;
+ int i;
+#ifdef DEBUG_MONITOR
+ wchar_t buffer[1000];
+#endif
+
+ // wait for process termination
+ WaitForSingleObject(pi->hProcess, INFINITE);
+
+ for(i = 0; i < MAX_PROCS; ++i)
+ {
+ if(pInfo[i].pid == pi->dwProcessId)
+ {
+ cleanUpProcBlock(pInfo + i);
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), _T("waitProcTermination: set PID %i to 0\n"),
+ pi->dwProcessId);
+ OutputDebugStringW(buffer);
+#endif
+ }
+ }
+ CloseHandle(pi->hProcess);
+
+ free(pi);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Use this utility program to process correctly quotation marks in the command line
+// Arguments:
+// target - string to copy to
+// source - string to copy from
+// cpyLength - copy length
+// availSpace - size of the target buffer
+// Return :number of bytes used in target, or -1 in case of error
+/////////////////////////////////////////////////////////////////////////////////////
+int copyTo(wchar_t * target, const wchar_t * source, int cpyLength, int availSpace)
+{
+ BOOL bSlash = FALSE;
+ int i = 0, j = 0;
+ int totCpyLength = cpyLength;
+
+#define QUOTATION_DO 0
+#define QUOTATION_DONE 1
+#define QUOTATION_NONE 2
+
+ int nQuotationMode = 0;
+
+
+
+ if(availSpace <= cpyLength) // = to reserve space for final '\0'
+ return -1;
+
+ if((_T('\"') == *source) && (_T('\"') == *(source + cpyLength - 1)))
+ {
+ nQuotationMode = QUOTATION_DONE;
+ }
+ else
+ if(wcschr(source, _T(' ')) == NULL)
+ {
+ // No reason to quote term because it doesn't have embedded spaces
+ nQuotationMode = QUOTATION_NONE;
+ }
+ else
+ {
+ // Needs to be quoted
+ nQuotationMode = QUOTATION_DO;
+ *target = _T('\"');
+ ++j;
+ }
+
+
+ for(; i < cpyLength; ++i, ++j)
+ {
+ if(source[i] == _T('\\'))
+ bSlash = TRUE;
+ else
+ {
+ // Don't escape embracing quotation marks
+ if((source[i] == _T('\"')) && !((nQuotationMode == QUOTATION_DONE) && ((i == 0) || (i == (cpyLength - 1))) ) )
+ {
+ if(!bSlash) // If still not escaped
+ {
+ if(j == availSpace)
+ return -1;
+ target[j] = _T('\\');
+ ++j;
+ }
+ }
+ bSlash = FALSE;
+ }
+
+ if(j == availSpace)
+ return -1;
+ target[j] = source[i];
+ }
+
+ if(nQuotationMode == QUOTATION_DO)
+ {
+ if(j == availSpace)
+ return -1;
+ target[j] = _T('\"');
+ ++j;
+ }
+
+ return j;
+}
diff --git a/core/org.eclipse.cdt.core.native/native_src/win/iostream.c b/core/org.eclipse.cdt.core.native/native_src/win/iostream.c
new file mode 100644
index 00000000000..7fcfaf90d18
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/win/iostream.c
@@ -0,0 +1,279 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2009 QNX Software Systems and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *
+ * raise.c
+ *
+ * This is a part of JNI implementation of spawner
+ * Includes implementation of JNI methods (see Spawner.java)
+ *******************************************************************************/
+#include <string.h>
+#include <stdlib.h>
+#include <jni.h>
+#include <windows.h>
+
+#include "Spawner.h"
+
+//#define READ_REPORT
+
+void ThrowByName(JNIEnv *env, const char *name, const char *msg);
+
+#define BUFF_SIZE (1024)
+
+/* Inaccessible static: skipBuffer */
+/*
+ * Class: SpawnerInputStream
+ * Method: read0
+ * Signature: (I)I
+ */
+#ifdef __cplusplus
+extern "C"
+#endif
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_read0
+ (JNIEnv * env, jobject proc, jint fd, jbyteArray buf, jint len)
+{
+ jbyte tmpBuf[BUFF_SIZE];
+ int nBuffOffset = 0;
+#ifdef DEBUG_MONITOR
+ _TCHAR buffer[1000];
+#endif
+ OVERLAPPED overlapped;
+ overlapped.Offset = 0;
+ overlapped.OffsetHigh = 0;
+ overlapped.hEvent = CreateEvent(NULL, // no security attribute
+ TRUE, // manual-reset event
+ TRUE, // initial state = signaled
+ NULL); // unnamed event object
+
+ if(NULL == overlapped.hEvent) {
+ char * lpMsgBuf;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (wchar_t *) &lpMsgBuf,
+ 0,
+ NULL
+ );
+
+ ThrowByName(env, "java/io/IOException", lpMsgBuf);
+ // Free the buffer.
+ LocalFree( lpMsgBuf );
+ }
+
+#ifdef DEBUG_MONITOR
+#ifdef READ_REPORT
+ _stprintf(buffer, _T("Start read %i\n"), fd);
+ OutputDebugStringW(buffer);
+#endif
+#endif
+
+ while(len > nBuffOffset)
+ {
+ DWORD nNumberOfBytesToRead = min(len - nBuffOffset, BUFF_SIZE);
+ DWORD nNumberOfBytesRead;
+ if(0 == ReadFile((HANDLE)fd, tmpBuf, nNumberOfBytesToRead, &nNumberOfBytesRead, &overlapped ))
+ {
+ int err = GetLastError();
+
+ if(err == ERROR_IO_PENDING)
+ {
+ // asynchronous i/o is still in progress
+ // check on the results of the asynchronous read
+ if(GetOverlappedResult((HANDLE)fd, &overlapped,
+ &nNumberOfBytesRead, TRUE))
+ err = 0;
+ // if there was a problem ...
+ else
+ err = GetLastError();
+ }
+ if(err == ERROR_BROKEN_PIPE) // Pipe was closed
+ break;
+ if(err != 0)
+ {
+ char * lpMsgBuf;
+#ifdef DEBUG_MONITOR
+ _stprintf(buffer, _T("Read failed - %i, error %i\n"), fd, err);
+ OutputDebugStringW(buffer);
+#endif
+ if(err != ERROR_MORE_DATA) // Otherwise error means just that there are more data
+ { // than buffer can accept
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (wchar_t *) &lpMsgBuf,
+ 0,
+ NULL
+ );
+
+ ThrowByName(env, "java/io/IOException", lpMsgBuf);
+ LocalFree( lpMsgBuf );
+ nBuffOffset = 0;
+ break;
+ }
+ else
+ {
+ // buffer overflow?
+ // according to msdn this happens in message read mode only
+#ifdef DEBUG_MONITOR
+ _stprintf(buffer, _T("Buffer full - %i, bytes read: %i\n"), fd, nNumberOfBytesRead);
+ OutputDebugStringW(buffer);
+#endif
+ // nNumberOfBytesRead can be 0 here for unknown reason (bug 269223)
+ nNumberOfBytesRead = nNumberOfBytesToRead;
+ }
+ }
+ }
+ if(nNumberOfBytesRead > 0)
+ (*env)->SetByteArrayRegion(env, buf, nBuffOffset, nNumberOfBytesRead, tmpBuf);
+ else
+ break;
+ nBuffOffset += nNumberOfBytesRead;
+ if(nNumberOfBytesRead != nNumberOfBytesToRead)
+ break;
+ else
+ {
+ // Is there data left in the pipe?
+ DWORD bytesAvailable = 0;
+ if (!PeekNamedPipe((HANDLE)fd, NULL, 0, NULL, &bytesAvailable, NULL)
+ || bytesAvailable == 0)
+ // No bytes left
+ break;
+ }
+ }
+ CloseHandle(overlapped.hEvent);
+#ifdef DEBUG_MONITOR
+#ifdef READ_REPORT
+ _stprintf(buffer, _T("End read %i - bytes read: %d\n"), fd, nBuffOffset);
+ OutputDebugStringW(buffer);
+#endif
+#endif
+ return nBuffOffset; // This is a real full readed length
+
+}
+
+/*
+ * Class: SpawnerInputStream
+ * Method: close0
+ * Signature: (I)I
+ */
+#ifdef __cplusplus
+extern "C"
+#endif
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_close0
+ (JNIEnv * env, jobject proc, jint fd)
+{
+ int rc;
+#ifdef DEBUG_MONITOR
+ _TCHAR buffer[1000];
+ _stprintf(buffer, _T("Close %i\n"), fd);
+ OutputDebugStringW(buffer);
+#endif
+ rc = (CloseHandle((HANDLE)fd) ? 0 : -1);
+#ifdef DEBUG_MONITOR
+ _stprintf(buffer, _T("Closed %i\n"), fd);
+ OutputDebugStringW(buffer);
+#endif
+ return (rc ? GetLastError() : 0);
+}
+
+#ifdef __cplusplus
+extern "C"
+#endif
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_available0
+ (JNIEnv * env, jobject proc, jint fd)
+{
+ DWORD nAvail = 0;
+
+ if (0 == PeekNamedPipe((HANDLE)fd, NULL, 0, NULL, &nAvail, NULL)) {
+ // error
+ return 0;
+ }
+ return nAvail;
+}
+
+/*
+ * Class: SpawnerOutputStream
+ * Method: write0
+ * Signature: (I[BI)I
+ */
+#ifdef __cplusplus
+extern "C"
+#endif
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_write0
+ (JNIEnv * env, jobject proc, jint fd, jbyteArray buf, jint len)
+{
+ jbyte tmpBuf[BUFF_SIZE];
+ int nBuffOffset = 0;
+
+
+ while(len > nBuffOffset)
+ {
+ DWORD nNumberOfBytesToWrite = min(len - nBuffOffset, BUFF_SIZE);
+ DWORD nNumberOfBytesWritten;
+ (*env)->GetByteArrayRegion(env, buf, nBuffOffset, nNumberOfBytesToWrite, tmpBuf);
+ if(0 == WriteFile((HANDLE)fd, tmpBuf, nNumberOfBytesToWrite, &nNumberOfBytesWritten, NULL))
+ {
+ char * lpMsgBuf;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (wchar_t *) &lpMsgBuf,
+ 0,
+ NULL
+ );
+
+ ThrowByName(env, "java/io/IOException", lpMsgBuf);
+ LocalFree( lpMsgBuf );
+ return 0;
+ }
+ nBuffOffset += nNumberOfBytesWritten;
+ }
+ return 0;
+}
+
+/*
+ * Class: SpawnerOutputStream
+ * Method: close0
+ * Signature: (I)I
+ */
+#ifdef __cplusplus
+extern "C"
+#endif
+JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_close0
+ (JNIEnv * env, jobject proc, jint fd)
+{
+ int rc;
+#ifdef DEBUG_MONITOR
+ _TCHAR buffer[1000];
+ _stprintf(buffer, _T("Close %i\n"), fd);
+ OutputDebugStringW(buffer);
+#endif
+ FlushFileBuffers((HANDLE)fd);
+ rc = (CloseHandle((HANDLE)fd) ? 0 : -1);
+#ifdef DEBUG_MONITOR
+ _stprintf(buffer, _T("Closed %i\n"), fd);
+ OutputDebugStringW(buffer);
+#endif
+ return (rc ? GetLastError() : 0);
+}
diff --git a/core/org.eclipse.cdt.core.native/native_src/win/raise.c b/core/org.eclipse.cdt.core.native/native_src/win/raise.c
new file mode 100644
index 00000000000..b908b159d0b
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/win/raise.c
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2011 QNX Software Systems and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *
+ * raise.c
+ *
+ * This is a part of JNI implementation of spawner
+ *******************************************************************************/
+#include <jni.h>
+#include <windows.h>
+
+#include "Spawner.h"
+
+extern void JNICALL ThrowByName(JNIEnv *env, const char *name, const char *msg);
+
+
+static HWND consoleHWND;
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Check if window is a console of process with pid
+// Arguments:
+// hwnd - window handler
+// arg - process PID
+// Return : TRUE if yes
+/////////////////////////////////////////////////////////////////////////////////////
+static BOOL CALLBACK
+find_child_console (HWND hwnd, LPARAM arg)
+{
+ DWORD thread_id;
+ DWORD process_id;
+ DWORD pid = arg;
+
+ thread_id = GetWindowThreadProcessId (hwnd, &process_id);
+ if (process_id == pid)
+ {
+ wchar_t window_class[32];
+
+ GetClassName (hwnd, window_class, sizeof (window_class));
+ if (wcscmp (window_class, L"ConsoleWindowClass") == 0)
+ {
+ consoleHWND = hwnd;
+ return FALSE;
+ }
+ }
+ /* keep looking */
+ return TRUE;
+}
+
+// Need to declare this Win32 prototype ourselves. _WIN32_WINNT is getting
+// defined to a Windows NT value, thus we don't get this. Can't assume
+// we're running on XP, anyway (or can we by now?)
+#if (_WIN32_WINNT < 0x0501) || defined(_MSC_VER)
+typedef BOOL (WINAPI *DebugBreakProcessFunc)(HANDLE);
+#endif
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Called to interrupt a process that we didn't launch (and thus does not share our
+// console). Windows XP introduced the function 'DebugBreakProcess', which allows
+// a process to interrupt another process even if if the two do not share a console.
+// If we're running on 2000 or earlier, we have to resort to simulating a CTRL-C
+// in the console by firing keyboard events. This will work only if the process
+// has its own console. That means, e.g., the process should have been started at
+// the cmdline with 'start myprogram.exe' instead of 'myprogram.exe'.
+//
+// Arguments:
+// pid - process' pid
+// Return : 0 if OK or error code
+/////////////////////////////////////////////////////////////////////////////////////
+int interruptProcess(int pid)
+{
+ // See if DebugBreakProcess is available (XP and beyond)
+ HMODULE hmod = LoadLibrary(L"Kernel32.dll");
+ if (hmod != NULL)
+ {
+ BOOL success = FALSE;
+ FARPROC procaddr = GetProcAddress(hmod, "DebugBreakProcess");
+ if (procaddr != NULL)
+ {
+ HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid);
+ if (proc != NULL)
+ {
+ typedef BOOL WINAPI (*DebugBreakProcessFunc)(HANDLE);
+ DebugBreakProcessFunc pDebugBreakProcess = (DebugBreakProcessFunc)procaddr;
+ success = (*pDebugBreakProcess)(proc);
+ CloseHandle(proc);
+ }
+ }
+ FreeLibrary(hmod);
+ hmod = NULL;
+
+ if (success)
+ return 0; // 0 == OK; if not, try old-school way
+ }
+
+#ifdef DEBUG_MONITOR
+ _TCHAR buffer[1000];
+#endif
+ int rc = 0;
+ consoleHWND = NULL;
+
+#ifdef DEBUG_MONITOR
+ _stprintf(buffer, _T("Try to interrupt process %i\n"), pid);
+ OutputDebugStringW(buffer);
+#endif
+ // Find console
+ EnumWindows (find_child_console, (LPARAM) pid);
+
+ if(NULL != consoleHWND) // Yes, we found out it
+ {
+ // We are going to switch focus to console,
+ // send Ctrl-C and then restore focus
+ BYTE control_scan_code = (BYTE) MapVirtualKey (VK_CONTROL, 0);
+ /* Fake Ctrl-C for SIGINT, and Ctrl-Break for SIGQUIT. */
+ BYTE vk_c_code = 'C';
+ BYTE vk_break_code = VK_CANCEL;
+ BYTE c_scan_code = (BYTE) MapVirtualKey (vk_c_code, 0);
+ BYTE break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0);
+ HWND foreground_window;
+
+
+ foreground_window = GetForegroundWindow ();
+ if (foreground_window)
+ {
+ /* NT 5.0, and apparently also Windows 98, will not allow
+ a Window to be set to foreground directly without the
+ user's involvement. The workaround is to attach
+ ourselves to the thread that owns the foreground
+ window, since that is the only thread that can set the
+ foreground window. */
+ DWORD foreground_thread, child_thread;
+ foreground_thread =
+ GetWindowThreadProcessId (foreground_window, NULL);
+ if (foreground_thread == GetCurrentThreadId ()
+ || !AttachThreadInput (GetCurrentThreadId (),
+ foreground_thread, TRUE))
+ foreground_thread = 0;
+
+ child_thread = GetWindowThreadProcessId (consoleHWND, NULL);
+ if (child_thread == GetCurrentThreadId ()
+ || !AttachThreadInput (GetCurrentThreadId (),
+ child_thread, TRUE))
+ child_thread = 0;
+
+ /* Set the foreground window to the child. */
+ if (SetForegroundWindow (consoleHWND))
+ {
+ if(0 != break_scan_code) {
+ /* Generate keystrokes as if user had typed Ctrl-Break */
+ keybd_event (VK_CONTROL, control_scan_code, 0, 0);
+ keybd_event (vk_break_code, break_scan_code, KEYEVENTF_EXTENDEDKEY, 0);
+ keybd_event (vk_break_code, break_scan_code,
+ KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
+ keybd_event (VK_CONTROL, control_scan_code, KEYEVENTF_KEYUP, 0);
+ }
+
+ /* Sleep for a bit to give time for respond */
+ Sleep (100);
+
+ SetForegroundWindow (foreground_window);
+ }
+ /* Detach from the foreground and child threads now that
+ the foreground switching is over. */
+ if (foreground_thread)
+ AttachThreadInput (GetCurrentThreadId (),
+ foreground_thread, FALSE);
+ if (child_thread)
+ AttachThreadInput (GetCurrentThreadId (),
+ child_thread, FALSE);
+#ifdef DEBUG_MONITOR
+ _stprintf(buffer, _T("Sent Ctrl-C & Ctrl-Break to process %i\n"), pid);
+ OutputDebugStringW(buffer);
+#endif
+ }
+ }
+#ifdef DEBUG_MONITOR
+ else {
+ _stprintf(buffer, _T("Cannot find console for process %i\n"), pid);
+ OutputDebugStringW(buffer);
+ }
+#endif
+
+ return rc;
+}
+
diff --git a/core/org.eclipse.cdt.core.native/native_src/win/spawner.c b/core/org.eclipse.cdt.core.native/native_src/win/spawner.c
new file mode 100644
index 00000000000..ba3e27f2c44
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/win/spawner.c
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2007 QNX Software Systems and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ *
+ * spawner.c
+ *
+ * This is a part of JNI implementation of spawner
+ *******************************************************************************/
+
+#include <tchar.h>
+#include <windows.h>
+
+#include "Spawner.h"
+
+CRITICAL_SECTION cs;
+
+
+wchar_t path[MAX_PATH + 1] = {_T('\0') }; // Directory where spawner.dll is located
+
+#if __cplusplus
+extern "C"
+#endif
+BOOL APIENTRY DllMain( HINSTANCE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+ )
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ {
+ wchar_t * p;
+ InitializeCriticalSection(&cs);
+ GetModuleFileNameW(hModule, path, MAX_PATH);
+ p = wcsrchr(path, _T('\\'));
+ if(NULL != p)
+ *(p + 1) = _T('\0');
+ else
+ wcscat(path, L"\\");
+ }
+ break;
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ break;
+ case DLL_PROCESS_DETACH:
+ DeleteCriticalSection(&cs);
+ break;
+ }
+ return TRUE;
+}
+
diff --git a/core/org.eclipse.cdt.core.native/native_src/win/starter.c b/core/org.eclipse.cdt.core.native/native_src/win/starter.c
new file mode 100644
index 00000000000..6284f75586f
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/native_src/win/starter.c
@@ -0,0 +1,527 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2015 QNX Software Systems and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ * Wind River Systems, Inc.
+ *
+ * starter.cpp
+ *
+ * This is a small utility for windows spawner
+ *******************************************************************************/
+
+#define STRICT
+#define _WIN32_WINNT 0x0500
+#include <windows.h>
+#include <process.h>
+#include <tchar.h>
+#include <stdio.h>
+#include <psapi.h>
+#include <stdbool.h>
+
+//#define DEBUG_MONITOR
+#define MAX_CMD_LINE_LENGTH (2049)
+#define PIPE_NAME_LENGTH 100
+
+int copyTo(wchar_t * target, const wchar_t * source, int cpyLength,
+ int availSpace);
+void DisplayErrorMessage();
+
+//BOOL KillProcessEx(DWORD dwProcessId); // Handle of the process
+
+///////////////////////////////////////////////////////////////////////////////
+BOOL WINAPI HandlerRoutine( DWORD dwCtrlType) // control signal type
+{
+ BOOL ret = TRUE;
+ switch(dwCtrlType)
+ {
+ case CTRL_C_EVENT:
+ break;
+ case CTRL_BREAK_EVENT:
+ break;
+ case CTRL_CLOSE_EVENT:
+ ret = FALSE;
+ break;
+ case CTRL_LOGOFF_EVENT:
+ ret = FALSE;
+ break;
+ case CTRL_SHUTDOWN_EVENT:
+ ret = FALSE;
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+// The default here means we haven't checked yet
+// i.e. cygwin is true but the bin dir hasn't been captured
+wchar_t * cygwinBin = NULL;
+bool _isCygwin = true;
+
+bool isCygwin(HANDLE process) {
+ // Have we checked before?
+ if (cygwinBin != NULL || !_isCygwin)
+ return _isCygwin;
+
+ // See if this process loaded cygwin, need a different SIGINT for them
+ HMODULE mods[1024];
+ DWORD needed;
+ if (EnumProcessModules(process, mods, sizeof(mods), &needed)) {
+ int i;
+ needed /= sizeof(HMODULE);
+ for (i = 0; i < needed; ++i ) {
+ wchar_t modName[MAX_PATH];
+ if (GetModuleFileNameEx(process, mods[i], modName, MAX_PATH)) {
+ wchar_t * p = wcsrchr(modName, L'\\');
+ if (p) {
+ *p = 0; // Null terminate there for future reference
+ if (!wcscmp(++p, L"cygwin1.dll")) {
+ _isCygwin = true;
+ // Store away the bind dir
+ cygwinBin = wcsdup(modName);
+ return _isCygwin;
+ }
+ }
+ }
+ }
+ }
+
+ _isCygwin = false;
+ return _isCygwin;
+}
+
+bool runCygwinCommand(wchar_t * command) {
+ wchar_t cygcmd[1024];
+ swprintf(cygcmd, sizeof(cygcmd)/sizeof(cygcmd[0]), L"%s\\%s", cygwinBin, command);
+
+ STARTUPINFO si;
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ PROCESS_INFORMATION pi;
+ ZeroMemory(&pi, sizeof(pi));
+ if (CreateProcess(NULL, cygcmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+ return true;
+ } else if (CreateProcess(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+ return true;
+ }
+ return false;
+}
+
+void ensureSize(wchar_t** ptr, int* psize, int requiredLength) {
+ int size= *psize;
+ if (requiredLength > size) {
+ size= 2*size;
+ if (size < requiredLength) {
+ size= requiredLength;
+ }
+ *ptr= (wchar_t *)realloc(*ptr, size * sizeof(wchar_t));
+ if (NULL == *ptr) {
+ *psize= 0;
+ } else {
+ *psize= size;
+ }
+ }
+}
+
+int main() {
+
+ int argc;
+ wchar_t ** argv = CommandLineToArgvW(GetCommandLine(), &argc);
+
+ // Make sure that we've been passed the right number of arguments
+ if (argc < 8) {
+ _tprintf(_T("Usage: %s (four inheritable event handles) (CommandLineToSpawn)\n"),
+ argv[0]);
+ return(0);
+ }
+
+ // Construct the full command line
+ int nCmdLineLength= MAX_CMD_LINE_LENGTH;
+ wchar_t * szCmdLine= (wchar_t *)malloc(nCmdLineLength * sizeof(wchar_t));
+ szCmdLine[0]= 0;
+ int nPos = 0;
+
+ for(int i = 8; i < argc; ++i)
+ {
+ int nCpyLen;
+ int len= wcslen(argv[i]);
+ int requiredSize= nPos+len+2;
+ if (requiredSize > 32*1024) {
+#ifdef DEBUG_MONITOR
+ OutputDebugStringW(_T("Command line too long!\n"));
+#endif
+ return 0;
+ }
+ ensureSize(&szCmdLine, &nCmdLineLength, requiredSize);
+ if (NULL == szCmdLine) {
+#ifdef DEBUG_MONITOR
+ OutputDebugStringW(_T("Not enough memory to build cmd line!\n"));
+#endif
+ return 0;
+ }
+ if(0 > (nCpyLen = copyTo(szCmdLine + nPos, argv[i], len, nCmdLineLength - nPos)))
+ {
+#ifdef DEBUG_MONITOR
+ OutputDebugStringW(_T("Not enough space to build command line\n"));
+#endif
+ return 0;
+ }
+ nPos += nCpyLen;
+ szCmdLine[nPos] = _T(' ');
+ ++nPos;
+ }
+ szCmdLine[nPos] = _T('\0');
+
+ STARTUPINFOW si = {sizeof(si)};
+ PROCESS_INFORMATION pi = {0};
+ DWORD dwExitCode = 0;
+#ifdef DEBUG_MONITOR
+ int currentPID = GetCurrentProcessId();
+ wchar_t buffer[MAX_CMD_LINE_LENGTH];
+#endif
+
+ BOOL exitProc = FALSE;
+ HANDLE waitEvent = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[4]);
+ HANDLE h[5];
+ h[0] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[3]); // simulated SIGINT (CTRL-C or Cygwin 'kill -SIGINT')
+// h[1] we reserve for the process handle
+ h[2] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[5]); // simulated SIGTERM
+ h[3] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[6]); // simulated SIGKILL
+ h[4] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[7]); // CTRL-C, in all cases
+
+ SetConsoleCtrlHandler(HandlerRoutine, TRUE);
+
+ int parentPid = wcstol(argv[1], NULL, 10);
+ int nCounter = wcstol(argv[2], NULL, 10);
+ wchar_t inPipeName[PIPE_NAME_LENGTH];
+ wchar_t outPipeName[PIPE_NAME_LENGTH];
+ wchar_t errPipeName[PIPE_NAME_LENGTH];
+
+ swprintf(inPipeName, sizeof(inPipeName)/sizeof(inPipeName[0]), L"\\\\.\\pipe\\stdin%08i%010i", parentPid, nCounter);
+ swprintf(outPipeName, sizeof(outPipeName)/sizeof(outPipeName[0]), L"\\\\.\\pipe\\stdout%08i%010i", parentPid, nCounter);
+ swprintf(errPipeName, sizeof(errPipeName)/sizeof(errPipeName[0]), L"\\\\.\\pipe\\stderr%08i%010i", parentPid, nCounter);
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, _T("Pipes: %s, %s, %s\n"), inPipeName, outPipeName, errPipeName);
+ OutputDebugStringW(buffer);
+#endif
+
+ HANDLE stdHandles[3];
+
+ SECURITY_ATTRIBUTES sa;
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = TRUE;
+ sa.lpSecurityDescriptor = NULL;
+
+ if((INVALID_HANDLE_VALUE == (stdHandles[0] = CreateFileW(inPipeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, &sa))) ||
+ (INVALID_HANDLE_VALUE == (stdHandles[1] = CreateFileW(outPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa))) ||
+ (INVALID_HANDLE_VALUE == (stdHandles[2] = CreateFileW(errPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa))))
+ {
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), _T("Failed to open pipe %i, %i, %i: %i\n"), stdHandles[0], stdHandles[1], stdHandles[2], GetLastError());
+ OutputDebugStringW(buffer);
+#endif
+ CloseHandle(stdHandles[0]);
+ CloseHandle(stdHandles[1]);
+ CloseHandle(stdHandles[2]);
+ return -1;;
+ }
+ SetHandleInformation(stdHandles[0], HANDLE_FLAG_INHERIT, TRUE);
+ SetHandleInformation(stdHandles[1], HANDLE_FLAG_INHERIT, TRUE);
+ SetHandleInformation(stdHandles[2], HANDLE_FLAG_INHERIT, TRUE);
+
+ if(!SetStdHandle(STD_INPUT_HANDLE, stdHandles[0]) ||
+ !SetStdHandle(STD_OUTPUT_HANDLE, stdHandles[1]) ||
+ !SetStdHandle(STD_ERROR_HANDLE, stdHandles[2])) {
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), _T("Failed to reassign standard streams: %i\n"), GetLastError());
+ OutputDebugStringW(buffer);
+#endif
+ CloseHandle(stdHandles[0]);
+ CloseHandle(stdHandles[1]);
+ CloseHandle(stdHandles[2]);
+ return -1;;
+ }
+
+#ifdef DEBUG_MONITOR_DETAILS
+ wchar_t * lpvEnv = GetEnvironmentStringsW();
+
+ // If the returned pointer is NULL, exit.
+ if (lpvEnv == NULL)
+ OutputDebugStringW(_T("Cannot Read Environment\n"));
+ else {
+ // Variable strings are separated by NULL byte, and the block is
+ // terminated by a NULL byte.
+
+ OutputDebugStringW(_T("Starter: Environment\n"));
+ for (wchar_t * lpszVariable = (wchar_t *) lpvEnv; *lpszVariable; lpszVariable+=wcslen(lpszVariable) + 1) {
+ swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), _T("%s\n"), lpszVariable);
+ OutputDebugStringW(buffer);
+ }
+
+ FreeEnvironmentStringsW(lpvEnv);
+ }
+#endif
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), _T("Starting: %s\n"), szCmdLine);
+ OutputDebugStringW(buffer);
+#endif
+ // Create job object
+ HANDLE hJob = CreateJobObject(NULL, NULL);
+ if (hJob != NULL) {
+ // Configure job to
+ // - terminate all associated processes when the last handle to it is closed
+ // - allow child processes to break away from the job.
+ JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo;
+ ZeroMemory(&jobInfo, sizeof(jobInfo));
+ jobInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_BREAKAWAY_OK;
+ if (!SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &jobInfo, sizeof(jobInfo))) {
+#ifdef DEBUG_MONITOR
+ OutputDebugStringW(_T("Cannot set job information\n"));
+ DisplayErrorMessage();
+#endif
+ }
+ } else {
+#ifdef DEBUG_MONITOR
+ OutputDebugStringW(_T("Cannot create job object\n"));
+ DisplayErrorMessage();
+#endif
+ }
+ // Spawn the other processes as part of this Process Group
+ // If this process is already part of a job, the flag CREATE_BREAKAWAY_FROM_JOB
+ // makes the child process detach from the job, such that we can assign it
+ // to our own job object.
+ BOOL f = CreateProcessW(NULL, szCmdLine, NULL, NULL, TRUE,
+ CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi);
+ // If breaking away from job is not permitted, retry without breakaway flag
+ if (!f)
+ f = CreateProcessW(NULL, szCmdLine, NULL, NULL, TRUE,
+ 0, NULL, NULL, &si, &pi);
+
+ // We don't need them any more
+ CloseHandle(stdHandles[0]);
+ CloseHandle(stdHandles[1]);
+ CloseHandle(stdHandles[2]);
+
+ if (f) {
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), _T("Process %i started\n"), pi.dwProcessId);
+ OutputDebugStringW(buffer);
+#endif
+ SetEvent(waitEvent); // Means that process has been spawned
+ CloseHandle(pi.hThread);
+ h[1] = pi.hProcess;
+
+ if(NULL != hJob) {
+ if(!AssignProcessToJobObject(hJob, pi.hProcess)) {
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), _T("Cannot assign process %i to a job\n"), pi.dwProcessId);
+ OutputDebugStringW(buffer);
+ DisplayErrorMessage();
+#endif
+ }
+ }
+
+ while(!exitProc)
+ {
+ // Wait for the spawned-process to die or for the event
+ // indicating that the processes should be forcibly killed.
+ DWORD event = WaitForMultipleObjects(5, h, FALSE, INFINITE);
+ switch (event)
+ {
+ case WAIT_OBJECT_0 + 0: // SIGINT
+ case WAIT_OBJECT_0 + 4: // CTRL-C
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), _T("starter (PID %i) received CTRL-C event\n"), currentPID);
+ OutputDebugStringW(buffer);
+#endif
+ if ((event == (WAIT_OBJECT_0 + 0)) && isCygwin(h[1])) {
+ // Need to issue a kill command
+ wchar_t kill[1024];
+ swprintf(kill, sizeof(kill)/sizeof(kill[0]), L"kill -SIGINT %d", pi.dwProcessId);
+ if (!runCygwinCommand(kill)) {
+ // fall back to console event
+ GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
+ }
+ } else {
+ GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
+ }
+
+ SetEvent(waitEvent);
+ break;
+
+ case WAIT_OBJECT_0 + 1: // App terminated normally
+ // Make it's exit code our exit code
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), _T("starter: launched process has been terminated(PID %i)\n"),
+ pi.dwProcessId);
+ OutputDebugStringW(buffer);
+#endif
+ GetExitCodeProcess(pi.hProcess, &dwExitCode);
+ exitProc = TRUE;
+ break;
+
+ // Terminate and Kill behavior differ only for cygwin processes, where
+ // we use the cygwin 'kill' command. We send a SIGKILL in one case,
+ // SIGTERM in the other. For non-cygwin processes, both requests
+ // are treated exactly the same
+ case WAIT_OBJECT_0 + 2: // TERM
+ case WAIT_OBJECT_0 + 3: // KILL
+ {
+ const wchar_t* signal = (event == WAIT_OBJECT_0 + 2) ? L"TERM" : L"KILL";
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), _T("starter received %s event (PID %i)\n"), signal, currentPID);
+ OutputDebugStringW(buffer);
+#endif
+ if (isCygwin(h[1])) {
+ // Need to issue a kill command
+ wchar_t kill[1024];
+ swprintf(kill, sizeof(kill)/sizeof(kill[0]), L"kill -%s %d", signal, pi.dwProcessId);
+ if (!runCygwinCommand(kill)) {
+ // fall back to console event
+ GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
+ }
+ } else {
+ GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
+ }
+
+ SetEvent(waitEvent);
+
+ if(NULL != hJob) {
+ if(!TerminateJobObject(hJob, (DWORD)-1)) {
+#ifdef DEBUG_MONITOR
+ OutputDebugStringW(_T("Cannot terminate job\n"));
+ DisplayErrorMessage();
+#endif
+ }
+ }
+
+ // Note that we keep trucking until the child process terminates (case WAIT_OBJECT_0 + 1)
+ break;
+ }
+
+ default:
+ // Unexpected code
+#ifdef DEBUG_MONITOR
+ DisplayErrorMessage();
+#endif
+ exitProc = TRUE;
+ break;
+ }
+
+ }
+ } else {
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), _T("Cannot start: %s\n"), szCmdLine);
+ OutputDebugStringW(buffer);
+
+ DisplayErrorMessage();
+#endif
+ }
+
+ if (NULL != szCmdLine)
+ {
+ free(szCmdLine);
+ }
+
+ CloseHandle(waitEvent);
+ CloseHandle(h[0]);
+ CloseHandle(h[1]);
+ CloseHandle(h[2]);
+ CloseHandle(h[3]);
+ CloseHandle(h[4]);
+
+ return(dwExitCode);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Use this utility program to process correctly quotation marks in the command line
+// Arguments:
+// target - string to copy to
+// source - string to copy from
+// cpyLength - copy length
+// availSpace - size of the target buffer
+// Return :number of bytes used in target, or -1 in case of error
+/////////////////////////////////////////////////////////////////////////////////////
+int copyTo(wchar_t * target, const wchar_t * source, int cpyLength,
+ int availSpace) {
+ BOOL bSlash = FALSE;
+ int i = 0, j = 0;
+ int totCpyLength = cpyLength;
+
+#define QUOTATION_DO 0
+#define QUOTATION_DONE 1
+#define QUOTATION_NONE 2
+
+ int nQuotationMode = 0;
+ if (availSpace <= cpyLength) // = to reserve space for '\0'
+ return -1;
+
+ if ((_T('\"') == *source) && (_T('\"') == *(source + cpyLength - 1))) {
+ // Already done
+ nQuotationMode = QUOTATION_DONE;
+ } else if (wcschr(source, _T(' '))== NULL) {
+ // No reason to quotate term becase it doesn't have embedded spaces
+ nQuotationMode = QUOTATION_NONE;
+ } else {
+ // Needs to be quotated
+ nQuotationMode = QUOTATION_DO;
+ *target = _T('\"');
+ ++j;
+ }
+
+ for (; i < cpyLength; ++i, ++j) {
+ if (source[i] == _T('\\'))
+ bSlash = TRUE;
+ else
+ // Don't escape embracing quotation marks
+ if ((source[i] == _T('\"')) && !((nQuotationMode == QUOTATION_DONE) && ((i == 0) || (i == (cpyLength - 1))) )) {
+ if (!bSlash) {
+ if (j == availSpace)
+ return -1;
+ target[j] = _T('\\');
+ ++j;
+ }
+ bSlash = FALSE;
+ } else
+ bSlash = FALSE;
+
+ if (j == availSpace)
+ return -1;
+ target[j] = source[i];
+ }
+
+ if (nQuotationMode == QUOTATION_DO) {
+ if (j == availSpace)
+ return -1;
+ target[j] = _T('\"');
+ ++j;
+ }
+ return j;
+}
+
+void DisplayErrorMessage() {
+ wchar_t * lpMsgBuf;
+ FormatMessageW(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (wchar_t *) &lpMsgBuf, 0, NULL);
+ OutputDebugStringW(lpMsgBuf);
+ // Free the buffer.
+ LocalFree(lpMsgBuf);
+}
+
+//////////////////////////////// End of File //////////////////////////////////
diff --git a/core/org.eclipse.cdt.core.native/pom.xml b/core/org.eclipse.cdt.core.native/pom.xml
new file mode 100644
index 00000000000..02bc3bf9137
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/pom.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2018 Red Hat, Inc. and others.
+ This program and the accompanying materials
+ are made available under the terms of the Eclipse Public License 2.0
+ which accompanies this distribution, and is available at
+ https://www.eclipse.org/legal/epl-2.0/
+
+ SPDX-License-Identifier: EPL-2.0
+
+ Contributors:
+ Mat Booth (Red Hat) - initial implementation
+-->
+<project
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+ xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.eclipse.cdt</groupId>
+ <artifactId>cdt-parent</artifactId>
+ <version>10.0.0-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+
+ <version>6.0.0-SNAPSHOT</version>
+ <artifactId>org.eclipse.cdt.core.native</artifactId>
+ <packaging>eclipse-plugin</packaging>
+
+ <profiles>
+ <profile>
+ <id>build-native.all</id>
+ <activation>
+ <property>
+ <name>native</name>
+ <value>all</value>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>natives</id>
+ <phase>process-resources</phase>
+ <configuration>
+ <target>
+ <exec executable="make" newenvironment="false" failOnError="true" dir="./native_src">
+ <arg value="rebuild" />
+ </exec>
+ </target>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>build-native.docker</id>
+ <activation>
+ <property>
+ <name>native</name>
+ <value>docker</value>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>natives</id>
+ <phase>process-resources</phase>
+ <configuration>
+ <target>
+ <exec executable="docker" newenvironment="false" failOnError="true">
+ <!-- docker run -\-rm -t -v $(git rev-parse -\-show-toplevel):/work -w /work/$(git rev-parse -\-show-prefix) quay.io/eclipse-cdt/cdt-infra-eclipse-full:latest make -C native_src rebuild -->
+ <arg value="run" />
+ <arg value="--rm" />
+ <arg value="-t" />
+ <arg value="-v" />
+ <arg value="${project.basedir}/../..:/work" />
+ <arg value="-w" />
+ <arg value="/work/core/org.eclipse.cdt.core.native" />
+ <arg value="quay.io/eclipse-cdt/cdt-infra-eclipse-full:latest" />
+ <arg value="make" />
+ <arg value="-C" />
+ <arg value="native_src" />
+ <arg value="rebuild" />
+ </exec>
+ </target>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>

Back to the top