You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ge...@apache.org on 2005/10/05 04:20:10 UTC

svn commit: r294974 [16/25] - in /incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm: ./ jchevm/ jchevm/doc/ jchevm/etc/ jchevm/include/ jchevm/java/ jchevm/java/org/ jchevm/java/org/dellroad/ jchevm/java/org/dellroad/jc/ jchevm/java/org/dellroad...

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/jc_invoke.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/jc_invoke.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/jc_invoke.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/jc_invoke.c Tue Oct  4 19:19:16 2005
@@ -0,0 +1,876 @@
+
+/*
+ * Copyright 2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ * 
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ * $Id: jc_invoke.c,v 1.8 2005/05/19 22:52:28 archiecobbs Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <err.h>
+
+#include <popt.h>
+#include "config.h"
+#include "jni.h"
+#include "jc_invoke.h"
+
+/* Name of config files */
+#define JC_USER_CONFIG		".jc"
+#define JC_GLOBAL_CONFIG	_AC_SYSCONFDIR "/jc.conf"
+
+/* Property names */
+#define JAVA_CLASS_PATH		"java.class.path"
+#define JAVA_LIBRARY_PATH	"java.library.path"
+#define JAVA_BOOT_CLASS_PATH	"java.boot.class.path"
+
+/* JAR loader class */
+#define JC_JAR_LOADER_CLASS	"org.dellroad.jc.vm.JarLoader"
+
+enum cmdline_option {
+	OPT_CLASSPATH = 1,
+	OPT_LIBRARYPATH,
+	OPT_BOOTCLASSPATH,
+	OPT_JAR,
+	OPT_PROPERTY,
+	OPT_VERBOSE,
+	OPT_VERSION,
+	OPT_LOADLIST,
+	OPT_COMPATOPTS,
+};
+
+struct flag_subst {
+	const char	*jdk;
+	const char	*jc;
+	int		arg;
+	const char	*prop;
+};
+
+/* Verbosity options */
+static const	char *const jc_verbose[] = {
+	"class",
+	"jni",
+	"gc",
+	"Xexceptions",
+	"Xresolution",
+	"Xgen",
+	"Xjni-invoke",
+	"Xinit",
+	"Xobj",
+	NULL
+};
+
+/* Map command line option to VM args property */
+static const	char *const jc_opt2prop[] = {
+	[OPT_CLASSPATH]=	JAVA_CLASS_PATH,
+	[OPT_LIBRARYPATH]=	JAVA_LIBRARY_PATH,
+	[OPT_BOOTCLASSPATH]=	JAVA_BOOT_CLASS_PATH
+};
+
+/* Command line options */
+static const	struct poptOption jc_popt_options[] = {
+    {	"classpath",		'c', POPT_ARG_STRING, NULL, OPT_CLASSPATH,
+	"Set application class loader search path", "path" },
+    {	"bootclasspath",	'b', POPT_ARG_STRING, NULL, OPT_BOOTCLASSPATH,
+	"Set bootstrap class loader search path", "path" },
+    {	"librarypath",		'l', POPT_ARG_STRING, NULL, OPT_LIBRARYPATH,
+	"Set native library search path", "path" },
+    {	"property",		'p', POPT_ARG_STRING, NULL, OPT_PROPERTY,
+	"Set a system property", "name=value" },
+    {	"verbose",		'v', POPT_ARG_STRING, NULL, OPT_VERBOSE,
+	"Enable verbose output: "
+		" class=Class loading"
+		", jni=Native libraries"
+		", gc=Garbage collection"
+		", exceptions=Exceptions"
+		", resolution=Class resolution"
+		", gen=ELF object generation"
+		", jni-invoke=Native method calls"
+		", init=Class initialization"
+		", obj=ELF object loading"
+		".",
+		"opt1,opt2,..." },
+    {	"loadlist",		'L', POPT_ARG_STRING, NULL, OPT_LOADLIST,
+	"Record loaded ELF objects in file", "filename" },
+    {	"jar",			'j', POPT_ARG_NONE, NULL, OPT_JAR,
+	"Execute main class of JAR file", NULL },
+    {	"show-options",		'X', POPT_ARG_NONE,   NULL, OPT_COMPATOPTS,
+	"Show additional options", NULL },
+    {	"version",		'V', POPT_ARG_NONE,   NULL, OPT_VERSION,
+	"Display version and exit", NULL },
+	POPT_AUTOHELP
+	POPT_TABLEEND
+};
+static const	int jc_num_options
+			= sizeof(jc_popt_options) / sizeof(*jc_popt_options);
+
+/* JDK-compatible equivalent command line arguments */
+static const struct flag_subst jdk_flags[] = {
+    {	"-client",	NULL,		0,	NULL },
+    {	"-server",	NULL,		0,	NULL },
+    {	"-hotspot",	NULL,		0,	NULL },
+    {	"-cp",		"-c",		0,	NULL },
+    {	"-classpath",	"-c",		0,	NULL },
+    {	"-version",	"-V",		0,	NULL },
+    {	"-help",	"-?",		0,	NULL },
+    {	"-jar",		"-j",		0,	NULL },
+    {	"-mx",		NULL,		0,	"jc.heap.size" },
+    {	"-Xmx",		NULL,		0,	"jc.heap.size" },
+    {	"-ms",		NULL,		0,	"jc.heap.initial" },
+    {	"-Xms",		NULL,		0,	"jc.heap.initial" },
+    {	"-ss",		NULL,		0,	"jc.stack.default" },
+    {	"-Xss",		NULL,		0,	"jc.stack.default" },
+    {	"-Xint",	"false",	0,	"jc.object.loader.enabled" },
+    {	"-Xnogen",	"false",	0,	"jc.object.generation.enabled"},
+    {	"-Xnoln",	"false",	0,	"jc.include.line.numbers" },
+    {	"-Xobj",	"true",		0,	"jc.without.classfiles" },
+    {	"-Xrnd",	"true",		0,	"jc.resolve.native.directly" },
+    {	NULL,		NULL,		0,	NULL }
+};
+
+/* Internal functions */
+static int	jc_run(JNIEnv *env, jboolean jar, int ac, const char **av);
+static int	jc_read_options(_jc_printer *printer, poptContext pctx,
+			const char *path);
+static int	jc_process_verbose(JavaVMInitArgs *args,
+			_jc_printer *printer, const char *value);
+static int	jc_add_vm_property(JavaVMInitArgs *args, _jc_printer *printer,
+			const char *name, size_t name_len, const char *value);
+static int	jc_add_vm_arg(JavaVMInitArgs *args, _jc_printer *printer,
+			const char *option, void *extraInfo);
+static int	jc_extend_array(_jc_printer printer,
+			void *array, size_t size, int length);
+static int	jc_print(int (*printer)(FILE *, const char *, va_list),
+			FILE *stream, const char *fmt, ...);
+static int	jc_insert_opt(_jc_printer printer, int *acp,
+			char ***avp, int pos, const char *opt);
+
+/*
+ * Invoke the JC VM with the supplied command line
+ * and JNI invocation aguments.
+ */
+int
+_jc_invoke(int orig_ac, const char **orig_av,
+	int ignoreUnrecognized, _jc_printer *printer)
+{
+	JavaVMInitArgs vm_args;
+	int rtn = _JC_RETURN_ERROR;
+	poptContext pctx = NULL;
+	jboolean jar = JNI_FALSE;
+	const char *home_dir;
+	JavaVM *vm = NULL;
+	JNIEnv *env = NULL;
+	const char **params;
+	int got_classpath = 0;
+	char **av = NULL;
+	int num_params;
+	void *envp;
+	int ac = 0;
+	int op;
+	int i;
+
+	/* Copy arguments so we can modify them */
+	if ((av = malloc((orig_ac + 1) * sizeof(*av))) == NULL) {
+		jc_print(printer, stderr, "jc: %s: %s\n",
+		    "malloc", strerror(errno));
+		goto done;
+	}
+	for (ac = 0; ac < orig_ac; ac++) {
+		if ((av[ac] = strdup(orig_av[ac])) == NULL)
+			goto done;
+	}
+
+	/* Initialize VM arguments */
+	memset(&vm_args, 0, sizeof(vm_args));
+	vm_args.version = JNI_VERSION_1_2;
+	vm_args.ignoreUnrecognized = ignoreUnrecognized;
+	if (jc_add_vm_arg(&vm_args, printer, "vfprintf", printer) != JNI_OK)
+		goto done;
+	if (jc_add_vm_arg(&vm_args, printer, "abort", abort) != JNI_OK)
+		goto done;
+	if (jc_add_vm_arg(&vm_args, printer, "exit", exit) != JNI_OK)
+		goto done;
+
+	/* Allow JDK-compatible command line flags */
+	for (i = 1; i < ac && *av[i] == '-'; i++) {
+		const char *const flag = av[i];
+		int j;
+
+		/* Skip normal options */
+		for (j = 0; j < jc_num_options; j++) {
+			const struct poptOption *const op = &jc_popt_options[j];
+
+			if ((op->longName != NULL
+			      && strcmp(flag, op->longName) == 0)
+			    || (flag[1] == op->shortName && flag[2] == '\0')) {
+				if (op->argInfo != POPT_ARG_NONE)
+					i++;
+				break;
+			}
+		}
+		if (j < jc_num_options)
+			continue;
+
+		/* Handle -D flag (we have to separate & insert) */
+		if (strncmp(flag, "-D", 2) == 0) {
+			if (jc_insert_opt(printer, &ac,
+			    &av, i++, "-p") != JNI_OK)
+				goto done;
+			memmove(av[i], av[i] + 2, strlen(av[i] + 2) + 1);
+			continue;
+		}
+
+		/* Handle other substitutions */
+		for (j = 0; jdk_flags[j].jdk != NULL; j++) {
+			const struct flag_subst *const sub = &jdk_flags[j];
+
+			/* Check if flag (or prefix) matches */
+			if (strcmp(flag, sub->jdk) != 0
+			    && !(sub->prop != NULL
+			      && sub->jc == NULL
+			      && !sub->arg
+			      && strncmp(flag,
+			       sub->jdk, strlen(sub->jdk)) == 0))
+				continue;
+
+			/* A property substitution? */
+			if (sub->prop != NULL) {
+				const char *val;
+				char *buf;
+				int skip;
+
+				/* Get desired property and value */
+				if (sub->jc != NULL)
+					val = sub->jc;
+				else if (!sub->arg)
+					val = flag + strlen(sub->jdk);
+				else {
+					if (i + 1 == ac)
+						goto usage;
+					val = av[i + 1];
+				}
+
+				/* Insert command line flags to set it */
+				if (jc_insert_opt(printer, &ac,
+				    &av, i++, "-p") != JNI_OK)
+					goto done;
+				if ((buf = malloc(strlen(sub->prop)
+				    + 1 + strlen(val) + 1)) == NULL)
+					goto done;
+				strcpy(buf, sub->prop);
+				strcat(buf, "=");
+				strcat(buf, val);
+				if (jc_insert_opt(printer, &ac,
+				    &av, i++, buf) != JNI_OK) {
+					free(buf);
+					goto done;
+				}
+				free(buf);
+
+				/* Delete old command line flag */
+				skip = 1 + sub->arg;
+				memmove(av + i, av + i + skip,
+				    ((ac -= skip) - i + 1) * sizeof(*av));
+				i--;
+				break;
+			}
+
+			/* A direct subsitution? */
+			if (sub->jc != NULL) {
+
+				/* Delete old flag */
+				memmove(av + i, av + i + 1,
+				    (ac-- - i) * sizeof(*av));
+
+				/* Insert new flag */
+				if (jc_insert_opt(printer, &ac,
+				    &av, i++, sub->jc) != JNI_OK)
+					goto done;
+				if (sub->arg)
+					i++;
+				break;
+			}
+
+			/* Just ignore it */
+			memmove(av + i, av + i + 1, (ac-- - i) * sizeof(*av));
+			i--;
+			break;
+		}
+	}
+
+	/* Create option parsing context */
+	if ((pctx = poptGetContext(NULL, ac, (const char **)av,
+	    jc_popt_options, POPT_CONTEXT_POSIXMEHARDER)) == NULL) {
+		jc_print(printer, stderr, "jc: %s: %s\n",
+		    "poptGetContext", strerror(errno));
+		goto done;
+	}
+	poptSetOtherOptionHelp(pctx, "[flag ...] <classname> [param ...]");
+
+	/* Apply system-wide options */
+	if (jc_read_options(printer, pctx, JC_GLOBAL_CONFIG) != JNI_OK)
+		goto done;
+
+	/* Apply user options */
+	if ((home_dir = getenv("HOME")) != NULL) {
+		const size_t hd_len = strlen(home_dir);
+		const size_t cf_len = sizeof(JC_USER_CONFIG) - 1;
+		char *path;
+
+		/* Construct pathname to ~/.jc file */
+		if ((path = malloc(hd_len + 1 + cf_len + 1)) == NULL) {
+			jc_print(printer, stderr, "jc: %s: %s\n",
+			    "malloc", strerror(errno));
+			goto done;
+		}
+		memcpy(path, home_dir, hd_len);
+		path[hd_len] = '/';
+		memcpy(path + hd_len + 1, JC_USER_CONFIG, cf_len + 1);
+
+		/* Apply user-specific options */
+		if (jc_read_options(printer, pctx, path) != JNI_OK) {
+			free(path);
+			goto done;
+		}
+		free(path);
+	}
+
+	/* Parse command line options */
+	while ((op = poptGetNextOpt(pctx)) > 0) {
+		const char *const value = poptGetOptArg(pctx);
+
+		switch (op) {
+		case OPT_CLASSPATH:
+			got_classpath = 1;
+			/* FALLTHROUGH */
+		case OPT_LIBRARYPATH:
+		case OPT_BOOTCLASSPATH:
+		    {
+			const char *const name = jc_opt2prop[op];
+
+			if (jc_add_vm_property(&vm_args, printer,
+			    name, strlen(name), value) != JNI_OK)
+				goto done;
+			break;
+		    }
+		case OPT_JAR:
+			jar = JNI_TRUE;
+			break;
+		case OPT_PROPERTY:
+		    {
+			const char *eq;
+
+			if ((eq = strchr(value, '=')) == NULL || eq == value) {
+				jc_print(printer, stderr,
+				   "jc: invalid property option \"%s\"\n",
+				   value);
+				goto usage;
+			}
+			if (jc_add_vm_property(&vm_args, printer,
+			    value, eq - value, eq + 1) != JNI_OK)
+				goto done;
+			break;
+		    }
+		case OPT_VERBOSE:
+		    {
+			int status;
+
+			if ((status = jc_process_verbose(&vm_args,
+			    printer, value)) == JNI_EVERSION)
+				goto usage;
+			if (status != JNI_OK)
+				goto done;
+			break;
+		    }
+		case OPT_LOADLIST:
+		    {
+			FILE *loadlist;
+
+			if ((loadlist = fopen(value, "w")) == NULL) {
+				jc_print(printer, stderr, "%s: %s\n",
+				    value, strerror(errno));
+				goto done;
+			}
+			if (jc_add_vm_arg(&vm_args, printer,
+			    "-Xloadlist", loadlist) != JNI_OK)
+				goto done;
+			break;
+		    }
+		case OPT_VERSION:
+			jc_print(printer, stdout,
+			    "JC virtual machine version %s\n"
+			    "Copyright (C) 2003-2005 Archie L. Cobbs\n"
+			    "All rights reserved.\n", VERSION);
+			rtn = _JC_RETURN_NORMAL;
+			goto done;
+		case OPT_COMPATOPTS:
+			jc_print(printer, stdout, "Additional options:\n");
+			jc_print(printer, stdout, "  %-16s", "-Dfoo=bar");
+			jc_print(printer, stdout, "Same as -p foo=bar\n");
+			for (i = 0; jdk_flags[i].jdk != NULL; i++) {
+				const struct flag_subst *const sub
+				    = &jdk_flags[i];
+
+				jc_print(printer, stdout, "  %-16s", sub->jdk);
+				if (sub->prop == NULL) {
+					const char *jop = sub->jc;
+					int j;
+
+					if (sub->jc == NULL) {
+						jc_print(printer, stdout,
+						    "Ignored\n");
+						continue;
+					}
+					for (j = 0; jc_popt_options[j].longName
+					    != NULL; j++) {
+					    	const struct poptOption *const
+						  pop = &jc_popt_options[j];
+
+						if (sub->jc[1]
+						    == pop->shortName) {
+						    	jop = pop->longName;
+							break;
+						}
+					}
+					if (strcmp(jop, "-?") == 0)
+						jop = "help";
+					jc_print(printer, stdout,
+					    "Same as --%s\n", jop);
+					continue;
+				}
+				jc_print(printer, stdout,
+				    "Same as -p %s=%s\n", sub->prop,
+				    sub->jc != NULL ? sub->jc : "");
+			}
+			rtn = _JC_RETURN_NORMAL;
+			goto done;
+		}
+	}
+	if (op != -1) {
+		jc_print(printer, stderr, "jc: unknown option \"%s\": %s\n",
+		    poptBadOption(pctx, 0), poptStrerror(op));
+		goto usage;
+	}
+
+	/* If no classpath was explicitly specified, use "." as a default */
+	if (!got_classpath) {
+		if (jc_add_vm_property(&vm_args, printer, JAVA_CLASS_PATH,
+		    sizeof(JAVA_CLASS_PATH) - 1, ".") != JNI_OK)
+			goto done;
+	}
+
+	/* Get class name and parameters */
+	params = poptGetArgs(pctx);
+	for (num_params = 0; params != NULL
+	    && params[num_params] != NULL; num_params++);
+	if (num_params == 0) {
+		poptPrintHelp(pctx, stderr, 0);
+		goto done;
+	}
+
+	/* Create new VM */
+	if (JNI_CreateJavaVM(&vm, &envp, &vm_args) != JNI_OK) {
+		jc_print(printer, stderr, "jc: failed to create VM\n");
+		goto done;
+	}
+	env = (JNIEnv *)envp;
+
+	/* Free options */
+	while (vm_args.nOptions > 0)
+		free(vm_args.options[--vm_args.nOptions].optionString);
+	free(vm_args.options);
+	vm_args.options = NULL;
+
+	/* Run program */
+	if ((rtn = jc_run(env, jar, num_params, params))
+	    == _JC_RETURN_EXCEPTION)
+		(*env)->ExceptionDescribe(env);
+
+	/* Free parsing context */
+	poptFreeContext(pctx);
+	pctx = NULL;
+
+done:
+	/* Clean up and return */
+	if (vm != NULL && (*vm)->DestroyJavaVM(vm) != 0)
+		warnx("DestroyJavaVM failed");
+	if (pctx != NULL)
+		poptFreeContext(pctx);
+	while (vm_args.nOptions > 0)
+		free(vm_args.options[--vm_args.nOptions].optionString);
+	free(vm_args.options);
+	while (ac > 0)
+		free(av[--ac]);
+	return rtn;
+
+usage:
+	/* Bad command line argument */
+	jc_print(printer, stderr, "jc: try \"jc --help\" for help\n");
+	goto done;
+}
+
+/*
+ * Run the Java program.
+ */
+static int
+jc_run(JNIEnv *env, jboolean jar, int ac, const char **av)
+{
+	const char *main_class;
+	jclass string_class;
+	jarray param_array;
+	jmethodID method;
+	jclass class;
+	char *buf;
+	int i;
+
+	/* Get main class and params */
+	if (jar)
+		main_class = JC_JAR_LOADER_CLASS;
+	else {
+		main_class = av[0];
+		av++;
+		ac--;
+	}
+
+	/* Build String[] array of parameters */
+	if ((string_class = (*env)->FindClass(env, "java/lang/String")) == NULL)
+		return _JC_RETURN_EXCEPTION;
+	if ((param_array = (*env)->NewObjectArray(env,
+	      ac, string_class, NULL)) == NULL)
+		return _JC_RETURN_EXCEPTION;
+	(*env)->DeleteLocalRef(env, string_class);
+	for (i = 0; i < ac; i++) {
+		jstring string;
+
+		if ((string = (*env)->NewStringUTF(env, av[i])) == NULL)
+			return _JC_RETURN_EXCEPTION;
+		(*env)->SetObjectArrayElement(env, param_array, i, string);
+		(*env)->DeleteLocalRef(env, string);
+	}
+
+	/* Convert application main class name to internal form */
+	if ((buf = alloca(strlen(main_class) + 1)) == NULL)
+		return _JC_RETURN_ERROR;
+	strcpy(buf, main_class);
+	for (i = 0; buf[i] != '\0'; i++) {
+		if (buf[i] == '.')
+			buf[i] = '/';
+	}
+
+	/* Find the application's main class */
+	class = (*env)->FindClass(env, buf);
+	if ((*env)->ExceptionCheck(env))
+		return _JC_RETURN_EXCEPTION;
+
+	/* Invoke main() */
+	if ((method = (*env)->GetStaticMethodID(env, class,
+	    "main", "([Ljava/lang/String;)V")) == NULL)
+		return _JC_RETURN_EXCEPTION;
+	(*env)->CallStaticVoidMethod(env, class, method, param_array);
+	(*env)->DeleteLocalRef(env, param_array);
+	(*env)->DeleteLocalRef(env, class);
+	if ((*env)->ExceptionCheck(env))
+		return _JC_RETURN_EXCEPTION;
+
+	/* Done */
+	return _JC_RETURN_NORMAL;
+}
+
+/* 
+ * Read command line arguments from a file and prepend them
+ * to the supplied parsing context.
+ */
+static int
+jc_read_options(_jc_printer *printer, poptContext pctx, const char *path)
+{
+	char **options = NULL;
+	int num_options = 0;
+	int status = JNI_ERR;
+	char line[1024];
+	int line_num;
+	FILE *fp;
+	int r;
+
+	/* Open file */
+	if ((fp = fopen(path, "r")) == NULL) {
+		if (errno == ENOENT)		/* if none found, nevermind */
+			return JNI_OK;
+		jc_print(printer, stderr,
+		    "jc: %s: %s\n", path, strerror(errno));
+		goto done;
+	}
+
+	/* Read options */
+	for (line_num = 1; fgets(line, sizeof(line), fp) != NULL; line_num++) {
+		size_t len = strlen(line);
+		char *opt;
+		char *s;
+
+		/* Check for line too long */
+		if (line[len - 1] != '\n') {
+			jc_print(printer, stderr,
+			    "jc: %s: line too long (line %d)\n",
+			    path, line_num);
+			goto done;
+		}
+
+		/* Trim leading whitespace */
+		for (s = line; isspace(*s); s++, len--);
+
+		/* Trim trailing whitespace */
+		while (len > 0 && isspace(s[len - 1]))
+			len--;
+		s[len] = '\0';
+
+		/* Ignore blank lines and # comment lines */
+		if (*s == '#' || *s == '\0')
+			continue;
+
+		/* Extend option list */
+		if (jc_extend_array(printer, &options,
+		    sizeof(*options), num_options) != JNI_OK)
+			goto done;
+
+		/* Prepend '--' to the option */
+		if ((opt = malloc(2 + len + 1)) == NULL) {
+			jc_print(printer, stderr,
+			    "jc: %s: %s\n", "malloc", strerror(errno));
+			goto done;
+		}
+		opt[0] = '-';
+		opt[1] = '-';
+		memcpy(opt + 2, s, len);
+		opt[2 + len] = '\0';
+
+		/* Add option to the list */
+		options[num_options++] = opt;
+	}
+
+	/* Terminate option list with a NULL */
+	if (jc_extend_array(printer, &options,
+	    sizeof(*options), num_options) != JNI_OK)
+		goto done;
+	options[num_options] = NULL;
+
+	/* Insert options into parsing context */
+	if (num_options > 0
+	    && (r = poptStuffArgs(pctx, (const char **)options)) < 0) {
+		jc_print(printer, stderr, "jc: %s: %s\n",
+		    "poptStuffArgs", poptStrerror(r));
+		goto done;
+	}
+
+	/* OK */
+	status = JNI_OK;
+
+done:
+	/* Clean up and return */
+	if (fp != NULL)
+		fclose(fp);
+	while (num_options > 0)
+		free(options[--num_options]);
+	free(options);
+	return status;
+}
+
+/*
+ * Process verbose command line options.
+ */
+static int
+jc_process_verbose(JavaVMInitArgs *args,
+	_jc_printer *printer, const char *value)
+{
+	int verbose_bits = 0;
+	const char *s;
+	const char *next;
+	size_t len;
+	char *buf;
+	int first;
+	int i;
+
+	/* Scan verbose options */
+	for (s = value; *s != '\0'; s = next) {
+		const char *vmopt;
+		const char *c;
+		size_t len;
+
+		/* Parse out next item, but skip empties */
+		if ((c = strchr(s, ',')) == NULL)
+			len = strlen(s);
+		else
+			len = c - s;
+		for (next = s + len; *next == ','; next++);
+		if (len == 0)
+			continue;
+
+		/* Find the named verbosity flag */
+		for (i = 0; jc_verbose[i] != NULL; i++) {
+
+			/* Check for match, possibly without 'X' prefix */
+			vmopt = jc_verbose[i];
+			if ((strncmp(s, vmopt, len) == 0 && vmopt[len] == '\0')
+			    || (*vmopt == 'X' && strncmp(s, vmopt + 1, len) == 0
+			      && vmopt[len + 1] == '\0'))
+				break;
+		}
+		if (jc_verbose[i] == NULL) {
+			jc_print(printer, stderr,
+			    "jc: unknown verbose flag \"%.*s\"\n", len, s);
+			return JNI_EVERSION;		/* kludge */
+		}
+
+		/* Add the corresponding VM flag */
+		verbose_bits |= (1 << i);
+	}
+
+	/* None specified? */
+	if (verbose_bits == 0)
+		return JNI_OK;
+
+	/* Create VM argument with the supplied verbose flags */
+	for (len = i = 0; jc_verbose[i] != NULL; i++) {
+		if ((verbose_bits & (1 << i)) != 0)
+			len += 1 + strlen(jc_verbose[i]);
+	}
+	len += strlen("-verbose") + 1;
+	if ((buf = alloca(len)) == NULL) {
+		jc_print(printer, stderr,
+		    "jc: %s: %s\n", "alloca", strerror(errno));
+		return JNI_ERR;
+	}
+	sprintf(buf, "-verbose");
+	for (first = JNI_TRUE, i = 0; jc_verbose[i] != NULL; i++) {
+		if ((verbose_bits & (1 << i)) != 0) {
+			sprintf(buf + strlen(buf), "%c%s",
+			    first ? ':' : ',', jc_verbose[i]);
+			first = JNI_FALSE;
+		}
+	}
+
+	/* Add VM option flag */
+	if (jc_add_vm_arg(args, printer, buf, NULL) != JNI_OK)
+		return JNI_ERR;
+
+	/* Done */
+	return JNI_OK;
+}
+
+/*
+ * Add a new property setting to the VM args.
+ */
+static int
+jc_add_vm_property(JavaVMInitArgs *args, _jc_printer *printer,
+        const char *name, size_t name_len, const char *value)
+{
+	char *option;
+
+	if ((option = alloca(2 + name_len + 1 + strlen(value) + 1)) == NULL) {
+		jc_print(printer, stderr,
+		    "jc: %s: %s\n", "alloca", strerror(errno));
+		return JNI_ERR;
+	}
+	strcpy(option, "-D");
+	memcpy(option + 2, name, name_len);
+	option[2 + name_len] = '=';
+	strcpy(option + 2 + name_len + 1, value);
+	return jc_add_vm_arg(args, printer, option, NULL);
+}
+
+/*
+ * Add a new JavaVM argument.
+ */
+static int
+jc_add_vm_arg(JavaVMInitArgs *args, _jc_printer *printer,
+	const char *option, void *extraInfo)
+{
+	/* Extend array */
+	if (jc_extend_array(printer, &args->options,
+	    sizeof(*args->options), args->nOptions) != JNI_OK)
+		return JNI_ERR;
+
+	/* Fill in new option */
+	memset(&args->options[args->nOptions],
+	    0, sizeof(args->options[args->nOptions]));
+	if ((args->options[args->nOptions].optionString
+	    = strdup(option)) == NULL) {
+		jc_print(printer, stderr,
+		    "jc: %s: %s\n", "strdup", strerror(errno));
+		return JNI_ERR;
+	}
+	args->options[args->nOptions].extraInfo = extraInfo;
+
+	/* Done */
+	args->nOptions++;
+	return JNI_OK;
+}
+
+/*
+ * Extend an array of somethings by one element.
+ */
+static int
+jc_extend_array(_jc_printer printer, void *arrayp, size_t size, int length)
+{
+	void *array = *(void **)arrayp;
+
+	/* Extend array */
+	if ((array = realloc(array, (length + 1) * size)) == NULL) {
+		jc_print(printer, stderr,
+		    "jc: %s: %s\n", "realloc", strerror(errno));
+		return JNI_ERR;
+	}
+
+	/* Done */
+	*(void **)arrayp = array;
+	return JNI_OK;
+}
+
+/*
+ * Print something using the supplied printer and stream.
+ */
+static int
+jc_print(_jc_printer *printer, FILE *stream, const char *fmt, ...)
+{
+	va_list args;
+	int r;
+
+	va_start(args, fmt);
+	r = (*printer)(stream, fmt, args);
+	va_end(args);
+	return r;
+}
+
+/*
+ * Insert a command line flag.
+ */
+static int
+jc_insert_opt(_jc_printer printer, int *acp,
+	char ***avp, int pos, const char *opt)
+{
+	/* Resize array */
+	if (jc_extend_array(printer, avp, sizeof(**avp), *acp + 1) != JNI_OK)
+		return JNI_ERR;
+
+	/* Shift elements to make room */
+	memmove(*avp + pos + 1, *avp + pos, (++(*acp) - pos) * sizeof(**avp));
+
+	/* Initialize new element */
+	(*avp)[pos] = strdup(opt);
+	return JNI_OK;
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/jni_invoke.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/jni_invoke.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/jni_invoke.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/jni_invoke.c Tue Oct  4 19:19:16 2005
@@ -0,0 +1,341 @@
+
+/*
+ * Copyright 2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ * 
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ * $Id: jni_invoke.c,v 1.4 2005/03/16 15:31:12 archiecobbs Exp $
+ */
+
+#include "libjc.h"
+
+/*
+ * Invocation methods
+ */
+static jint	DestroyJavaVM(JavaVM *vm);
+static jint	AttachCurrentThread(JavaVM *vm, void **envp, void *args);
+static jint	AttachCurrentThreadAsDaemon(JavaVM *vm,
+			void **envp, void *args);
+static jint	AttachCurrentThreadInternal(JavaVM *vm,
+			void **envp, void *args, jboolean daemon);
+static jint	DetachCurrentThread(JavaVM *vm);
+static jint	GetEnv(JavaVM *vm, void **envp, jint interface_id);
+
+/* JNI invocation interface table */
+const struct JNIInvokeInterface _jc_invoke_interface = {
+	NULL,
+	NULL,
+	NULL,
+	DestroyJavaVM,
+	AttachCurrentThread,
+	DetachCurrentThread,
+	GetEnv,
+	AttachCurrentThreadAsDaemon
+};
+
+/* Linked list of all VMs, protected by a mutex */
+static LIST_HEAD(, _jc_jvm)	_jc_vms_list
+				    = LIST_HEAD_INITIALIZER(&_jc_vms_list);
+static pthread_mutex_t		_jc_vms_mutex = PTHREAD_MUTEX_INITIALIZER;
+#ifndef NDEBUG
+static _jc_env			*_jc_vms_mutex_owner;
+#endif
+
+/* Signal handler state */
+static jboolean			_jc_signals_initialized;
+
+/*
+ * Get default setup for creating a new VM.
+ */
+jint
+JNI_GetDefaultJavaVMInitArgs(void *_vm_args)
+{
+	JavaVMInitArgs *vm_args = (JavaVMInitArgs *)_vm_args;
+	int error;
+
+	/* Initialize */
+	if ((error = _jc_init()) != JNI_OK)
+		return error;
+
+	/* We only communicate using the 1.2 interface version */
+	if (vm_args->version != JNI_VERSION_1_2)
+		return JNI_EVERSION;
+
+	/* Done */
+	return JNI_OK;
+}
+
+/*
+ * Get a list of all VMs that exist.
+ */
+jint
+JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs)
+{
+	_jc_jvm *vm;
+	jint error;
+	jsize count;
+
+	/* Initialize */
+	if ((error = _jc_init()) != JNI_OK)
+		return error;
+
+	/* Acquire lock on the VM list */
+	_JC_MUTEX_LOCK(NULL, _jc_vms_mutex);
+
+	/* Add entries */
+	count = 0;
+	LIST_FOREACH(vm, &_jc_vms_list, link) {
+		if (count >= bufLen)
+			break;
+		vmBuf[count] = _JC_JVM2JNI(vm);
+		count++;
+	}
+	*nVMs = count;
+
+	/* Release lock on the VM list */
+	_JC_MUTEX_UNLOCK(NULL, _jc_vms_mutex);
+
+	/* Done */
+	return JNI_OK;
+}
+
+/*
+ * Create a new Java VM.
+ */
+jint
+JNI_CreateJavaVM(JavaVM **jvmp, void **envp, void *args)
+{
+	_jc_env *env;
+	_jc_jvm *vm;
+	int status;
+
+	/* Do one-time initialization */
+	if ((status = _jc_init()) != JNI_OK)
+		return status;
+
+	/* Initialize signals when creating the first VM */
+	_JC_MUTEX_LOCK(NULL, _jc_vms_mutex);
+	if (!_jc_signals_initialized && _jc_init_signals() == JNI_OK)
+		_jc_signals_initialized = JNI_TRUE;
+	_JC_MUTEX_UNLOCK(NULL, _jc_vms_mutex);
+	if (!_jc_signals_initialized)
+		goto fail;
+
+	/* Create VM */
+	if ((status = _jc_create_vm(args, &vm, &env)) != JNI_OK)
+		goto fail;
+	VERBOSE(JNI, vm, "JNI_CreateJavaVM invoked");
+
+	/* Add VM to global VM list */
+	_JC_MUTEX_LOCK(NULL, _jc_vms_mutex);
+	LIST_INSERT_HEAD(&_jc_vms_list, vm, link);
+	_JC_MUTEX_UNLOCK(NULL, _jc_vms_mutex);
+
+	/* Returning now to native code */
+	_jc_stopping_java(env, NULL);
+
+	/* Done */
+	*envp = _JC_ENV2JNI(env);
+	*jvmp = _JC_JVM2JNI(vm);
+	return JNI_OK;
+
+fail:
+	/* Clean up after failure */
+	_JC_ASSERT(status != JNI_OK);
+	_JC_MUTEX_LOCK(NULL, _jc_vms_mutex);
+	if (LIST_EMPTY(&_jc_vms_list) && _jc_signals_initialized) {
+		_jc_restore_signals();
+		_jc_signals_initialized = JNI_FALSE;
+	}
+	_JC_MUTEX_UNLOCK(NULL, _jc_vms_mutex);
+	return status;
+}
+
+/*
+ * Destroy a VM.
+ */
+static jint
+DestroyJavaVM(JavaVM *jvm)
+{
+	_jc_jvm *vm = _JC_JNI2JVM(jvm);
+	_jc_env *env = _jc_get_current_env();
+
+	/* This thread must be attached to the jvm */
+	if (env == NULL || env->vm != vm)
+		return JNI_ERR;
+
+	/* Enter java mode */
+	_jc_resuming_java(env);
+	VERBOSE(JNI, vm, "JNI_DestroyJavaVM invoked");
+
+	/* Kill all other threads */
+	_jc_thread_shutdown(&env);
+
+	/* Remove VM from the global list and restore signals after last VM */
+	_JC_MUTEX_LOCK(NULL, _jc_vms_mutex);
+	LIST_REMOVE(vm, link);
+	_JC_ASSERT(_jc_signals_initialized);
+	if (LIST_EMPTY(&_jc_vms_list)) {
+		_jc_restore_signals();
+		_jc_signals_initialized = JNI_FALSE;
+	}
+	_JC_MUTEX_UNLOCK(NULL, _jc_vms_mutex);
+
+	/* Free VM */
+	VERBOSE(JNI, vm, "JNI_DestroyJavaVM: destroying VM");
+	_jc_free_vm(&vm);
+
+	/* Done */
+	return JNI_OK;
+}
+
+/*
+ * Attach the current thread to the VM as a user thread.
+ */
+static jint
+AttachCurrentThread(JavaVM *jvm, void **envp, void *args)
+{
+	return AttachCurrentThreadInternal(jvm, envp, args, JNI_FALSE);
+}
+
+/*
+ * Attach the current thread to the VM as a daemon thread.
+ */
+static jint
+AttachCurrentThreadAsDaemon(JavaVM *jvm, void **envp, void *args)
+{
+	return AttachCurrentThreadInternal(jvm, envp, args, JNI_TRUE);
+}
+
+/*
+ * Attach the current thread to the VM.
+ */
+static jint
+AttachCurrentThreadInternal(JavaVM *jvm,
+	void **envp, void *_args, jboolean daemon)
+{
+	_jc_jvm *const vm = _JC_JNI2JVM(jvm);
+	JavaVMAttachArgs *const args = _args;
+	_jc_ex_info einfo;
+	_jc_env *env;
+
+	/* We only communicate using the 1.2 interface version */
+	if (args != NULL && args->version != JNI_VERSION_1_2)
+		return JNI_EVERSION;
+
+	/* If thread is already attached, just return its pointer */
+	if ((env = _jc_get_current_env()) != NULL) {
+		*envp = _JC_ENV2JNI(env);
+		return JNI_OK;
+	}
+
+	/* Create and attach a new thread structure to the current thread */
+	_JC_MUTEX_LOCK(NULL, vm->mutex);
+	env = _jc_attach_thread(vm, &einfo);
+	_JC_MUTEX_UNLOCK(NULL, vm->mutex);
+	if (env == NULL) {
+		_jc_eprintf(vm, "%s: %s: %s\n", __FUNCTION__,
+		    _jc_vmex_names[einfo.num], einfo.msg);
+		return JNI_ERR;
+	}
+
+	/* Sanity check group */
+	_JC_ASSERT(args == NULL || args->group == NULL
+	    || _jc_subclass_of(*args->group, vm->boot.types.ThreadGroup));
+
+	/* Create java.lang.Thread instance */
+	if (_jc_thread_create_instance(env,
+	    (args != NULL && args->group != NULL) ?
+	      *args->group : vm->boot.objects.systemThreadGroup,
+	    (args != NULL && args->name != NULL) ? args->name : NULL,
+	    vm->threads.java_prio_norm, daemon) != JNI_OK)
+		goto fail;
+
+	/* Returning to native code */
+	_jc_stopping_java(env, NULL);
+
+	/* Done */
+	*envp = _JC_ENV2JNI(env);
+	return JNI_OK;
+
+fail:
+	/* Clean up and return error */
+	_JC_MUTEX_LOCK(NULL, vm->mutex);
+	_jc_detach_thread(&env);
+	_JC_MUTEX_UNLOCK(NULL, vm->mutex);
+	return JNI_ERR;
+}
+
+/*
+ * Detach the current thread from the VM.
+ */
+static jint
+DetachCurrentThread(JavaVM *jvm)
+{
+	_jc_jvm *const vm = _JC_JNI2JVM(jvm);
+	_jc_env *env = _jc_get_current_env();
+
+	/* This thread must be attached to the jvm */
+	if (env == NULL || env->vm != vm)
+		return JNI_ERR;
+
+	/* Go un-native */
+	_jc_resuming_java(env);
+
+	/* Grab global mutex */
+	_JC_MUTEX_LOCK(NULL, vm->mutex);
+
+	/* Detach this thread */
+	_jc_detach_thread(&env);
+
+	/* Unlock global mutex */
+	_JC_MUTEX_UNLOCK(NULL, vm->mutex);
+
+	/* Done */
+	return JNI_OK;
+}
+
+/*
+ * Get the JNI environment corresponding to the current thread.
+ */
+static jint
+GetEnv(JavaVM *jvm, void **envp, jint interface_id)
+{
+	_jc_jvm *const vm = _JC_JNI2JVM(jvm);
+	_jc_env *env;
+	int error;
+
+	/* Initialize */
+	if ((error = _jc_init()) != JNI_OK) {
+		*envp = NULL;
+		return JNI_EDETACHED;
+	}
+
+	/* Check if this thread is attached */
+	if ((env = _jc_get_current_env()) == NULL || env->vm != vm) {
+		*envp = NULL;
+		return JNI_EDETACHED;
+	}
+
+	/* Check JNI version */
+	if (interface_id != JNI_VERSION_1_2) {
+		*envp = NULL;
+		return JNI_EVERSION;
+	}
+
+	/* OK */
+	*envp = _JC_ENV2JNI(env);
+	return JNI_OK;
+}
+