From 640477f91eae7560dd7b46499caf0818e51dfb9e Mon Sep 17 00:00:00 2001 From: dos-reis Date: Thu, 2 Jun 2011 23:04:55 +0000 Subject: more utility code consolidation --- src/Makefile.am | 2 +- src/Makefile.in | 2 +- src/driver/Makefile.in | 8 +- src/driver/utils.cc | 548 ------------------------------------------------- src/gui/debate.cc | 1 + src/utils/Makefile.in | 9 +- src/utils/command.cc | 548 +++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 562 insertions(+), 556 deletions(-) delete mode 100644 src/driver/utils.cc create mode 100644 src/utils/command.cc diff --git a/src/Makefile.am b/src/Makefile.am index 482f3748..77d90c46 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -76,7 +76,7 @@ stamp-subdirs: .PHONY: $(oa_all_targets) -all-driver: all-lib +all-driver: all-utils all-lib cd driver && $(MAKE) $(AM_MAKEFLAGS) $@ all-utils: stamp-subdirs diff --git a/src/Makefile.in b/src/Makefile.in index 43b89d32..8d880d42 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -674,7 +674,7 @@ stamp-subdirs: .PHONY: $(oa_all_targets) -all-driver: all-lib +all-driver: all-utils all-lib cd driver && $(MAKE) $(AM_MAKEFLAGS) $@ all-utils: stamp-subdirs diff --git a/src/driver/Makefile.in b/src/driver/Makefile.in index 5ad25526..1769b44c 100644 --- a/src/driver/Makefile.in +++ b/src/driver/Makefile.in @@ -32,11 +32,14 @@ bin_PROGRAMS = open-axiom$(EXEEXT) -open_axiom_SOURCES = main.cc utils.cc +open_axiom_SOURCES = main.cc open_axiom_objects = $(open_axiom_SOURCES:.cc=.lo) -open_axiom_LDADD = -L$(builddir)/../lib $(oa_c_libs) +open_axiom_LDADD = \ + -L$(axiom_target_libdir)/ \ + -L$(builddir)/../lib \ + -lOpenAxiom $(oa_c_libs) VPATH += $(top_srcdir)/src/include @@ -59,7 +62,6 @@ stamp: $(bin_PROGRAMS) -DOPENAXIOM_ROOT_DIRECTORY="\"$(open_axiom_installdir)\"" \ $(axiom_includes) $< -utils.lo: open-axiom.h main.lo: open-axiom.h open-axiom$(EXEEXT): $(open_axiom_objects) diff --git a/src/driver/utils.cc b/src/driver/utils.cc deleted file mode 100644 index 498e2f4e..00000000 --- a/src/driver/utils.cc +++ /dev/null @@ -1,548 +0,0 @@ -/* - Copyright (C) 2008-2011, Gabriel Dos Reis. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - - Neither the name of The Numerical Algorithms Group Ltd. nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include -#include -#include -#include -#include "open-axiom.h" - -namespace OpenAxiom { - -/* The basename of the file holding the OpenAxiom core executable. */ -#define OPENAXIOM_CORE_EXECUTABLE \ - "AXIOMsys" OPENAXIOM_EXEEXT - -/* The basename of the file holding the session manager executable. */ -#define OPENAXIOM_SMAN_EXECUTABLE \ - "sman" OPENAXIOM_EXEEXT - -/* Path to the OpenAxiom executable core, relative to - OPENAXIOM_ROOT_DIRECTORY, or to the system root directory as specified - on command line. */ -#define OPENAXIOM_CORE_PATH \ - "/bin/" OPENAXIOM_CORE_EXECUTABLE - -#define OPENAXIOM_GUI_SUBPATH \ - "/bin/" OPENAXIOM_GUI_EXECUTABLE - -#define OPENAXIOM_GUI_EXECUTABLE \ - "gui" OPENAXIOM_EXEEXT - -/* Path to the session manager, relative to OPENAXIOM_ROOT_DIRECTORY, - or to the system root directory as specified on command line. */ -#define OPENAXIOM_SMAN_PATH \ - "/bin/" OPENAXIOM_SMAN_EXECUTABLE - -/* Name of the entry point for Lisp-based OpenAxiom. */ -#define OPENAXIOM_LISP_CORE_ENTRY_POINT \ - "|AxiomCore|::|topLevel|" - - // -- Arguments -- - Arguments::Arguments(int n) : std::vector(n > 0 ? n + 1 : 0) - { } - - int Arguments::size() const { - return empty() ? 0 : std::vector::size() - 1; - } - - void Arguments::allocate(int n) { - resize(n + 1); - } - - char* const* Arguments::data() const { - return &*begin(); - }; - - // -- Command -- - Command::Command() - : core(), - rt_args(), - root_dir(), - exec_path() - { } - - static const char* - get_suffix(const char* first, const char* last, const char* seq) { - for (; first < last; ++first, ++seq) - if (*first != *seq) - return 0; - return seq; - } - - // -- Return non-null if `lhs' is a prefix of `rhs'. When non-null - // -- the pointer points to the '=' character that starts of the - // -- value supplied to the argument. - template - const char* is_prefix(const char (&lhs)[N], const char* rhs) { - for (int i = 0; i < N - 1; ++i) - if (lhs[i] != rhs[i]) - return 0; - return rhs + N - 1; - } - - const char* - option_value(const Command* command, const char* opt) { - const int n = strlen(opt); - for (int i = 1; i < command->core.argc; ++i) { - const char* arg = command->core.argv[i]; - if (strlen(arg) < n) - continue; - if(const char* val = get_suffix(opt, opt + n, arg)) { - if (*val++ == '=') - return val; - break; - } - } - return 0; - } - -/* Return a path to the running system, either as specified on command - line through --system=, or as specified at configuration time. */ -const char* -get_systemdir(int argc, char* argv[]) -{ - int i; - - /* Root directory specified on command line takes precedence - over location specified at configuration time. */ - for (i = 1; i < argc; ++i) - if (strcmp("--", argv[i]) == 0) - break; - else if (strncmp("--system=", argv[i], sizeof("--system=") - 1) == 0) { - return argv[i] + sizeof ("--system=") - 1; - } - - /* Command line did not change the system location to use. - Return what was computed at configuration time. */ - return OPENAXIOM_ROOT_DIRECTORY; -} - -/* Return the path to `driver'. */ -static const char* -get_driver_subpath(Driver driver) -{ - switch (driver) { - case sman_driver: - return OPENAXIOM_SMAN_PATH; - - case gui_driver: - return OPENAXIOM_GUI_SUBPATH; - - case script_driver: - case compiler_driver: - case core_driver: - case translator_driver: - case linker_driver: - return OPENAXIOM_CORE_PATH; - - default: - abort(); - } -} - - -/* Return a path for PROG specified as a relative path to PREFIX. */ -const char* -make_path_for(const char* prefix, Driver driver) -{ - const int prefix_length = strlen(prefix); - const char* prog = get_driver_subpath(driver); - char* execpath = (char*) malloc(prefix_length + strlen(prog) + 1); - strcpy(execpath, prefix); - strcpy(execpath + prefix_length, prog); - return execpath; -} - -/* Build arguments, if any, to be supplied to the runtime system - of `driver'. */ -void -build_rts_options(Command* command, Driver driver) -{ - switch (driver) { - case config_driver: - case sman_driver: - case gui_driver: - case execute_driver: - case unknown_driver: - break; - - case core_driver: - break; - - case compiler_driver: - case script_driver: - case translator_driver: - case linker_driver: - switch (OPENAXIOM_BASE_RTS) { - case gcl_runtime: - command->rt_args.allocate(3); - command->rt_args[0] = (char*) "-batch"; - command->rt_args[1] = (char*) "-eval"; - command->rt_args[2] = - (char*) ("(" OPENAXIOM_LISP_CORE_ENTRY_POINT ")"); - break; - - case sbcl_runtime: - command->rt_args.allocate(4); - command->rt_args[0] = (char*) "--noinform"; - command->rt_args[1] = (char*) "--end-runtime-options"; - command->rt_args[2] = (char*) "--noprint"; - command->rt_args[3] = (char*) "--end-toplevel-options"; - break; - - case clozure_runtime: - command->rt_args.allocate(2); - command->rt_args[0] = (char*) "--quiet"; - command->rt_args[1] = (char*) "--batch"; - break; - - case clisp_runtime: - command->rt_args.allocate(2); - command->rt_args[0] = (char*) "--quiet"; - command->rt_args[1] = (char*) "-norc"; - break; - - case ecl_runtime: - command->rt_args.allocate(2); - command->rt_args[0] = (char*) "-q"; - command->rt_args[1] = (char*) "-norc"; - break; - - default: - abort(); - } - break; - - default: - abort(); - } -} - -#if OPENAXIOM_USE_SMAN -# define OPENAXIOM_DEFAULT_DRIVER sman_driver -#elif OPENAXIOM_USE_GUI -# define OPENAXIOM_DEFAULT_DRIVER gui_driver -#else -# define OPENAXIOM_DEFAULT_DRIVER core_driver -#endif - - -static void print_line(const char* line) { - fputs(line, stdout); - fputc('\n', stdout); -} - -/* Print OpenAxiom version information. */ -static void print_version(void) { - print_line(PACKAGE_STRING); -} - -/* Print OpenAxiom invokation syntax (e.g. options) on standard - output stream. */ - -static void print_usage(void) { - print_line("Usage: open-axiom [options] [file]"); - print_line("General options:"); - print_line(" --help Print this information and exit."); - print_line(" --version Print OpenAxiom version and exit."); - print_line(" --script Execute the file argument as a Spad script."); - print_line(" If specified, this option should be last before file argument."); - print_line(" --compile Invoke the compiler on the file argument."); - print_line(" If specified, this option should be last before file argument."); - print_line(" --server Start the Superman as master process."); - print_line(" --no-server Do not start Superman as master process."); - print_line(""); - print_line("Superman options:"); - print_line(" --no-gui Do not start the Graphics or HyperDoc components."); - print_line(" --graph Start the Graphics component. This option is meaningful"); - print_line(" only if OpenAxiom was built with graphics support."); - print_line(" --no-graph Do not start the Graphics component."); - print_line(" --hyperdoc Start the HyperDoc component. This option is meaningful"); - print_line(" only if OpenAxiom was built with graphics support."); - print_line(" --no-hyperdoc Do not start the HyperDoc component."); - print_line(" --execute cmd args execute `cmd' with arguments `args'"); - - print_line(""); - print_line("Compiler options:"); - print_line(" --optimize= Set compiler optimization level to , a natural number."); - print_line(""); - print_line("If invoked without options and without an input file " - "OpenAxiom will start as an interative program with Superman" - " as the master process, the majority of uses. If invoked " - "with a file as single argument, OpenAxiom assumes the file is a Spad " - "script and will attempt to execute it as such."); - print_line(""); - print_line("Submit bug report to " PACKAGE_BUGREPORT); -} - - // Map a option to the driver that implement that action. - struct DriverMap { - const char* action; - const Driver driver; - }; - - static const DriverMap driver_table[] = { - { "--script", script_driver }, - { "--compile", compiler_driver }, - { "--translate", compiler_driver }, - { "--build-databases", compiler_driver }, - { "--make", linker_driver }, - }; - - // Obtain the driver that implement a specific action requested - // on command line. - static Driver - option_driver(const char* opt) { - for (int i = 0; i < length(driver_table); ++i) - if (strcmp(opt, driver_table[i].action) == 0) - return driver_table[i].driver; - return unknown_driver; - } - -/* Determine driver to be used for executing `command'. */ -Driver -preprocess_arguments(Command* command, int argc, char** argv) -{ - int i; - int other = 1; - int files = 0; - Driver driver = unknown_driver; - - command->root_dir = get_systemdir(argc, argv); - for (i = 1; i < argc; ++i) - if(strcmp(argv[i], "--no-server") == 0) - driver = core_driver; - else if (strcmp(argv[i], "--server") == 0) - driver = sman_driver; - else if (strcmp(argv[i], "--config") == 0) - driver = config_driver; - else if (strcmp(argv[i], "--execute") == 0) { - driver = execute_driver; - break; - } - else if (strcmp(argv[i], "--help") == 0) { - print_usage(); - driver = null_driver; - break; - } - else if (strcmp(argv[i], "--version") == 0) { - print_version(); - driver = null_driver; - break; - } - else if (const char* val = is_prefix("--execpath=", argv[i])) { - command->exec_path = val; - } - else { - /* Apparently we will invoke the Core system; we need to - pass on this option. */ - if (const Driver d = option_driver(argv[i])) - driver = d; - else { - if (argv[i][0] == '-') - /* Maybe option for the driver. */ - ; - else if (strlen(argv[i]) > 0) - /* Assume a file. */ - ++files; - else - /* Silly. */ - continue; - } - /* Save it for the core executable. */ - argv[other++] = argv[i]; - } - - /* Determine argument vector. */ - if (driver == execute_driver) { - command->core.argc = argc - i - 1; - command->core.argv = argv + i + 1; - } - else { - command->core.argc = other; - command->core.argv = argv; - } - - if (driver != null_driver) { - /* If we have a file but not instructed to compile, assume - we are asked to interpret a script. */ - if (files > 0) - switch (driver) { - case unknown_driver: - case sman_driver: - case gui_driver: - command->core.argc += 1; - command->core.argv = - (char**) malloc((other + 2) * sizeof(char*)); - command->core.argv[0] = argv[0]; - command->core.argv[1] = (char*) "--script"; - for (i = 0; i < other; ++i) - command->core.argv[2 + i] = argv[1 + i]; - driver = script_driver; - break; - default: - /* Driver specified by user. */ - break; - } - else if (driver == unknown_driver) - driver = OPENAXIOM_DEFAULT_DRIVER; - command->core.argv[command->core.argc] = NULL; - - build_rts_options(command, driver); - } - return driver; -} - - // Return a pointer to the path to the program to execute, as - // specified by `command' and `driver'. - static const char* - executable_path(const Command* command, Driver driver) { - return command->exec_path != 0 - ? command->exec_path - : make_path_for(command->root_dir, driver); - } - - -/* Execute the Core Executable as described by `command'. On - POSIX systems, this is a non-return function on success. - See execv(). */ -int -execute_core(const Command* command, Driver driver) -{ - char* execpath = (char*) executable_path(command, driver); -#ifdef __WIN32__ - char* command_line; - int cur = strlen(command->core.argv[0]); - int command_line_length = 0; - int i; - PROCESS_INFORMATION procInfo; - STARTUPINFO startupInfo = { 0 }; - DWORD status; /* Exit code for this program masqueraded as - the child created below. */ - - /* How long is the final command line for the MS system? */ - command_line_length += cur; - for (i = 0; i < command->rt_args.size(); ++i) - command_line_length += 1 /* blank char as separator */ - + 2 /* quotes around every argument. */ - + strlen(command->rt_args[i]); /* room for each argument */ - /* Don't forget room for the doubledash string. */ - command_line_length += sizeof("--") - 1; - /* And arguments to the actual command. */ - for (i = 1; i < command->core.argc; ++i) - command_line_length += 1 + 2 + strlen(command->core.argv[i]); - - /* Now, build the actual command line. This is done by - concatenating the arguments into a single string. */ - command_line = (char*) malloc(command_line_length + 1); - strcpy(command_line, command->core.argv[0]); - for (i = 0; i < command->rt_args.size(); ++i) { - const int arg_length = strlen(command->rt_args[i]); - command_line[cur++] = ' '; - command_line[cur++] = '"'; - strcpy(command_line + cur, command->rt_args[i]); - cur += arg_length; - command_line[cur++] = '"'; - } - command_line[cur++] = ' '; - command_line[cur++] = '-'; /* start arguments to the core executable. */ - command_line[cur++] = '-'; - for (i = 1; i < command->core.argc; ++i) { - const int arg_length = strlen(command->core.argv[i]); - command_line[cur++] = ' '; - command_line[cur++] = '"'; - strcpy(command_line + cur, command->core.argv[i]); - cur += arg_length; - command_line[cur++] = '"'; - } - command_line[cur] = '\0'; /* The command line is done. */ - - if(CreateProcess(/* lpApplicationName */ execpath, - /* lpCommandLine */ command_line, - /* lpProcessAttributes */ NULL, - /* lpThreadAttributes */ NULL, - /* bInheritHandles */ TRUE, - /* dwCreationFlags */ 0, - /* lpEnvironment */ NULL, - /* lpCurrentDirectory */ NULL, - /* lpstartupInfo */ &startupInfo, - /* lpProcessInformation */ &procInfo) == 0) { - fprintf(stderr, "error %d\n", GetLastError()); - abort(); - } - WaitForSingleObject(procInfo.hProcess, INFINITE); - GetExitCodeProcess(procInfo.hProcess, &status); - CloseHandle(procInfo.hThread); - CloseHandle(procInfo.hProcess); - return status; - -#else /* __WIN32__ */ - int i; - Arguments args(command->rt_args.size() + command->core.argc + 2); - /* GCL has this oddity that it wants to believe that argv[0] has - something to tell about what GCL's own runtime is. Silly. */ - if (OPENAXIOM_BASE_RTS == gcl_runtime) - args[0] = (char*) ""; - /* And CLISP wants to believe that argv[0] is where it hides stuff - from the saved image. */ - else if (OPENAXIOM_BASE_RTS == clisp_runtime) - args[0] = execpath; - else - args[0] = command->core.argv[0]; - /* Now, make sure we copy whatever arguments are required by the - runtime system. */ - for (i = 0; i < command->rt_args.size(); ++i) - args[i + 1] = command->rt_args[i]; - - if (command->core.argc > 1) { - /* We do have arguments from the command line. We want to - differentiate this from the base runtime system arguments. - We do this by inserting a doubledash to indicate beginning - of arguments. */ - args[command->rt_args.size() + 1] = (char*) "--"; - /* Then, copy over the arguments received from the command line. */ - for (i = 1; i < command->core.argc; ++i) - args[command->rt_args.size() + i + 1] = command->core.argv[i]; - args[command->rt_args.size() + command->core.argc + 1] = NULL; - } - else - args[command->rt_args.size() + command->core.argc] = NULL; - - execv(execpath, args.data()); - perror(execpath); - return -1; -#endif /* __WIN32__ */ -} - -} diff --git a/src/gui/debate.cc b/src/gui/debate.cc index 92209db8..35740c37 100644 --- a/src/gui/debate.cc +++ b/src/gui/debate.cc @@ -33,6 +33,7 @@ #include #include "debate.h" #include +#include "open-axiom.h" namespace OpenAxiom { diff --git a/src/utils/Makefile.in b/src/utils/Makefile.in index 764bda0f..1352cfea 100644 --- a/src/utils/Makefile.in +++ b/src/utils/Makefile.in @@ -1,4 +1,4 @@ -# Copyright (C) 2010, Gabriel Dos Reis. +# Copyright (C) 2011, Gabriel Dos Reis. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -37,7 +37,7 @@ hammer_OBJECTS = $(hammer_SOURCES:.cc=.lo) hammer_LDADD = -L. -lOpenAxiom libOpenAxiom_HEADERS = storage.H hash-table.H string-pool.H sexpr.H -libOpenAxiom_SOURCES = storage.cc string-pool.cc sexpr.cc +libOpenAxiom_SOURCES = storage.cc string-pool.cc sexpr.cc command.cc libOpenAxiom_OBJECTS = $(libOpenAxiom_SOURCES:.cc=.lo) oa_public_headers = storage hash-table string-pool sexpr @@ -45,7 +45,10 @@ oa_public_headers = storage hash-table string-pool sexpr ## Where we store public header files oa_target_headerdir = $(oa_target_includedir)/open-axiom -oa_include_flags = -I. -I$(oa_target_includedir) -I$(top_builddir)/config +oa_include_flags = -I. -I$(oa_target_includedir) \ + -I$(top_builddir)/config \ + -I$(top_srcdir)/src/include \ + -DOPENAXIOM_ROOT_DIRECTORY="\"$(open_axiom_installdir)\"" oa_target_oalib = $(axiom_target_libdir)/libOpenAxiom.$(LIBEXT) diff --git a/src/utils/command.cc b/src/utils/command.cc new file mode 100644 index 00000000..498e2f4e --- /dev/null +++ b/src/utils/command.cc @@ -0,0 +1,548 @@ +/* + Copyright (C) 2008-2011, Gabriel Dos Reis. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + - Neither the name of The Numerical Algorithms Group Ltd. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include "open-axiom.h" + +namespace OpenAxiom { + +/* The basename of the file holding the OpenAxiom core executable. */ +#define OPENAXIOM_CORE_EXECUTABLE \ + "AXIOMsys" OPENAXIOM_EXEEXT + +/* The basename of the file holding the session manager executable. */ +#define OPENAXIOM_SMAN_EXECUTABLE \ + "sman" OPENAXIOM_EXEEXT + +/* Path to the OpenAxiom executable core, relative to + OPENAXIOM_ROOT_DIRECTORY, or to the system root directory as specified + on command line. */ +#define OPENAXIOM_CORE_PATH \ + "/bin/" OPENAXIOM_CORE_EXECUTABLE + +#define OPENAXIOM_GUI_SUBPATH \ + "/bin/" OPENAXIOM_GUI_EXECUTABLE + +#define OPENAXIOM_GUI_EXECUTABLE \ + "gui" OPENAXIOM_EXEEXT + +/* Path to the session manager, relative to OPENAXIOM_ROOT_DIRECTORY, + or to the system root directory as specified on command line. */ +#define OPENAXIOM_SMAN_PATH \ + "/bin/" OPENAXIOM_SMAN_EXECUTABLE + +/* Name of the entry point for Lisp-based OpenAxiom. */ +#define OPENAXIOM_LISP_CORE_ENTRY_POINT \ + "|AxiomCore|::|topLevel|" + + // -- Arguments -- + Arguments::Arguments(int n) : std::vector(n > 0 ? n + 1 : 0) + { } + + int Arguments::size() const { + return empty() ? 0 : std::vector::size() - 1; + } + + void Arguments::allocate(int n) { + resize(n + 1); + } + + char* const* Arguments::data() const { + return &*begin(); + }; + + // -- Command -- + Command::Command() + : core(), + rt_args(), + root_dir(), + exec_path() + { } + + static const char* + get_suffix(const char* first, const char* last, const char* seq) { + for (; first < last; ++first, ++seq) + if (*first != *seq) + return 0; + return seq; + } + + // -- Return non-null if `lhs' is a prefix of `rhs'. When non-null + // -- the pointer points to the '=' character that starts of the + // -- value supplied to the argument. + template + const char* is_prefix(const char (&lhs)[N], const char* rhs) { + for (int i = 0; i < N - 1; ++i) + if (lhs[i] != rhs[i]) + return 0; + return rhs + N - 1; + } + + const char* + option_value(const Command* command, const char* opt) { + const int n = strlen(opt); + for (int i = 1; i < command->core.argc; ++i) { + const char* arg = command->core.argv[i]; + if (strlen(arg) < n) + continue; + if(const char* val = get_suffix(opt, opt + n, arg)) { + if (*val++ == '=') + return val; + break; + } + } + return 0; + } + +/* Return a path to the running system, either as specified on command + line through --system=, or as specified at configuration time. */ +const char* +get_systemdir(int argc, char* argv[]) +{ + int i; + + /* Root directory specified on command line takes precedence + over location specified at configuration time. */ + for (i = 1; i < argc; ++i) + if (strcmp("--", argv[i]) == 0) + break; + else if (strncmp("--system=", argv[i], sizeof("--system=") - 1) == 0) { + return argv[i] + sizeof ("--system=") - 1; + } + + /* Command line did not change the system location to use. + Return what was computed at configuration time. */ + return OPENAXIOM_ROOT_DIRECTORY; +} + +/* Return the path to `driver'. */ +static const char* +get_driver_subpath(Driver driver) +{ + switch (driver) { + case sman_driver: + return OPENAXIOM_SMAN_PATH; + + case gui_driver: + return OPENAXIOM_GUI_SUBPATH; + + case script_driver: + case compiler_driver: + case core_driver: + case translator_driver: + case linker_driver: + return OPENAXIOM_CORE_PATH; + + default: + abort(); + } +} + + +/* Return a path for PROG specified as a relative path to PREFIX. */ +const char* +make_path_for(const char* prefix, Driver driver) +{ + const int prefix_length = strlen(prefix); + const char* prog = get_driver_subpath(driver); + char* execpath = (char*) malloc(prefix_length + strlen(prog) + 1); + strcpy(execpath, prefix); + strcpy(execpath + prefix_length, prog); + return execpath; +} + +/* Build arguments, if any, to be supplied to the runtime system + of `driver'. */ +void +build_rts_options(Command* command, Driver driver) +{ + switch (driver) { + case config_driver: + case sman_driver: + case gui_driver: + case execute_driver: + case unknown_driver: + break; + + case core_driver: + break; + + case compiler_driver: + case script_driver: + case translator_driver: + case linker_driver: + switch (OPENAXIOM_BASE_RTS) { + case gcl_runtime: + command->rt_args.allocate(3); + command->rt_args[0] = (char*) "-batch"; + command->rt_args[1] = (char*) "-eval"; + command->rt_args[2] = + (char*) ("(" OPENAXIOM_LISP_CORE_ENTRY_POINT ")"); + break; + + case sbcl_runtime: + command->rt_args.allocate(4); + command->rt_args[0] = (char*) "--noinform"; + command->rt_args[1] = (char*) "--end-runtime-options"; + command->rt_args[2] = (char*) "--noprint"; + command->rt_args[3] = (char*) "--end-toplevel-options"; + break; + + case clozure_runtime: + command->rt_args.allocate(2); + command->rt_args[0] = (char*) "--quiet"; + command->rt_args[1] = (char*) "--batch"; + break; + + case clisp_runtime: + command->rt_args.allocate(2); + command->rt_args[0] = (char*) "--quiet"; + command->rt_args[1] = (char*) "-norc"; + break; + + case ecl_runtime: + command->rt_args.allocate(2); + command->rt_args[0] = (char*) "-q"; + command->rt_args[1] = (char*) "-norc"; + break; + + default: + abort(); + } + break; + + default: + abort(); + } +} + +#if OPENAXIOM_USE_SMAN +# define OPENAXIOM_DEFAULT_DRIVER sman_driver +#elif OPENAXIOM_USE_GUI +# define OPENAXIOM_DEFAULT_DRIVER gui_driver +#else +# define OPENAXIOM_DEFAULT_DRIVER core_driver +#endif + + +static void print_line(const char* line) { + fputs(line, stdout); + fputc('\n', stdout); +} + +/* Print OpenAxiom version information. */ +static void print_version(void) { + print_line(PACKAGE_STRING); +} + +/* Print OpenAxiom invokation syntax (e.g. options) on standard + output stream. */ + +static void print_usage(void) { + print_line("Usage: open-axiom [options] [file]"); + print_line("General options:"); + print_line(" --help Print this information and exit."); + print_line(" --version Print OpenAxiom version and exit."); + print_line(" --script Execute the file argument as a Spad script."); + print_line(" If specified, this option should be last before file argument."); + print_line(" --compile Invoke the compiler on the file argument."); + print_line(" If specified, this option should be last before file argument."); + print_line(" --server Start the Superman as master process."); + print_line(" --no-server Do not start Superman as master process."); + print_line(""); + print_line("Superman options:"); + print_line(" --no-gui Do not start the Graphics or HyperDoc components."); + print_line(" --graph Start the Graphics component. This option is meaningful"); + print_line(" only if OpenAxiom was built with graphics support."); + print_line(" --no-graph Do not start the Graphics component."); + print_line(" --hyperdoc Start the HyperDoc component. This option is meaningful"); + print_line(" only if OpenAxiom was built with graphics support."); + print_line(" --no-hyperdoc Do not start the HyperDoc component."); + print_line(" --execute cmd args execute `cmd' with arguments `args'"); + + print_line(""); + print_line("Compiler options:"); + print_line(" --optimize= Set compiler optimization level to , a natural number."); + print_line(""); + print_line("If invoked without options and without an input file " + "OpenAxiom will start as an interative program with Superman" + " as the master process, the majority of uses. If invoked " + "with a file as single argument, OpenAxiom assumes the file is a Spad " + "script and will attempt to execute it as such."); + print_line(""); + print_line("Submit bug report to " PACKAGE_BUGREPORT); +} + + // Map a option to the driver that implement that action. + struct DriverMap { + const char* action; + const Driver driver; + }; + + static const DriverMap driver_table[] = { + { "--script", script_driver }, + { "--compile", compiler_driver }, + { "--translate", compiler_driver }, + { "--build-databases", compiler_driver }, + { "--make", linker_driver }, + }; + + // Obtain the driver that implement a specific action requested + // on command line. + static Driver + option_driver(const char* opt) { + for (int i = 0; i < length(driver_table); ++i) + if (strcmp(opt, driver_table[i].action) == 0) + return driver_table[i].driver; + return unknown_driver; + } + +/* Determine driver to be used for executing `command'. */ +Driver +preprocess_arguments(Command* command, int argc, char** argv) +{ + int i; + int other = 1; + int files = 0; + Driver driver = unknown_driver; + + command->root_dir = get_systemdir(argc, argv); + for (i = 1; i < argc; ++i) + if(strcmp(argv[i], "--no-server") == 0) + driver = core_driver; + else if (strcmp(argv[i], "--server") == 0) + driver = sman_driver; + else if (strcmp(argv[i], "--config") == 0) + driver = config_driver; + else if (strcmp(argv[i], "--execute") == 0) { + driver = execute_driver; + break; + } + else if (strcmp(argv[i], "--help") == 0) { + print_usage(); + driver = null_driver; + break; + } + else if (strcmp(argv[i], "--version") == 0) { + print_version(); + driver = null_driver; + break; + } + else if (const char* val = is_prefix("--execpath=", argv[i])) { + command->exec_path = val; + } + else { + /* Apparently we will invoke the Core system; we need to + pass on this option. */ + if (const Driver d = option_driver(argv[i])) + driver = d; + else { + if (argv[i][0] == '-') + /* Maybe option for the driver. */ + ; + else if (strlen(argv[i]) > 0) + /* Assume a file. */ + ++files; + else + /* Silly. */ + continue; + } + /* Save it for the core executable. */ + argv[other++] = argv[i]; + } + + /* Determine argument vector. */ + if (driver == execute_driver) { + command->core.argc = argc - i - 1; + command->core.argv = argv + i + 1; + } + else { + command->core.argc = other; + command->core.argv = argv; + } + + if (driver != null_driver) { + /* If we have a file but not instructed to compile, assume + we are asked to interpret a script. */ + if (files > 0) + switch (driver) { + case unknown_driver: + case sman_driver: + case gui_driver: + command->core.argc += 1; + command->core.argv = + (char**) malloc((other + 2) * sizeof(char*)); + command->core.argv[0] = argv[0]; + command->core.argv[1] = (char*) "--script"; + for (i = 0; i < other; ++i) + command->core.argv[2 + i] = argv[1 + i]; + driver = script_driver; + break; + default: + /* Driver specified by user. */ + break; + } + else if (driver == unknown_driver) + driver = OPENAXIOM_DEFAULT_DRIVER; + command->core.argv[command->core.argc] = NULL; + + build_rts_options(command, driver); + } + return driver; +} + + // Return a pointer to the path to the program to execute, as + // specified by `command' and `driver'. + static const char* + executable_path(const Command* command, Driver driver) { + return command->exec_path != 0 + ? command->exec_path + : make_path_for(command->root_dir, driver); + } + + +/* Execute the Core Executable as described by `command'. On + POSIX systems, this is a non-return function on success. + See execv(). */ +int +execute_core(const Command* command, Driver driver) +{ + char* execpath = (char*) executable_path(command, driver); +#ifdef __WIN32__ + char* command_line; + int cur = strlen(command->core.argv[0]); + int command_line_length = 0; + int i; + PROCESS_INFORMATION procInfo; + STARTUPINFO startupInfo = { 0 }; + DWORD status; /* Exit code for this program masqueraded as + the child created below. */ + + /* How long is the final command line for the MS system? */ + command_line_length += cur; + for (i = 0; i < command->rt_args.size(); ++i) + command_line_length += 1 /* blank char as separator */ + + 2 /* quotes around every argument. */ + + strlen(command->rt_args[i]); /* room for each argument */ + /* Don't forget room for the doubledash string. */ + command_line_length += sizeof("--") - 1; + /* And arguments to the actual command. */ + for (i = 1; i < command->core.argc; ++i) + command_line_length += 1 + 2 + strlen(command->core.argv[i]); + + /* Now, build the actual command line. This is done by + concatenating the arguments into a single string. */ + command_line = (char*) malloc(command_line_length + 1); + strcpy(command_line, command->core.argv[0]); + for (i = 0; i < command->rt_args.size(); ++i) { + const int arg_length = strlen(command->rt_args[i]); + command_line[cur++] = ' '; + command_line[cur++] = '"'; + strcpy(command_line + cur, command->rt_args[i]); + cur += arg_length; + command_line[cur++] = '"'; + } + command_line[cur++] = ' '; + command_line[cur++] = '-'; /* start arguments to the core executable. */ + command_line[cur++] = '-'; + for (i = 1; i < command->core.argc; ++i) { + const int arg_length = strlen(command->core.argv[i]); + command_line[cur++] = ' '; + command_line[cur++] = '"'; + strcpy(command_line + cur, command->core.argv[i]); + cur += arg_length; + command_line[cur++] = '"'; + } + command_line[cur] = '\0'; /* The command line is done. */ + + if(CreateProcess(/* lpApplicationName */ execpath, + /* lpCommandLine */ command_line, + /* lpProcessAttributes */ NULL, + /* lpThreadAttributes */ NULL, + /* bInheritHandles */ TRUE, + /* dwCreationFlags */ 0, + /* lpEnvironment */ NULL, + /* lpCurrentDirectory */ NULL, + /* lpstartupInfo */ &startupInfo, + /* lpProcessInformation */ &procInfo) == 0) { + fprintf(stderr, "error %d\n", GetLastError()); + abort(); + } + WaitForSingleObject(procInfo.hProcess, INFINITE); + GetExitCodeProcess(procInfo.hProcess, &status); + CloseHandle(procInfo.hThread); + CloseHandle(procInfo.hProcess); + return status; + +#else /* __WIN32__ */ + int i; + Arguments args(command->rt_args.size() + command->core.argc + 2); + /* GCL has this oddity that it wants to believe that argv[0] has + something to tell about what GCL's own runtime is. Silly. */ + if (OPENAXIOM_BASE_RTS == gcl_runtime) + args[0] = (char*) ""; + /* And CLISP wants to believe that argv[0] is where it hides stuff + from the saved image. */ + else if (OPENAXIOM_BASE_RTS == clisp_runtime) + args[0] = execpath; + else + args[0] = command->core.argv[0]; + /* Now, make sure we copy whatever arguments are required by the + runtime system. */ + for (i = 0; i < command->rt_args.size(); ++i) + args[i + 1] = command->rt_args[i]; + + if (command->core.argc > 1) { + /* We do have arguments from the command line. We want to + differentiate this from the base runtime system arguments. + We do this by inserting a doubledash to indicate beginning + of arguments. */ + args[command->rt_args.size() + 1] = (char*) "--"; + /* Then, copy over the arguments received from the command line. */ + for (i = 1; i < command->core.argc; ++i) + args[command->rt_args.size() + i + 1] = command->core.argv[i]; + args[command->rt_args.size() + command->core.argc + 1] = NULL; + } + else + args[command->rt_args.size() + command->core.argc] = NULL; + + execv(execpath, args.data()); + perror(execpath); + return -1; +#endif /* __WIN32__ */ +} + +} -- cgit v1.2.3