| /* --COPYRIGHT--,EPL |
| * Copyright (c) 2008-2019 Texas Instruments Incorporated |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Texas Instruments - initial implementation |
| * |
| * --/COPYRIGHT--*/ |
| /* |
| * ======== xs.c ======== |
| * This utility allows running XDC scripts outside of any object model. |
| * |
| * Usage: xs [-h] [-D<name>=<value>] [--xdcpath <xdcpath>] |
| * [--cp <classpath>] [--lp <java library path>] [-i] [--X<JVM opt>] |
| * [-m <module> | -[fc] <script> | <package> [args]] |
| * |
| * xs sets environment['xdc.root'] to the following values in order of |
| * preference: 1) -Dxdc.root option passed on the command line, 2) the |
| * directory containing this executable. |
| * |
| * The availiable options are partitioned into two groups: internal and |
| * external options. |
| * |
| * Internal options are subject to change and are intended for internal |
| * use only. Internal options always begin with '--'. |
| * |
| * External options are documented and must not be changed without a |
| * means for achieving backward compatibility with existing uses of xs. |
| * External options never begin with '--'. |
| * |
| * xs Options (<opts>): |
| * --xdcpath <xdcpath> add <xdcpath> to the package path |
| * --cp <cpath> adds <cpath> to automatically computed Java classpath |
| * --d turn on internal debug output. May be repeated; |
| * more --d's generates more optput. |
| * --X<opt> this option is passed directly to SUN JVM (minus |
| * one leading '-') |
| * |
| * --j <jar> add <jar> to classpath |
| * |
| * -g[=<opts>] run in "GUI debug" mode and pass optional <opts> to |
| * the debugger. If no options are passed, then the |
| * debugger stops at the first line of the specified |
| * script. Supported <opts> options: |
| * 'i' set initial breakpoint at start of the xs |
| * startup script, tconfini.tcf |
| * |
| * -i run in interactive mode |
| * -p <path> add <path> to list of directories to search for |
| * xs "system" files. This option allows platform |
| * developers to add a directory containing platform |
| * definitions not provided by TI. |
| * |
| * -D<name>=<val> add the "name=value" definition to the TCOM |
| * environment |
| * |
| * -v print the version and exit |
| * |
| * JavaScript Shell Options (in addition to -v passed to Shell when -i is |
| * passed to this executable): |
| * -[fc] <file> execute the script in the file <file> |
| * -m <module> execute the function 'main' in the module <module> |
| * |
| * Examples: |
| * Running a script with arguments: |
| * xs -f foo.xs hello world |
| * |
| * Running main() function in capsule in package pkg: |
| * xs -c pkg/cap.xs hello world |
| * |
| * Running main() function in module Mod in package pkg: |
| * xs -m pkg.Mod hello world |
| * |
| * Running main() function in module Main in package pkg: |
| * xs pkg |
| */ |
| #define GT_TRACE 1 |
| |
| #include <xdc/std.h> |
| #include <tcf.h> |
| #include <xdc/services/host/lib/gt.h> |
| #include <xdc/services/host/lib/xutl.h> |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stdarg.h> |
| #include <string.h> |
| |
| #include <time.h> |
| #include <sys/timeb.h> |
| |
| #if defined(xdc_target__os_Windows) |
| #include <windows.h> /* GetModuleFileName, GetFileAttributes */ |
| #define DIRSTR "\\" /* directory separator character */ |
| #define CALLBACK __stdcall /* Win32 callbacks use pascal conv */ |
| #define E64JRE "\n %s can't find a 64-bit JVM. Upgrade to CCS 9.0 or newer, or\ |
| install XDCTools with JVM, or set the environment variable XDCTOOLS_JAVA_HOME\ |
| to a 64-bit JVM, for example \"C:/Program Files/Java/jdk1.8.0_121/jre\".\n" |
| #else |
| #define DIRSTR "/" |
| #define CALLBACK |
| #endif |
| |
| #if defined(xdc_target__os_Linux) || defined(xdc_target__os_MacOS) |
| #include <unistd.h> |
| #endif |
| |
| #define XDCSHELF "packages" DIRSTR "xdc" DIRSTR "shelf" DIRSTR "java" |
| |
| #define MAXJARS 32 /* maximum # of jars in class path */ |
| #define MAXLINE 512 /* maximum interactive input line */ |
| #define MAXNAME 512 /* maximum file name length */ |
| #define MAXNUMPATH 16 /* max # of directories to search */ |
| #define MAXOPTIONS 64 /* max options for JVM */ |
| |
| static Void error(Int exitStatus, String format, ...); |
| static String getCanonicalProgName(String argv0); |
| static String getLine(String prev); |
| static Bool getProgPath(Char *pathBuf); |
| static Void init(Void); |
| static Int initPathTab(String pathTab[]); |
| static void CALLBACK jvmAbort(void); |
| static void CALLBACK jvmExit(int status); |
| static Void printVersion(Void); |
| static Void printTime(String msg, struct timeb *t); |
| static Void usage(Void); |
| |
| static String jarTab[MAXJARS + 1] = { |
| "js.jar", /* rhino JavaScript interpreter */ |
| "config.jar", /* configuration model */ |
| "antlr.jar", /* antlr parser used by iliad */ |
| NULL /* NULL termination required */ |
| }; |
| static Int jarTabLen = 3; |
| |
| static String jvmOptions[MAXOPTIONS + 1] = { |
| "-Xverify:none", /* disable *all* byte-code verification; |
| * this improves JVM startup time without |
| * affecting Java semantics |
| */ |
| NULL |
| }; |
| static Int nOpts = 1; |
| |
| static String pathTab[MAXNUMPATH + 1] = {NULL}; |
| static Int pathTabLen = 0; |
| |
| static Int dflag = 0; |
| static Bool iflag = FALSE; |
| static Bool mflag = FALSE; |
| static String progName = ""; |
| |
| /* |
| * ======== main ======== |
| */ |
| int main(Int argc, String argv[]) |
| { |
| Int i; |
| String errorMsg; |
| Int status = TCF_EOK; |
| TCF_Attrs attrs = TCF_ATTRS; |
| TCF_Handle tcf; |
| Bool xsFlags; |
| |
| /* benchmark trace for Shell activated by -Dxdc.traceGroups="bench" */ |
| Bool traceFlag; |
| String envtrace = NULL; |
| String xdcpath = NULL; |
| String xdcroot = NULL; |
| String progPath; |
| |
| /* nargv is a list of arguments passed to Shell */ |
| String *nargv; |
| String initScriptPath = NULL; |
| String xsRelativePath = "/packages/xdc/xs.js"; |
| Int nargc = 0; |
| String err; |
| |
| struct timeb startTime; |
| |
| /* arguments for processing the optional ini file */ |
| static String iniFileName = "/etc/xs.ini"; |
| static Char iniFileOption[MAXNAME + 3] = "-@"; |
| static String iniFilePath = &iniFileOption[2]; |
| static String iniFileOptions[] = { |
| iniFileOption |
| }; |
| |
| /* We catch this time first, in case the benchmark trace is on */ |
| ftime(&startTime); |
| |
| progName = argv[0]; |
| XUTL_init(); |
| |
| /* construct the ini file name */ |
| if (getProgPath(iniFilePath)) { |
| strcat(iniFilePath, iniFileName); |
| |
| /* if the ini file exists, add it to the command line */ |
| if (XUTL_isFile(iniFilePath)) { |
| argv = XUTL_insertArgv(1, iniFileOptions, 1, argc, argv, &argc, &err); |
| if (argv == NULL) { |
| fprintf(stderr, "%s: unable to process ini file: %s\n\n", |
| progName, err); |
| exit(1); |
| } |
| } |
| } |
| |
| /* expand any @file options */ |
| argv = XUTL_expandArgv(argc, argv, &argc, &err); |
| if (argv == NULL) { |
| fprintf(stderr, "%s: unable to expand command line arguments: %s\n\n", |
| progName, err); |
| exit(1); |
| } |
| |
| init(); |
| |
| /* The maximum number of pointers we may need is all of argv and three |
| * additional ones. |
| */ |
| nargv = (String *)malloc(sizeof(String) * (argc + 3)); |
| if (nargv == NULL) { |
| error(1, "out of memory"); |
| } |
| |
| /* The path to the directory with this executable is needed to find |
| * the initial xs.js script and to pass xdc.root, which is required for |
| * the initial script. |
| */ |
| progPath = (String)malloc(MAXNAME + 1); |
| if (progPath == NULL) { |
| error(1, "out of memory"); |
| } |
| getProgPath(progPath); |
| |
| #if defined(xdc_target__os_Windows) |
| String home = getenv("XDCTOOLS_JAVA_HOME"); |
| if (home) { |
| if (strstr(home, "ccsv7") || strstr(home, "ccsv8")) { |
| Char jrepath[MAXNAME]; |
| strcpy(jrepath, progPath); |
| if (strlen(progPath) + 5 > MAXNAME) { |
| error(1, "The path %s/jre is too long.\n", progPath); |
| } |
| strcat(jrepath, "/jre"); |
| if (GetFileAttributes(jrepath) == INVALID_FILE_ATTRIBUTES) { |
| error(1, E64JRE, progPath); |
| } |
| } |
| } |
| #endif |
| |
| /* turn on/off trace */ |
| GT_set("TC-016,GD-01"); |
| |
| /* initialize search path table and the root directory */ |
| pathTabLen = initPathTab(pathTab); |
| attrs.pathTab = pathTab; |
| attrs.rootDir = pathTab[0]; |
| |
| attrs.jvmOpts = jvmOptions; |
| attrs.jarTab = jarTab; |
| |
| attrs.jvmExit = jvmExit; |
| attrs.jvmAbort = jvmAbort; |
| |
| /* parse command line args */ |
| argv += 1; /* skip over xs executable name */ |
| argc -= 1; |
| xsFlags = FALSE; |
| traceFlag = FALSE; |
| |
| if (argc == 0) { |
| usage(); |
| return (0); |
| } |
| |
| while (argc > 0 && argv[0][0] == '-' && !xsFlags) { |
| switch (argv[0][1]) { |
| |
| case 'h': { |
| usage(); |
| return (0); |
| break; |
| } |
| |
| case 'v': { |
| printVersion(); |
| return(0); |
| break; |
| } |
| case 'p': { |
| /* add argv[1] to pathTab array (used to locate files) */ |
| if (argc <= 1) { |
| usage(); |
| exit(1); |
| } |
| if (pathTabLen >= MAXNUMPATH) { |
| error(0, "error: more than %d path names specified\n\n", |
| MAXNUMPATH); |
| for (i = 0; i < pathTabLen; i++) { |
| fprintf(stderr, " %d\t%s\n", i, pathTab[i]); |
| } |
| exit(1); |
| } |
| pathTab[pathTabLen++] = argv[1]; |
| pathTab[pathTabLen] = NULL; |
| argv += 2; |
| argc -= 2; |
| break; |
| } |
| |
| case 'D': { |
| /* If xdc.root is passed, we will not add our own */ |
| if (strncmp(argv[0], "-Dxdc.root", 10) == 0) { |
| xdcroot = (String)malloc(strlen(argv[0]) - 10); |
| if (xdcroot == NULL) { |
| error(1, "out of memory"); |
| } |
| strcpy(xdcroot, &argv[0][11]); |
| } |
| |
| /* If xdc.traceGroups is passed, and 'bench' is in it, the |
| * trace option is passed to Shell. |
| */ |
| if (strncmp(argv[0], "-Dxdc.traceGroups", 17) == 0) { |
| if (strstr(argv[0] + 17, "bench") != NULL) { |
| traceFlag = TRUE; |
| } |
| } |
| |
| jvmOptions[nOpts++] = argv[0]; |
| if (nOpts >= MAXOPTIONS) { |
| error(1, "too many options for JVM\n\n"); |
| } |
| argv += 1; |
| argc -= 1; |
| break; |
| } |
| |
| case 'g': { |
| attrs.gflag = TRUE; |
| if (strncmp(argv[0], "-g=", 3) == 0) { |
| attrs.gopts = &(argv[0][3]); |
| } |
| argv += 1; |
| argc -= 1; |
| break; |
| } |
| |
| case 'i': { |
| iflag = TRUE; |
| argv += 1; |
| argc -= 1; |
| break; |
| } |
| case '-' : { |
| switch (argv[0][2]) { |
| |
| case 'h': { |
| if (strncmp(argv[0] + 2, "help", 4) == 0) { |
| usage(); |
| return (0); |
| } |
| else { |
| usage(); |
| error(1, "illegal option %s\n\n", argv[0]); |
| } |
| break; |
| } |
| |
| case 'j': { |
| if (argc <= 1) { |
| usage(); |
| exit(1); |
| } |
| if (jarTabLen >= MAXJARS) { |
| error(1, "too many jar files specified\n"); |
| } |
| jarTab[jarTabLen++] = argv[1]; |
| jarTab[jarTabLen] = NULL; |
| argv += 2; |
| argc -= 2; |
| break; |
| } |
| |
| case 'v': { |
| if (strncmp(argv[0] + 2, "version", 7) == 0) { |
| printVersion(); |
| return(0); |
| break; |
| } |
| else { |
| printf("illegal option %s\n\n", argv[0]); |
| usage(); |
| exit(1); |
| } |
| } |
| |
| case 'X': { |
| jvmOptions[nOpts++] = argv[0] + 1; /* skip extra '-' */ |
| if (nOpts >= MAXOPTIONS) { |
| error(1, "too many options for JVM\n"); |
| } |
| argv += 1; |
| argc -= 1; |
| break; |
| } |
| |
| /* --xdcpath (or deprecated --xp) specifies XDCPATH */ |
| case 'x': { |
| Int xpSize = 0; |
| |
| if (strcmp(argv[0] + 2, "xdcpath") == 0 || |
| strcmp(argv[0] + 2, "xp") == 0) { |
| if (argc > 1) { |
| xdcpath = argv[1]; |
| argv += 2; |
| argc -= 2; |
| } |
| else { |
| usage(); |
| error(1, "incomplete option %s\n\n", argv[0]); |
| } |
| break; |
| } |
| |
| if (strncmp(argv[0], "--xdcpath=", 10) == 0) { |
| xpSize = 10; |
| } |
| else if (strncmp(argv[0], "--xp=", 5) == 0) { |
| xpSize = 5; |
| } |
| else { |
| usage(); |
| error(1, "illegal option %s\n", argv[0]); |
| break; |
| } |
| |
| xdcpath = argv[0] + xpSize; |
| argv += 1; |
| argc -= 1; |
| break; |
| } |
| |
| case 'c': { |
| if (argv[0][3] != 'p') { |
| usage(); |
| error(1, "illegal option %s\n", argv[0]); |
| } |
| if (argc <= 1) { |
| usage(); |
| error(1, "incomplete option %s\n", argv[0]); |
| } |
| attrs.classPath = argv[1]; |
| argv += 2; |
| argc -= 2; |
| break; |
| } |
| case 'd': { |
| dflag++; |
| GT_set("TC+016,GD+0123"); |
| argv += 1; |
| argc -= 1; |
| break; |
| } |
| default: |
| printf("illegal option %s\n", argv[0]); |
| usage(); |
| return (0); |
| break; |
| } |
| break; |
| } |
| case 'm': |
| case 'c': |
| case 'f': { |
| /* Any of these start xs.js arguments, which means that |
| * xs.c and JVM arguments all have to show up before these. |
| */ |
| xsFlags = TRUE; |
| break; |
| } |
| |
| default: { |
| printf("illegal option %s\n", argv[0]); |
| usage(); |
| return (0); |
| break; |
| } |
| } |
| |
| } |
| |
| /* Pass any command line specified xdcpath to JVM. If XDCPATH is not |
| * passed to JVM here, TCF_create will check if XDCPATH is defined in |
| * the environment and, if found, pass it to JVM. |
| */ |
| if (xdcpath != NULL) { |
| String def; |
| Int k, l; |
| |
| /* Replace the consecutive semicolons by single semicolon */ |
| for (k = 0, l = 0; xdcpath[k] != '\0'; k++) { |
| if (!((xdcpath[k] == ';') && (xdcpath[k+1] == ';'))) { |
| xdcpath[l] = xdcpath[k]; |
| l++; |
| } |
| } |
| xdcpath[l] = '\0'; |
| |
| /* +16 for "-DXDCPATH=" */ |
| def = (String)malloc(strlen(xdcpath) + 16); |
| if (def == NULL) { |
| error(1, "out of memory"); |
| } |
| sprintf(def, "-DXDCPATH=%s", xdcpath); |
| |
| /* add xdcpath to the jvmOptions */ |
| jvmOptions[nOpts++] = def; |
| if (nOpts >= MAXOPTIONS) { |
| error(1, "too many options for JVM\n\n"); |
| } |
| } |
| |
| /* Handling of xdc.root has to be done in C code because it's used right at |
| * the beginning of JavaScript code. Also the path to xs executable is used |
| * to resolve xdc.root, so it is easier to handle everything here. |
| * |
| * If the user did not pass 'xdc.root' explicitly, we use the directory |
| * in which we found 'xs.c' to set 'xdc.root'. |
| */ |
| if (xdcroot == NULL) { |
| xdcroot = (String)malloc(strlen(progPath) + 1); |
| if (xdcroot == NULL) { |
| error(1, "out of memory"); |
| } |
| strcpy(xdcroot, progPath); |
| |
| /* add xdcroot to the jvmOptions */ |
| jvmOptions[nOpts] = (String)malloc(strlen(xdcroot) + 13); |
| |
| if (jvmOptions[nOpts] == NULL) { |
| error(1, "out of memory"); |
| } |
| sprintf(jvmOptions[nOpts], "-Dxdc.root=%s", xdcroot); |
| nOpts += 1; |
| } |
| |
| /* get the path to the initialization script */ |
| initScriptPath = (String)malloc(strlen(xdcroot) + |
| strlen(xsRelativePath) + 2); |
| if (initScriptPath == NULL) { |
| error(1, "out of memory"); |
| } |
| |
| strcpy(initScriptPath, xdcroot); |
| strcat(initScriptPath, xsRelativePath); |
| |
| /* create TCF session manager */ |
| if ((tcf = TCF_create(NULL, &attrs, &errorMsg)) == NULL) { |
| error(1, "can't create session manager: %s\n", errorMsg); |
| } |
| |
| if (iflag) { |
| nargv[nargc] = "-v"; |
| nargc += 1; |
| } |
| |
| if ((envtrace = getenv("XDC_TRACE_GROUPS")) != NULL) { |
| if (strstr(envtrace, "bench") != NULL) { |
| traceFlag = TRUE; |
| } |
| } |
| /* trace flag for Shell is turned on. */ |
| if (traceFlag) { |
| printTime("xs.exe starts", &startTime); |
| fflush(NULL); |
| } |
| |
| nargv[nargc] = initScriptPath; |
| nargc += 1; |
| |
| if (argc == 0 && !iflag) { |
| /* No script, package or module is supplied and interactive mode is |
| * not requested. |
| */ |
| printf("Script, capsule, module or package must be supplied as an \n"); |
| printf("argument,\nor interactive mode (-i) must be selected.\n"); |
| usage(); |
| return(0); |
| } |
| |
| for (i = 0; i < argc; i++) { |
| nargv[nargc] = (String)malloc(strlen(argv[i]) + 1); |
| if (nargv[nargc] == NULL) { |
| error(1, "out of memory"); |
| } |
| strcpy(nargv[nargc], argv[i]); |
| nargc += 1; |
| } |
| |
| if (iflag) { |
| TCF_Session session; |
| session = TCF_start(tcf, nargc, nargv, &errorMsg); |
| if (session != NULL) { |
| String cmd = NULL; |
| while (status != TCF_EFATAL && (cmd = getLine(cmd)) != NULL) { |
| if ((status = TCF_process(session, cmd)) != TCF_EINCOMPLETE) { |
| free(cmd); |
| cmd = NULL; |
| } |
| } |
| TCF_stop(session); |
| } |
| else { |
| error(0, "can't create session: %s\n", errorMsg); |
| status = TCF_EINTERN; |
| } |
| } |
| else { |
| /* run TCF interpreter on the script name and get return status */ |
| status = TCF_run(tcf, nargc, nargv); |
| } |
| |
| free(xdcroot); |
| free(initScriptPath); |
| free(progPath); |
| |
| /* we get here if main() returns without calling System.exit(); i.e., |
| * exit status of 0 for the Rhino Shell. Otherwise the exit hook |
| * exits. |
| */ |
| if (dflag > 0) { |
| error(0, "exit status: %d\n", status); |
| } |
| |
| /* delete interpreter and exit the TCF module */ |
| TCF_delete(tcf); |
| TCF_exit(); |
| |
| if (traceFlag) { |
| printTime("xs.exe exits", NULL); |
| } |
| |
| return (status); |
| } |
| |
| /* |
| * ======== error ======== |
| */ |
| static Void error(Int exitStatus, String format, ...) |
| { |
| va_list ap; |
| |
| String canProgName = getCanonicalProgName(progName); |
| if (canProgName == NULL) { |
| canProgName = progName; |
| } |
| fprintf(stderr, "%s: %s", canProgName, exitStatus == 0 ? "" : "error: "); |
| |
| va_start(ap, format); |
| (void)vfprintf(stderr, format, ap); |
| va_end(ap); |
| |
| if (exitStatus != 0) { |
| exit(exitStatus); |
| } |
| } |
| |
| /* |
| * ======== getLine ======== |
| */ |
| static String getLine(String prev) |
| { |
| char buffer[MAXLINE + 1]; |
| String prefix; |
| String command = NULL; |
| |
| if (prev == NULL) { |
| fprintf(stdout, mflag ? ">>>>\n" : "js> "); |
| fflush(stdout); |
| prefix = ""; |
| } |
| else { |
| prefix = prev; |
| } |
| |
| if (fgets(buffer, sizeof(buffer), stdin)) { |
| if (strcmp(buffer, "quit\n") && strcmp(buffer, "quit\r\n")) { |
| SizeT len = strlen(buffer) + strlen(prefix); |
| if ((command = malloc(len + 1)) != NULL) { |
| strcpy(command, prefix); |
| strcat(command, buffer); |
| } |
| } |
| } |
| |
| if (prev != NULL) { |
| free(prev); |
| } |
| |
| return (command); |
| } |
| |
| /* |
| * ======== getProgPath ======== |
| * Return TRUE if a path to this executable, not including the name of the |
| * executable, is found and copied to pathBuf. Return FALSE if the path |
| * lookup failed. |
| */ |
| static Bool getProgPath(Char *pathBuf) |
| { |
| String tmp; |
| |
| #if defined(xdc_target__os_Windows) |
| if (GetModuleFileName(0, pathBuf, MAXNAME) != 0) { |
| if ((tmp = strrchr(pathBuf, DIRSTR[0])) != NULL) { |
| tmp[0] = '\0'; |
| return (TRUE); |
| } |
| } |
| |
| pathBuf[0] = '\0'; /* just in case ... */ |
| return (FALSE); |
| #else |
| if (strlen(progName) >= MAXNAME) { |
| pathBuf[0] = '\0'; |
| return (FALSE); |
| } |
| |
| strcpy(pathBuf, progName); |
| if ((tmp = strrchr(pathBuf, DIRSTR[0])) != NULL) { |
| tmp[0] = '\0'; |
| } |
| else { |
| strcpy(pathBuf, "."); |
| } |
| |
| /* if pathBuf is a relative path, prepend cwd to make absolute path */ |
| if (pathBuf[0] != DIRSTR[0]) { |
| Char buf[MAXNAME + 1]; |
| if (getcwd(buf, MAXNAME) != NULL) { |
| if ((strlen(pathBuf) + strlen(buf) + 2) < MAXNAME) { |
| if (strcmp(pathBuf, ".") != 0) { |
| strcat(buf, DIRSTR); |
| strcat(buf, pathBuf); |
| } |
| strcpy(pathBuf, buf); |
| } |
| } |
| } |
| |
| return (TRUE); |
| #endif |
| } |
| |
| /* |
| * ======== getCanonicalProgName ======== |
| */ |
| static String getCanonicalProgName(String argv0) |
| { |
| #if defined(xdc_target__os_Windows) |
| if (strrchr(argv0, '\\') == NULL && strrchr(argv0, '/') == NULL) { |
| Char buf[MAXNAME + 1]; |
| String prog = NULL; |
| |
| if (getProgPath(buf)) { |
| if ((strlen(buf) + strlen(argv0)) < MAXNAME) { |
| strcat(buf, DIRSTR); |
| strcat(buf, argv0); |
| if ((prog = malloc(strlen(buf) + 1)) != NULL) { |
| strcpy(prog, buf); |
| } |
| } |
| } |
| return (prog); |
| } |
| #endif |
| return (XUTL_getCanonicalPath(argv0)); |
| } |
| |
| |
| /* |
| * ======== init ======== |
| */ |
| static Void init(Void) |
| { |
| TCF_init(); |
| GT_init(); |
| |
| #if 0 |
| /* It now looks like we don't need to hack below: detaching the |
| * main thread in TCF_delete() seems to prevent the deadlock |
| * described below. We keep the code and description just in case ... |
| */ |
| #if defined(xdc_target__os_Windows) |
| /* |
| * HACK!!! BUG: the following line causes this utility to only run on |
| * a single-processor of multi-processor NT system. We do this to avoid |
| * what is an apparent deadlock that occurs between the Java garbage |
| * collector and this thread: |
| * |
| * garbage collector: |
| * calls free() |
| * free() acquires heap lock |
| * -----> preempted by xs main thread |
| * |
| * xs: |
| * calls TCF_delete() |
| * calls JVM destroy |
| * JVM destroy suspends garbage collector |
| * calls free() (for TCF object) |
| * free blocks on heap lock owned by suspended gc |
| */ |
| SetProcessAffinityMask(GetCurrentProcess(), 0x1); |
| #endif |
| #endif |
| } |
| |
| /* |
| * ======== initPathTab ======== |
| * Initialize the path table pathTab. This path table is used to |
| * search for the loadable JVM, as well as the JavaScript jar (js.jar) |
| * and the configuration jar (config.jar). |
| * |
| * The search path is initialized as follows: |
| * dirname(argv[0]) |
| * dirname(argv[0])/XDCSHELF |
| */ |
| static Int initPathTab(String pathTab[]) |
| { |
| static Char appBuf[MAXNAME + 1]; /* dirname(argv[0]) */ |
| static Char shelfBuf[MAXNAME + 1]; /* dirname(argv[0])/XDCSHELF */ |
| |
| Int i = 0; |
| |
| if (getProgPath(appBuf)) { |
| /* The path added here is where JRE is found in XDCtools product. */ |
| pathTab[i++] = appBuf; |
| |
| /* In some cases, we may want to add JRE to the shelf. */ |
| if ((strlen(appBuf) + strlen(XDCSHELF) + 1) < MAXNAME) { |
| strcpy(shelfBuf, appBuf); |
| strcat(shelfBuf, DIRSTR XDCSHELF); |
| pathTab[i++] = shelfBuf; |
| } |
| } |
| |
| /* null terminate the path table */ |
| pathTab[i] = NULL; |
| |
| if (i > MAXNUMPATH) { |
| error(1, "too many path names specified\n"); |
| } |
| |
| return (i); |
| } |
| |
| /* |
| * ======== jvmAbort ======== |
| * Called by JVM on abort |
| */ |
| static void CALLBACK jvmAbort(void) |
| { |
| if (dflag > 0) { |
| error(0, "JVM abort hook\n"); |
| } |
| |
| abort(); |
| } |
| |
| /* |
| * ======== jvmExit ======== |
| * Called by JVM on exit. |
| */ |
| static void CALLBACK jvmExit(int status) |
| { |
| if (dflag > 0) { |
| error(status, "JVM exit: %d\n", status); |
| } |
| |
| TCF_exit(); |
| exit(status); |
| } |
| |
| /* the following three definitions are required for ident.c */ |
| #define _NAME_ __FILE__ |
| #define _DATE_ __DATE__ |
| #define _CSUM_ "" |
| #include "../../../../ident.c" /* defines _VERS_ string */ |
| |
| /* |
| * ======== printTime ======== |
| * |
| * print the message and the time passed in the second argument, except when |
| * that argument is NULL. In that case, the current time is printed. |
| */ |
| static Void printTime(String msg, struct timeb *t) |
| { |
| struct timeb tb; |
| struct tm *btime; |
| char *wmsg; |
| int wmsg_size = 9; // hh:mm:ss |
| char *pmsg; |
| int pmsg_size = 3; // am/pm |
| |
| wmsg = (char *)malloc(sizeof(char) * wmsg_size); |
| pmsg = (char *)malloc(sizeof(char) * pmsg_size); |
| if (wmsg == NULL || pmsg == NULL) { |
| error(1, "out of memory"); |
| } |
| |
| if (t == NULL) { |
| ftime(&tb); |
| t = &tb; |
| } |
| |
| btime = localtime(&(t->time)); |
| strftime(wmsg, wmsg_size, "%I:%M:%S", btime); |
| strftime(pmsg, pmsg_size, "%p", btime); |
| printf("TIME=%s.%03u %s %s\n", wmsg, t->millitm, pmsg, msg); |
| free(pmsg); |
| free(wmsg); |
| } |
| |
| /* |
| * ======== printVersion ======== |
| */ |
| static Void printVersion(Void) |
| { |
| Char *vers = __VERS; |
| |
| if (vers[0] == '@') { |
| while (vers[0] != '\0' && !isspace(vers[0])) { |
| vers++; |
| } |
| while (vers[0] != '\0' && isspace(vers[0])) { |
| vers++; |
| } |
| } |
| |
| /* don't use getProgPath(); the output of this function should be |
| * independent of the caller's environment |
| */ |
| printf("xs (XDCscript Interpreter) %s, %s\n", vers, __DATE); |
| } |
| |
| /* |
| * ======== usage ======== |
| */ |
| static Void usage(Void) |
| { |
| printf("Usage: xs [options] [<script> | <capsule> | <module> | <package>] [args]\n"); |
| printf("Options:\n"); |
| printf(" -h, --help\t\tPrint this message and exit\n"); |
| printf(" -v, --version\t\tPrint the version and exit\n"); |
| printf(" @opts-file\t\tRead the specified file and include its contents "); |
| printf("as\n\t\t\targuments to xs\n"); |
| /*printf("[--cp <classpath>]\n\t [--lp <java library path>] ");*/ |
| printf(" -i\t\t\tRun in interactive mode\n"); |
| printf(" --xdcpath PATH, or\n --xdcpath=PATH"); |
| printf("\tAdd PATH to the beginning of the package path\n"); |
| /*printf(" --X<opt>\t\tOption -X<opt> is passed directly to SUN JVM\n");*/ |
| printf(" -D<name>=<val>\tAdd the \"name=value\" definition to the XDC\n"); |
| printf("\t\t\tScript environment\n"); |
| printf(" -g[=<opts>]\t\tuse graphical debugger to run script, and \n"); |
| printf("\t\t\toptionally pass <opts> to debugger\n"); |
| printf("\t\t\tThis option must be last in [options].\n\n"); |
| printf(" -m\t\t\tSpecifies that the next argument is the name of\n"); |
| printf("\t\t\ta module. The module must define a main() function.\n"); |
| printf("\t\t\tThis option must be last in [options].\n"); |
| printf(" -f\t\t\tSpecifies that the next argument is the name of\n"); |
| printf("\t\t\ta script. This option must be last in [options].\n"); |
| printf(" -c\t\t\tSpecifies that the next argument is the name of\n"); |
| printf("\t\t\ta capsule. The module must define a main() function.\n"); |
| printf("\t\t\tThis option must be last in [options].\n\n"); |
| |
| printf(" If none of the options '-m', '-f', and '-c' is specified, \n"); |
| printf(" the argument given to xs after [options] is assumed to\n"); |
| printf(" be a package name. This package must have a module named\n"); |
| printf(" Main that defines a main() function.\n\n"); |
| |
| printf("Graphical Debugger Options:\n"); |
| printf(" -i\t\t\tbreak at the first line of the startup script\n\n"); |
| } |