From b56562693a88f88e7c290de9e1dc18d96a0da792 Mon Sep 17 00:00:00 2001 From: Gabriel Dos Reis Date: Mon, 2 Jan 2017 14:03:55 -0800 Subject: Include a native entry point for parsing Boot source files, and for transpiling to Lisp. --- src/ChangeLog | 10 + src/boot/Makefile.am | 5 +- src/boot/Makefile.in | 8 +- src/include/open-axiom/Parser | 53 ++ src/include/open-axiom/dialect | 16 +- src/io/std-streams.cc | 57 -- src/io/std-streams.cxx | 57 ++ src/lib/Makefile.in | 25 +- src/lib/bsdsignal.c | 65 -- src/lib/bsdsignal.cxx | 65 ++ src/lib/cfuns-c.c | 914 ---------------------------- src/lib/cfuns-c.cxx | 914 ++++++++++++++++++++++++++++ src/lib/sockio-c.c | 1307 ---------------------------------------- src/lib/sockio-c.cxx | 1307 ++++++++++++++++++++++++++++++++++++++++ src/syntax/Parser.cxx | 134 ++++ src/syntax/token.cc | 116 ---- src/syntax/token.cxx | 116 ++++ src/utils/Makefile.am | 5 +- src/utils/Makefile.in | 44 +- 19 files changed, 2695 insertions(+), 2523 deletions(-) create mode 100644 src/include/open-axiom/Parser delete mode 100644 src/io/std-streams.cc create mode 100644 src/io/std-streams.cxx delete mode 100644 src/lib/bsdsignal.c create mode 100644 src/lib/bsdsignal.cxx delete mode 100644 src/lib/cfuns-c.c create mode 100644 src/lib/cfuns-c.cxx delete mode 100644 src/lib/sockio-c.c create mode 100644 src/lib/sockio-c.cxx create mode 100644 src/syntax/Parser.cxx delete mode 100644 src/syntax/token.cc create mode 100644 src/syntax/token.cxx (limited to 'src') diff --git a/src/ChangeLog b/src/ChangeLog index ab2df6a9..b1302e3a 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,13 @@ +2017-01-02 Gabriel Dos Reis + + * lib/Makefile.in (core_SOURCES): Include files for IO, + tokenization, and parsing. + * include/open-axiom/Parser (boot_to_lisp): New exported entry point. + * boot/Makefile.am (bemol_LDADD): Add libopen-axiom-core + * include/open-axiom/dialect: Add documentation. + * syntax/Parser.cxx: New. + * utils/Makefile.am (libOpenAxiom_a_SOURCES): Adjust. + 2016-12-29 Gabriel Dos Reis * lisp/core.lisp.in ($NativeModulePrefix): Define and export. diff --git a/src/boot/Makefile.am b/src/boot/Makefile.am index 9a3b320a..5a4ecaa1 100644 --- a/src/boot/Makefile.am +++ b/src/boot/Makefile.am @@ -1,6 +1,6 @@ # Copyright (c) 1991-2002, The Numerical Algorithms Group Ltd. # All rights reserved. -# Copyright (C) 2007-2014, Gabriel Dos Reis. +# Copyright (C) 2007-2017, Gabriel Dos Reis. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -74,7 +74,8 @@ bemol_SOURCES = \ bemol.cc bemol_LDADD = \ - $(oa_target_libdir)/libOpenAxiom.a + $(oa_target_libdir)/libOpenAxiom.a \ + $(oa_target_libdir)/libopen-axiom-core.a oa_target_bootdir = $(oa_targetdir)/boot if OA_ECL_RT diff --git a/src/boot/Makefile.in b/src/boot/Makefile.in index c3d91bec..885b9636 100644 --- a/src/boot/Makefile.in +++ b/src/boot/Makefile.in @@ -16,7 +16,7 @@ # Copyright (c) 1991-2002, The Numerical Algorithms Group Ltd. # All rights reserved. -# Copyright (C) 2007-2014, Gabriel Dos Reis. +# Copyright (C) 2007-2017, Gabriel Dos Reis. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -157,7 +157,8 @@ CONFIG_CLEAN_VPATH_FILES = PROGRAMS = $(noinst_PROGRAMS) am_bemol_OBJECTS = bemol.$(OBJEXT) bemol_OBJECTS = $(am_bemol_OBJECTS) -bemol_DEPENDENCIES = $(oa_target_libdir)/libOpenAxiom.a +bemol_DEPENDENCIES = $(oa_target_libdir)/libOpenAxiom.a \ + $(oa_target_libdir)/libopen-axiom-core.a AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent @@ -461,7 +462,8 @@ bemol_SOURCES = \ bemol.cc bemol_LDADD = \ - $(oa_target_libdir)/libOpenAxiom.a + $(oa_target_libdir)/libOpenAxiom.a \ + $(oa_target_libdir)/libopen-axiom-core.a oa_target_bootdir = $(oa_targetdir)/boot @OA_ECL_RT_FALSE@oa_bootsys_linkset = diff --git a/src/include/open-axiom/Parser b/src/include/open-axiom/Parser new file mode 100644 index 00000000..735e67d6 --- /dev/null +++ b/src/include/open-axiom/Parser @@ -0,0 +1,53 @@ +// -*- C++ -*- +// Copyright (C) 2016-2017, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// 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 OpenAxiom. 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. + +#ifndef OPENAXIOM_PARSER_included +#define OPENAXIOM_PARSER_included + +#include + +namespace OpenAxiom { + // Translate a Boot input source code to a Lisp source code. + // Both parameters point to the pathnames of the input source file + // and the output source file, respectively. Return zero on success. + extern "C" int boot_to_lisp(const char*, const char*); + + namespace Error { + // Exception type for filesystem error. + struct CannotOpenFile { + std::string path; + }; + } +} + +#endif // OPENAXIOM_PARSER_included diff --git a/src/include/open-axiom/dialect b/src/include/open-axiom/dialect index 5d5218c6..6350e91e 100644 --- a/src/include/open-axiom/dialect +++ b/src/include/open-axiom/dialect @@ -1,5 +1,5 @@ // -*- C++ -*- -// Copyright (C) 2013-2014, Gabriel Dos Reis. +// Copyright (C) 2013-2017, Gabriel Dos Reis. // All rights reserved. // Written by Gabriel Dos Reis. // @@ -34,14 +34,16 @@ #ifndef OPENAXIOM_DIALECT_included #define OPENAXIOM_DIALECT_included +#include + namespace OpenAxiom { // Languages for which we have parsers. - enum class Language { - Spad = 0x1, - Boot = 0x2, - Lisp = 0x4, - BootSpad = Spad | Boot, - All = Spad | Boot | Lisp, + enum class Language : uint8_t { + Spad = 0x1, // Spad programming language + Boot = 0x2, // Boot programming language + Lisp = 0x4, // Lisp programming language + BootSpad = Spad | Boot, // Boot or Spad + All = Spad | Boot | Lisp, // All supported programming languages }; } diff --git a/src/io/std-streams.cc b/src/io/std-streams.cc deleted file mode 100644 index a0a470ee..00000000 --- a/src/io/std-streams.cc +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (C) 2013, Gabriel Dos Reis. -// All rights reserved. -// Written by Gabriel Dos Reis. -// -// 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 OpenAxiom. 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 - -namespace OpenAxiom { - namespace Diagnostics { - StandardStream::StandardStream(std::ostream& o, std::ostream& e) - : out(&o), err(&e) - { } - - StandardStream::~StandardStream() = default; - - std::ostream& - StandardStream::set_output(std::ostream& os) { - auto prev = out; - out = &os; - return *prev; - } - - std::ostream& - StandardStream::set_error(std::ostream& os) { - auto prev = err; - err = &os; - return *prev; - } - } -} diff --git a/src/io/std-streams.cxx b/src/io/std-streams.cxx new file mode 100644 index 00000000..a0a470ee --- /dev/null +++ b/src/io/std-streams.cxx @@ -0,0 +1,57 @@ +// Copyright (C) 2013, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// 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 OpenAxiom. 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 + +namespace OpenAxiom { + namespace Diagnostics { + StandardStream::StandardStream(std::ostream& o, std::ostream& e) + : out(&o), err(&e) + { } + + StandardStream::~StandardStream() = default; + + std::ostream& + StandardStream::set_output(std::ostream& os) { + auto prev = out; + out = &os; + return *prev; + } + + std::ostream& + StandardStream::set_error(std::ostream& os) { + auto prev = err; + err = &os; + return *prev; + } + } +} diff --git a/src/lib/Makefile.in b/src/lib/Makefile.in index 7a8d4609..aeecfabf 100644 --- a/src/lib/Makefile.in +++ b/src/lib/Makefile.in @@ -1,4 +1,4 @@ -# Copyright (C) 2007-2016, Gabriel Dos Reis. +# Copyright (C) 2007-2017, Gabriel Dos Reis. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,7 +31,14 @@ -core_SOURCES = bsdsignal.c cfuns-c.c sockio-c.c +core_SOURCES = \ + bsdsignal.cxx \ + cfuns-c.cxx \ + sockio-c.cxx \ + ../io/std-streams.cxx \ + ../io/InputFragment.cxx \ + ../syntax/token.cxx \ + ../syntax/Parser.cxx terminal_io_SOURCES = cursor.c edin.c fnct_key.c openpty.c prt.c wct.c @@ -52,9 +59,9 @@ unused_SOURCES = emupty.c libopen_axiom_core_SOURCES = $(core_SOURCES) ifeq (@oa_use_libtool_for_shared_lib@,no) -libopen_axiom_core_objects = $(libopen_axiom_core_SOURCES:.c=.$(OBJEXT)) +libopen_axiom_core_objects = $(libopen_axiom_core_SOURCES:.cxx=.$(OBJEXT)) else -libopen_axiom_core_objects = $(libopen_axiom_core_SOURCES:.c=.lo) +libopen_axiom_core_objects = $(libopen_axiom_core_SOURCES:.cxx=.lo) endif libspad_objects = $(libspad_SOURCES:.c=.lo) @@ -67,7 +74,7 @@ subdir = src/lib/ .PHONY: all all-lib .SUFFIXES: -.SUFFIXES: .o .lib .obj .c .h +.SUFFIXES: .o .lib .obj .c .h .cxx all: all-ax @@ -90,14 +97,18 @@ $(oa_target_libdir)/$(oa_shrlib_prefix)open-axiom-core$(SHREXT): \ $(libopen_axiom_core_objects) \ @oa_c_runtime_extra@ -lm -libopen-axiom-core.$(LIBEXT): $(libopen_axiom_core_SOURCES:.c=.lo) - $(LINK) -o $@ $(libopen_axiom_core_SOURCES:.c=.lo) +libopen-axiom-core.$(LIBEXT): $(libopen_axiom_core_SOURCES:.cxx=.lo) + $(LINK) -o $@ $(libopen_axiom_core_SOURCES:.cxx=.lo) libspad.$(LIBEXT): $(libspad_objects) $(LINK) -o $@ $(libspad_objects) .PRECIOUS: %.$(OBJEXT) +%.$(OBJEXT) %.lo: %.cxx $(oa_c_macros_h) + $(COMPILE) $(oa_shrobj_flags) -no-suppress -o $@ $(CFLAGS) \ + $(oa_includes) $(AXIOM_X11_CFLAGS) $< + %.$(OBJEXT) %.lo: %.c $(oa_c_macros_h) $(COMPILE) $(oa_shrobj_flags) -no-suppress -o $@ $(CFLAGS) \ $(oa_includes) $(AXIOM_X11_CFLAGS) $< diff --git a/src/lib/bsdsignal.c b/src/lib/bsdsignal.c deleted file mode 100644 index 07fc6b54..00000000 --- a/src/lib/bsdsignal.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd. - All rights reserved. - Copyright (C) 2007-2010, 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 "openaxiom-c-macros.h" -#include -#include "bsdsignal.h" - -OPENAXIOM_C_EXPORT SignalHandlerFunc -bsdSignal(int sig, SignalHandlerFunc action, int restartSystemCall) -{ -#if HAVE_DECL_SIGACTION - - struct sigaction in,out; - in.sa_handler = action; - /* handler is reinstalled - calls are restarted if restartSystemCall */ -#ifdef SA_RESTART - if(restartSystemCall) in.sa_flags = SA_RESTART; - else in.sa_flags = 0; -#elif defined(SA_INTERRUPT) - if (restartSystemCall) in.sa_flags = 0; - else in.sa_flags = SA_INTERRUPT; -#else - in.sa_flags = 0; -#endif - - return (sigaction(sig, &in, &out) ? (SignalHandlerFunc) -1 : - (SignalHandlerFunc) out.sa_handler); -#else /* !HAVE_DECL_SIGACTION */ - return (SignalHandlerFunc) -1; -#endif /* HAVE_DECL_SIGACTION */ -} - - diff --git a/src/lib/bsdsignal.cxx b/src/lib/bsdsignal.cxx new file mode 100644 index 00000000..07fc6b54 --- /dev/null +++ b/src/lib/bsdsignal.cxx @@ -0,0 +1,65 @@ +/* + Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd. + All rights reserved. + Copyright (C) 2007-2010, 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 "openaxiom-c-macros.h" +#include +#include "bsdsignal.h" + +OPENAXIOM_C_EXPORT SignalHandlerFunc +bsdSignal(int sig, SignalHandlerFunc action, int restartSystemCall) +{ +#if HAVE_DECL_SIGACTION + + struct sigaction in,out; + in.sa_handler = action; + /* handler is reinstalled - calls are restarted if restartSystemCall */ +#ifdef SA_RESTART + if(restartSystemCall) in.sa_flags = SA_RESTART; + else in.sa_flags = 0; +#elif defined(SA_INTERRUPT) + if (restartSystemCall) in.sa_flags = 0; + else in.sa_flags = SA_INTERRUPT; +#else + in.sa_flags = 0; +#endif + + return (sigaction(sig, &in, &out) ? (SignalHandlerFunc) -1 : + (SignalHandlerFunc) out.sa_handler); +#else /* !HAVE_DECL_SIGACTION */ + return (SignalHandlerFunc) -1; +#endif /* HAVE_DECL_SIGACTION */ +} + + diff --git a/src/lib/cfuns-c.c b/src/lib/cfuns-c.c deleted file mode 100644 index 11c28691..00000000 --- a/src/lib/cfuns-c.c +++ /dev/null @@ -1,914 +0,0 @@ -/* - Copyright (C) 1991-2002, The Numerical Algorithms Group Ltd. - All rights reserved. - - Copyright (C) 2007-2013, 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 "openaxiom-c-macros.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#ifdef OPENAXIOM_MS_WINDOWS_HOST -# include -#else -# include -# include -#endif - -#include "cfuns.h" - -/* Most versions of Windows don't have the POSIX functions getuid(), - geteuid(), getgid(), and getegid(). The following definitions are - approximations, to patch for the deficiencies of Windows - POSIX interface. */ - -#if !HAVE_DECL_GETUID -# define getuid() 0 -#endif - -#if !HAVE_DECL_GETGID -# define getgid() 0 -#endif - -#if !HAVE_DECL_GETEUID -# define geteuid() getuid() -#endif - -#if !HAVE_DECL_GETEGID -# define getegid() getgid() -#endif - -namespace OpenAxiom { - // Make a copy of string data on free store. - static char* - copy_c_str(const std::string& s) { - return strdup(s.c_str()); - } - -OPENAXIOM_C_EXPORT int -addtopath(char *dir) -{ - char *path, *newpath; - - path = oa_getenv("PATH"); - if (path == NULL) - return -1; - - newpath = (char *) malloc(1 + strlen(path) + strlen(dir) + strlen("PATH=:")); - if (newpath == NULL) - return -1; - - sprintf(newpath, "PATH=%s:%s", path, dir); - - return putenv(newpath); -} - - - -/* Returns 1 if `c' designates a path separator, 0 otherwise. */ -static inline int -openaxiom_is_path_separator(char c) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - return c == '\\' || c == '/'; -#else - return c == '/'; -#endif -} - -/* - Returns a the dirname of `path'. If `path' has no separator, then - returns ".". The returned value if malloc-allocated. */ - -OPENAXIOM_C_EXPORT char* -oa_dirname(const char* path) -{ - const int n = strlen(path); - const char* mark = path + n; - - if (n == 0) - return strdup("."); - else if (n == 1 && openaxiom_is_path_separator(*path)) - return strdup("/"); - - /* For "/banana/space/", we want "/banana". */ - if (openaxiom_is_path_separator(*--mark)) - --mark; - while (path < mark && !openaxiom_is_path_separator(*mark)) - --mark; - - if (path == mark) - return strdup(openaxiom_is_path_separator(*path) ? "/" : "."); - else { - const int l = mark - path; - char* dir = (char*) malloc(l + 1); - memcpy(dir, path, l); - dir[l] = '\0'; - return dir; - } -} - -/* - * Test whether the path is the name of a directory. Returns 1 if so, 0 if - * not, -1 if it doesn't exist. - */ - - -OPENAXIOM_C_EXPORT int -directoryp(char *path) -{ - struct stat buf; - int code = stat(path, &buf); - - return code == -1 ? -1 : S_ISDIR(buf.st_mode); -} - -OPENAXIOM_C_EXPORT int -make_path_from_file(char *s, char *t) -{ - char *pos = NULL; - char *c; - - /** simply copies the path name from t into s **/ - for (c = t + strlen(t); c != s; c--) - if (*c == '/') { - pos = c; - break; - } - /** Check to see if the path was actually present **/ - if (c == t) { /** No Path, so return the pwd **/ - return (-1); - } - /** now just do the copying **/ - strncpy(s, t, pos - t); - return 1; -} - -/* The functions writeablep() and readablep() determine write and - read access of a file designated by its name. The function - axiom_has_write_access is a sub-routine of writeablep. - - The access is determined based on the POSIX semantics; see - "Advanced Programming in the UNIX Environement", section 4.5. - - 1. If the effective user ID of the process is 0 (the superuser), - access is allowed. This gives the superuser free rein throughout - the entire file system. - - 2. If the effective user ID of the process equals the owner ID of - the file (i.e., the process owns the file), access is allowed - if the appropriate user access permission bit is set. [...] - - 3. If the effective group ID of the process or one of the - supplementary group IDs of the process equals the group ID - of the file, access is allowed if the appropriate - group access permission bit is set. Otherwise, permission - is denied. - - 4. If the appropriate other access permission bit is set, access is - allowed. Otherwise, permission is defined. */ - - -/* Return 1 if the process has write access of file as explained above. - Otherwise, return 0. */ - -static inline int -axiom_has_write_access(const struct stat* file_info) -{ - uid_t effetive_uid = geteuid(); - - if (effetive_uid == 0) - return 1; - - if (effetive_uid == file_info->st_uid) - return (file_info->st_mode & S_IWUSR) ? 1 : 0; - -#ifdef S_IWGRP - if (getegid() == file_info->st_gid) - return (file_info->st_mode & S_IWGRP) ? 1 : 0; -#endif - -#ifdef S_IWOTH - return (file_info->st_mode & S_IWOTH) ? 1 : 0; -#else - return 0; -#endif -} - - -/* Return - -1 if the file designated by PATH is inexistent. - 0 if the file exists but write access is denied. - 1 if the file exists and process has write access. - 2 if the file does not exists but process has write - has write access to the dirname of path. */ - -OPENAXIOM_C_EXPORT int -writeablep(const char *path) -{ - struct stat buf; - int code; - - code = stat(path, &buf); - if (code == -1) { - /* The file does not exist, so check to see if the directory - is writable. */ - char* dir = oa_dirname(path); - code = stat(dir, &buf); - /* FIXME: Work around MinGW/MSYS bug. - The string pointed to by `dir' was strdup'd. According to - the C standard, that means the the string was allocated - by `malloc', therefore can be disposed of by `free'. However, - the MinGW/MSYS port appears to use MS' StrDup as the real - worker. Consequently, the guarantee that the the string can - free'd no longer holds. We have to use MS's LocalFree. */ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - LocalFree(dir); -#else - free(dir); -#endif - return (code == 0) && axiom_has_write_access(&buf) ? 2 : -1; - } - - return axiom_has_write_access(&buf); -} - - -/* Return - -1 if the file designated by PATH is inexistent. - 0 if the file exists but process has no read access. - 1 if the file exists and read access is granted. */ - -OPENAXIOM_C_EXPORT int -readablep(const char *path) -{ - struct stat buf; - int code; - - code = stat(path, &buf); - if (code == -1) - return -1; - - if (geteuid() == buf.st_uid) - return ((buf.st_mode & S_IREAD) != 0); - -#ifdef S_IRGRP - if (getegid() == buf.st_gid) - return ((buf.st_mode & S_IRGRP) != 0); -#endif - -#ifdef S_IROTH - return ((buf.st_mode & S_IROTH) != 0); -#else - return 0; -#endif -} - - - -OPENAXIOM_C_EXPORT long -findString(char *file, char *string) -{ - int nstring, charpos; - FILE *fn; - char buffer[1024]; - - if ((fn = fopen(file, "r")) == NULL) - return -1; - - for (charpos = 0, nstring = strlen(string); - fgets(buffer, sizeof buffer, fn) != NULL; - charpos += strlen(buffer) - ) - if (!strncmp(buffer, string, nstring)) - return charpos; - return -1; - -} - -OPENAXIOM_C_EXPORT int -copyEnvValue(char *varName, char *buffer) -{ - char *s; - - s = oa_getenv(varName); - if (s == NULL) - return 0; - strcpy(buffer, s); - return strlen(s); -} - -/* Return 1 if the file descriptor FD, as viewed by the Core Executable, - is attached to a terminal. */ -OPENAXIOM_C_EXPORT int -std_stream_is_terminal(int fd) -{ - assert(fd > -1 && fd < 3); -#ifdef OPENAXIOM_MS_WINDOWS_HOST - DWORD handle; - switch (fd) { - case 0: handle = STD_INPUT_HANDLE; break; - case 1: handle = STD_OUTPUT_HANDLE; break; - case 2: handle = STD_ERROR_HANDLE; break; - /* Next code is never executed but it makes the compiler happy. */ - default: return 0; - } - /* The MS documentation suggests `GetFileType' for determining - the nature of the file handle. The return value, in our case, - is an over approximation of what we are interested in: Are we - dealing with a stream connected to a terminal? The constant - FILE_TYPE_CHAR characterises character files; in particular - a console terminal, or a printer. There is an undocumented - function `VerifyConsoleIoHandle' to deal precisely with the case - we are interested in. However, while availale in Wine, it is - not available in the MinGW headers. Consequently, we cannot - rely on it for the moment. - So, we may still get garbage out of this function on MS platforms. */ - return GetFileType(GetStdHandle(handle)) == FILE_TYPE_CHAR; -#else - return isatty(fd); -#endif -} - -/* Change the process' curretnt directory. Return zero on success, - and -1 on failure. */ -OPENAXIOM_C_EXPORT int -oa_chdir(const char* path) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - return SetCurrentDirectory(path) ? 0 : -1; -#else - return chdir(path); -#endif /* OPENAXIOM_MS_WINDOWS_HOST */ -} - - -/* return true if path is `.' or `..'. */ -static inline int -is_dot_or_dotdot(const char* path) -{ - return strcmp(path, ".") == 0 || strcmp(path, "..") == 0; -} - -/* Remove a directory entry. Files are removed, directories are - recursively walked and removed. - Return 0 on success, and -1 on falure. - In practice, OpenAxiom does not remove directories with - non-trivial recursive structues. */ -OPENAXIOM_C_EXPORT int -oa_unlink(const char* path) -{ - const char* curdir; - int status = -1; -#ifdef OPENAXIOM_MS_WINDOWS_HOST - WIN32_FIND_DATA findData; - HANDLE walkHandle; - - if (is_dot_or_dotdot(path)) - return -1; - - walkHandle = FindFirstFile(path, &findData); - if (walkHandle == INVALID_HANDLE_VALUE) - return -1; - - /* Remember where we are so we can return back properly. */ - curdir = oa_getcwd(); - - do { - if (is_dot_or_dotdot(findData.cFileName)) - continue; - if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - if ((status = oa_chdir(findData.cFileName)) < 0) - goto sortie; - if ((status = oa_unlink("*")) < 0) - goto sortie; - if ((status = oa_chdir("..")) < 0) - goto sortie; - if(!RemoveDirectory(findData.cFileName)) { - status = -1; - goto sortie; - } - } - else if (!DeleteFile(findData.cFileName)) { - status = -1; - goto sortie; - } - status = 0; - } while (FindNextFile(walkHandle, &findData)); - if (!FindClose(walkHandle)) { - status = -1; - goto sortie; - } -#else - struct stat pathstat; - DIR* dir; - struct dirent* entry; - - /* Don't ever try to remove `.' or `..'. */ - if (is_dot_or_dotdot(path)) - return -1; - - if (stat(path, &pathstat) < 0) - return -1; - - /* handle non directories first. */ - if (!S_ISDIR(pathstat.st_mode)) - return unlink(path); - - /* change into the path so that we don't have to form full - pathnames. */ - curdir = oa_getcwd(); - if ((dir = opendir(path)) == NULL || oa_chdir(path) < 0) - goto sortie; - - while (errno = 0, (entry = readdir(dir)) != NULL) { - struct stat s; - if (is_dot_or_dotdot(entry->d_name)) - continue; - if ((status = stat(entry->d_name, &s)) < 0) - goto sortie; - if (S_ISDIR(s.st_mode)) { - if ((status = oa_unlink(entry->d_name)) < 0) - goto sortie; - } - else if ((status = unlink(entry->d_name)) < 0) - goto sortie; - } - if (errno != 0) { - status = -1; - goto sortie; - } - - /* Now, get one level up, and remove the empty directory. */ - if (oa_chdir("..") < 0 || closedir(dir) < 0 || rmdir(path) < 0) - status = -1; - else - status = 0; -#endif /* OPENAXIOM_MS_WINDOWS_HOST */ - - sortie: - oa_chdir(curdir); - free((char*) curdir); - return status; -} - -OPENAXIOM_C_EXPORT const char* -oa_acquire_temporary_pathname() { -#if OPENAXIOM_MS_WINDOWS_HOST - char buf[MAX_PATH]; - const char* tmpdir = oa_get_tmpdir(); - auto n = GetTempFileName(tmpdir, "oa-", random() % SHRT_MAX, buf); - /* tmpdir was malloc()ed when OPENAXIOM_MS_WINDOWS_HOST. */ - free(const_cast(tmpdir)); - if (n == 0) { - perror("oa_acquire_temporary_pathname"); - exit(1); - } - return strdup(buf); -#elif HAVE_DECL_MKTEMP - return mktemp(copy_c_str(std::string{ oa_get_tmpdir() } + "/oa-XXXXXX")); -#elif HAVE_DECL_TEMPNAM - return tempnam(oa_get_tmpdir(), "oa-"); -#else - return copy_c_str("oa-" + std::to_string(random())); -#endif -} - -OPENAXIOM_C_EXPORT void -oa_release_temporary_pathname(const char* s) -{ - free(const_cast(s)); // yuck! -} - -/* Rename a file or directory. */ -OPENAXIOM_C_EXPORT int -oa_rename(const char* old_path, const char* new_path) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - return MoveFile(old_path, new_path) ? 0 : -1; -#else - return rename(old_path, new_path); -#endif -} - -/* Create a new directory named `path'. Return 0 on success, - and -1 on failure. */ -OPENAXIOM_C_EXPORT int -oa_mkdir(const char* path) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - return CreateDirectory(path, NULL) ? 0 : -1; -#else -# define DIRECTORY_PERM ((S_IRWXU|S_IRWXG|S_IRWXO) & ~(S_IWGRP|S_IWOTH)) - return mkdir (path, DIRECTORY_PERM); -# undef DIRECTORY_PERM -#endif -} - -/* Run a shell command. Effectively forward to C's system(). */ -OPENAXIOM_C_EXPORT int -oa_system(const char* cmd) -{ - return system(cmd); -} - -OPENAXIOM_C_EXPORT int -oa_getpid(void) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - return GetCurrentProcessId(); -#else - return getpid(); -#endif -} - -/* Concatenate two strings and return a pointer to the - newly allocate resulting string. */ -OPENAXIOM_C_EXPORT const char* -oa_concatenate_string(const char* lhs, const char* rhs) -{ - if (lhs == NULL) - return rhs; - else if (rhs == NULL) - return lhs; - else { - const int lhs_length = strlen(lhs); - char* result = (char*) malloc(lhs_length + strlen(rhs) + 1); - strcpy(result, lhs); - strcpy(result + lhs_length, rhs); - return result; - } -} - -/* Return a string object that is the result of catenating the strings - designated by `left' and `right'. */ -OPENAXIOM_C_EXPORT const char* -oa_strcat(const char* left, const char* right) -{ - int left_size = strlen(left); - int right_size = strlen(right); - int size = left_size + right_size; - char* buffer = (char*) malloc(size + 1); - - memcpy(buffer, left, left_size); - memcpy(buffer + left_size, right, right_size); - buffer[size] = '\0'; - return buffer; -} - -/* Return the value of an environment variable. */ -OPENAXIOM_C_EXPORT char* -oa_getenv(const char* var) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST -#define BUFSIZE 128 - char* buf = (char*) malloc(BUFSIZE); - int len = GetEnvironmentVariable(var, buf, BUFSIZE); - if (len == 0) { - free(buf); - return NULL; - } - else if (len > BUFSIZE) { - buf = (char*) realloc(buf,len); - len = GetEnvironmentVariable(var, buf, len); - if (len == 0) { - free(buf); - return NULL; - } - } - return buf; -#else - return getenv(var); -#endif -} - -/* Set the value of environment variable VAR to VAL. - Return 1 on success, and 0 otherwise. */ -OPENAXIOM_C_EXPORT int -oa_setenv(const char* var, const char* val) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - return SetEnvironmentVariable(var, val); -#elif HAVE_DECL_SETENV - return !setenv(var, val, true); -#else - const int var_length = strlen(var); - const int val_length = strlen(val); - char* str = (char*) malloc(var_length + 1 + val_length + 1); - strcpy(str, var); - str[var_length] = '='; - strcpy(str + var_length + 1, val); - str[var_length + 1 + val_length] = '\0'; - return !putenv(str); -#endif -} - - -OPENAXIOM_C_EXPORT char* -oa_getcwd(void) -{ - size_t bufsz = 256; - char* buf = (char*) malloc(bufsz); -#ifdef OPENAXIOM_MS_WINDOWS_HOST - DWORD n = GetCurrentDirectory(bufsz, buf); - if (n == 0) { - perror("oa_getcwd"); - exit(-1); - } - else if (n > bufsz) { - buf = (char*) realloc(buf,n); - if (GetCurrentDirectory(n, buf) != n) { - perror("oa_getcwd"); - exit(-1); - } - } - return buf; -#else /* OPENAXIOM_MS_WINDOWS_HOST */ - errno = 0; - while (getcwd(buf,bufsz) == 0) { - if (errno == ERANGE) { - errno = 0; - bufsz *= 2; - buf = (char*) realloc(buf, bufsz); - } - else { - perror("oa_getcwd"); - exit(-1); - } - } - return buf; -#endif -} - -OPENAXIOM_C_EXPORT int -oa_access_file_for_read(const char* path) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - return GetFileAttributes(path) == INVALID_FILE_ATTRIBUTES ? -1 : 1; -#else - return access(path, R_OK); -#endif -} - - -OPENAXIOM_C_EXPORT const char* -oa_get_tmpdir(void) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - char* buf; - /* First, probe. */ - int bufsz = GetTempPath(0, NULL); - if (bufsz == 0) { - perror("oa_get_tmpdir"); - exit(1); - } - else { - int new_size; - buf = (char*) malloc(bufsz + 1); - new_size = GetTempPath(bufsz, buf); - if(new_size == 0 || new_size >= bufsz) { - perror("oa_get_tmpdir"); - free(buf); - exit(1); - } - buf[new_size] = '\0'; - } - return buf; -#else - return "/tmp"; -#endif -} - - -OPENAXIOM_C_EXPORT int -oa_copy_file(const char* src, const char* dst) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - return CopyFile(src,dst, /* bFailIfExists = */ 0) ? 0 : -1; -#else -#define OA_BUFSZ 512 -#define OA_DEFAULT_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) - char buf[OA_BUFSZ]; - int src_fd; - int dst_fd; - int count; - if((src_fd = open(src, O_RDONLY)) < 0) - return -1; - if ((dst_fd = creat(dst, OA_DEFAULT_MODE)) < 0) { - close(src_fd); - return -1; - } - - while ((count = read(src_fd, buf, OA_BUFSZ)) > 0) - if (write(dst_fd, buf, count) != count) - break; - -#undef OA_DEFAULT_MODE -#undef OA_BUFSZ - return (close(dst_fd) < 0 || close(src_fd) < 0 || count < 0) ? -1 : 0; -#endif -} - - -OPENAXIOM_C_EXPORT double -plus_infinity(void ) -{ -#ifdef INFINITY - return INFINITY; -#else - /* This must be a curious platform. */ - volatile double zero = 0.0; - return 1.0 / zero; /* If it traps, well, it traps. */ -#endif -} - -OPENAXIOM_C_EXPORT double -minus_infinity(void) -{ - return -plus_infinity(); -} - -OPENAXIOM_C_EXPORT double -quiet_double_NaN(void) -{ -#ifdef NAN - return NAN; -#else - return sqrt(-1.0); /* Just pick one. */ -#endif -} - - -OPENAXIOM_C_EXPORT Byteorder -oa_get_host_byteorder(void) -{ -#ifdef WORDS_BIGENDIAN - return Byteorder::big; -#else - return Byteorder::little; -#endif -} - - -OPENAXIOM_C_EXPORT void -oa_allocate_process_argv(Process* proc, int argc) -{ - proc->argc = argc; - proc->argv = (char**) malloc((1 + argc) * sizeof (char*)); - proc->argv[argc] = NULL; -} - -OPENAXIOM_C_EXPORT int -oa_spawn(Process* proc, SpawnFlags flags) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - const char* path = NULL; - char* cmd_line = NULL; - int curpos = strlen(proc->argv[0]); - int cmd_line_length = curpos; - int i; - PROCESS_INFORMATION proc_info; - STARTUPINFO startup_info = { 0 }; - DWORD status; - - for (i = 0; i < proc->argc; ++i) - cmd_line_length += 1 + strlen(proc->argv[i]); - - cmd_line = (char*) malloc(cmd_line_length + 1); - strcpy(cmd_line, proc->argv[0]); - for (i = 0; i < proc->argc; ++i) { - cmd_line[curpos++] = ' '; - strcpy(cmd_line + curpos, proc->argv[i]); - curpos += strlen(proc->argv[i]); - } - cmd_line[curpos] = '\0'; - - if ((flags & SpawnFlags::search_path) == 0) - path = proc->argv[0]; - - if(CreateProcess(/* lpApplicationName */ path, - /* lpCommandLine */ cmd_line, - /* lpProcessAttributes */ NULL, - /* lpThreadAttributes */ NULL, - /* bInheritHandles */ TRUE, - /* dwCreationFlags */ 0, - /* lpEnvironment */ NULL, - /* lpCurrentDirectory */ NULL, - /* lpstartupInfo */ &startup_info, - /* lpProcessInformation */ &proc_info) == 0) { - fprintf(stderr, "oa_spawn: error %lu\n", GetLastError()); - return proc->id = -1; - } - proc->id = proc_info.dwProcessId; - if ((flags & SpawnFlags::replace) == 0) - return proc->id; - WaitForSingleObject(proc_info.hProcess, INFINITE); - GetExitCodeProcess(proc_info.hProcess, &status); - CloseHandle(proc_info.hThread); - CloseHandle(proc_info.hProcess); - return status; - -#else - proc->id = 0; - if ((flags & SpawnFlags::replace) == 0) - proc->id = fork(); - if (proc->id == 0) { - if (flags & SpawnFlags::search_path) - execvp(proc->argv[0], proc->argv); - else - execv(proc->argv[0], proc->argv); - perror(strerror(errno)); - /* Don't keep useless clones around. */ - if ((flags & SpawnFlags::replace) == 0) - exit(-1); - } - return proc->id; -#endif -} - -OPENAXIOM_C_EXPORT char* -oa_substr(const char* str, const size_t begin, const size_t end) -{ - char* substring; - int len; - - if (str == NULL || strlen(str) == 0 || - strlen(str) < begin || end >= strlen(str) || begin > end) - return NULL; - - len = (end - begin) + 2; - substring = (char*) malloc(len * sizeof(char)); - memset(substring,'\0',len); - memcpy(substring, str+begin, len-1); - - return substring; -} - -OPENAXIOM_C_EXPORT char** -oa_split(const char* sequence, const char* delimiter, int* size) -{ - int sequence_length = 0, newsize = 0; - char* token; - char** tokens = NULL; - char* sequence_copy; - - sequence_length = strlen(sequence); - sequence_copy = (char*) malloc((sequence_length + 1) * sizeof(char*)); - strcpy(sequence_copy,sequence); - sequence_copy[sequence_length] = '\0'; - - token = strtok(sequence_copy, delimiter); - while (token != NULL) { - - tokens = (char**) realloc(tokens,(newsize + 1) * sizeof(char*)); - tokens[newsize] = token; - newsize++; - token = strtok (NULL, delimiter); - } - - *size = newsize; - - return tokens; -} - -} diff --git a/src/lib/cfuns-c.cxx b/src/lib/cfuns-c.cxx new file mode 100644 index 00000000..11c28691 --- /dev/null +++ b/src/lib/cfuns-c.cxx @@ -0,0 +1,914 @@ +/* + Copyright (C) 1991-2002, The Numerical Algorithms Group Ltd. + All rights reserved. + + Copyright (C) 2007-2013, 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 "openaxiom-c-macros.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef OPENAXIOM_MS_WINDOWS_HOST +# include +#else +# include +# include +#endif + +#include "cfuns.h" + +/* Most versions of Windows don't have the POSIX functions getuid(), + geteuid(), getgid(), and getegid(). The following definitions are + approximations, to patch for the deficiencies of Windows + POSIX interface. */ + +#if !HAVE_DECL_GETUID +# define getuid() 0 +#endif + +#if !HAVE_DECL_GETGID +# define getgid() 0 +#endif + +#if !HAVE_DECL_GETEUID +# define geteuid() getuid() +#endif + +#if !HAVE_DECL_GETEGID +# define getegid() getgid() +#endif + +namespace OpenAxiom { + // Make a copy of string data on free store. + static char* + copy_c_str(const std::string& s) { + return strdup(s.c_str()); + } + +OPENAXIOM_C_EXPORT int +addtopath(char *dir) +{ + char *path, *newpath; + + path = oa_getenv("PATH"); + if (path == NULL) + return -1; + + newpath = (char *) malloc(1 + strlen(path) + strlen(dir) + strlen("PATH=:")); + if (newpath == NULL) + return -1; + + sprintf(newpath, "PATH=%s:%s", path, dir); + + return putenv(newpath); +} + + + +/* Returns 1 if `c' designates a path separator, 0 otherwise. */ +static inline int +openaxiom_is_path_separator(char c) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + return c == '\\' || c == '/'; +#else + return c == '/'; +#endif +} + +/* + Returns a the dirname of `path'. If `path' has no separator, then + returns ".". The returned value if malloc-allocated. */ + +OPENAXIOM_C_EXPORT char* +oa_dirname(const char* path) +{ + const int n = strlen(path); + const char* mark = path + n; + + if (n == 0) + return strdup("."); + else if (n == 1 && openaxiom_is_path_separator(*path)) + return strdup("/"); + + /* For "/banana/space/", we want "/banana". */ + if (openaxiom_is_path_separator(*--mark)) + --mark; + while (path < mark && !openaxiom_is_path_separator(*mark)) + --mark; + + if (path == mark) + return strdup(openaxiom_is_path_separator(*path) ? "/" : "."); + else { + const int l = mark - path; + char* dir = (char*) malloc(l + 1); + memcpy(dir, path, l); + dir[l] = '\0'; + return dir; + } +} + +/* + * Test whether the path is the name of a directory. Returns 1 if so, 0 if + * not, -1 if it doesn't exist. + */ + + +OPENAXIOM_C_EXPORT int +directoryp(char *path) +{ + struct stat buf; + int code = stat(path, &buf); + + return code == -1 ? -1 : S_ISDIR(buf.st_mode); +} + +OPENAXIOM_C_EXPORT int +make_path_from_file(char *s, char *t) +{ + char *pos = NULL; + char *c; + + /** simply copies the path name from t into s **/ + for (c = t + strlen(t); c != s; c--) + if (*c == '/') { + pos = c; + break; + } + /** Check to see if the path was actually present **/ + if (c == t) { /** No Path, so return the pwd **/ + return (-1); + } + /** now just do the copying **/ + strncpy(s, t, pos - t); + return 1; +} + +/* The functions writeablep() and readablep() determine write and + read access of a file designated by its name. The function + axiom_has_write_access is a sub-routine of writeablep. + + The access is determined based on the POSIX semantics; see + "Advanced Programming in the UNIX Environement", section 4.5. + + 1. If the effective user ID of the process is 0 (the superuser), + access is allowed. This gives the superuser free rein throughout + the entire file system. + + 2. If the effective user ID of the process equals the owner ID of + the file (i.e., the process owns the file), access is allowed + if the appropriate user access permission bit is set. [...] + + 3. If the effective group ID of the process or one of the + supplementary group IDs of the process equals the group ID + of the file, access is allowed if the appropriate + group access permission bit is set. Otherwise, permission + is denied. + + 4. If the appropriate other access permission bit is set, access is + allowed. Otherwise, permission is defined. */ + + +/* Return 1 if the process has write access of file as explained above. + Otherwise, return 0. */ + +static inline int +axiom_has_write_access(const struct stat* file_info) +{ + uid_t effetive_uid = geteuid(); + + if (effetive_uid == 0) + return 1; + + if (effetive_uid == file_info->st_uid) + return (file_info->st_mode & S_IWUSR) ? 1 : 0; + +#ifdef S_IWGRP + if (getegid() == file_info->st_gid) + return (file_info->st_mode & S_IWGRP) ? 1 : 0; +#endif + +#ifdef S_IWOTH + return (file_info->st_mode & S_IWOTH) ? 1 : 0; +#else + return 0; +#endif +} + + +/* Return + -1 if the file designated by PATH is inexistent. + 0 if the file exists but write access is denied. + 1 if the file exists and process has write access. + 2 if the file does not exists but process has write + has write access to the dirname of path. */ + +OPENAXIOM_C_EXPORT int +writeablep(const char *path) +{ + struct stat buf; + int code; + + code = stat(path, &buf); + if (code == -1) { + /* The file does not exist, so check to see if the directory + is writable. */ + char* dir = oa_dirname(path); + code = stat(dir, &buf); + /* FIXME: Work around MinGW/MSYS bug. + The string pointed to by `dir' was strdup'd. According to + the C standard, that means the the string was allocated + by `malloc', therefore can be disposed of by `free'. However, + the MinGW/MSYS port appears to use MS' StrDup as the real + worker. Consequently, the guarantee that the the string can + free'd no longer holds. We have to use MS's LocalFree. */ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + LocalFree(dir); +#else + free(dir); +#endif + return (code == 0) && axiom_has_write_access(&buf) ? 2 : -1; + } + + return axiom_has_write_access(&buf); +} + + +/* Return + -1 if the file designated by PATH is inexistent. + 0 if the file exists but process has no read access. + 1 if the file exists and read access is granted. */ + +OPENAXIOM_C_EXPORT int +readablep(const char *path) +{ + struct stat buf; + int code; + + code = stat(path, &buf); + if (code == -1) + return -1; + + if (geteuid() == buf.st_uid) + return ((buf.st_mode & S_IREAD) != 0); + +#ifdef S_IRGRP + if (getegid() == buf.st_gid) + return ((buf.st_mode & S_IRGRP) != 0); +#endif + +#ifdef S_IROTH + return ((buf.st_mode & S_IROTH) != 0); +#else + return 0; +#endif +} + + + +OPENAXIOM_C_EXPORT long +findString(char *file, char *string) +{ + int nstring, charpos; + FILE *fn; + char buffer[1024]; + + if ((fn = fopen(file, "r")) == NULL) + return -1; + + for (charpos = 0, nstring = strlen(string); + fgets(buffer, sizeof buffer, fn) != NULL; + charpos += strlen(buffer) + ) + if (!strncmp(buffer, string, nstring)) + return charpos; + return -1; + +} + +OPENAXIOM_C_EXPORT int +copyEnvValue(char *varName, char *buffer) +{ + char *s; + + s = oa_getenv(varName); + if (s == NULL) + return 0; + strcpy(buffer, s); + return strlen(s); +} + +/* Return 1 if the file descriptor FD, as viewed by the Core Executable, + is attached to a terminal. */ +OPENAXIOM_C_EXPORT int +std_stream_is_terminal(int fd) +{ + assert(fd > -1 && fd < 3); +#ifdef OPENAXIOM_MS_WINDOWS_HOST + DWORD handle; + switch (fd) { + case 0: handle = STD_INPUT_HANDLE; break; + case 1: handle = STD_OUTPUT_HANDLE; break; + case 2: handle = STD_ERROR_HANDLE; break; + /* Next code is never executed but it makes the compiler happy. */ + default: return 0; + } + /* The MS documentation suggests `GetFileType' for determining + the nature of the file handle. The return value, in our case, + is an over approximation of what we are interested in: Are we + dealing with a stream connected to a terminal? The constant + FILE_TYPE_CHAR characterises character files; in particular + a console terminal, or a printer. There is an undocumented + function `VerifyConsoleIoHandle' to deal precisely with the case + we are interested in. However, while availale in Wine, it is + not available in the MinGW headers. Consequently, we cannot + rely on it for the moment. + So, we may still get garbage out of this function on MS platforms. */ + return GetFileType(GetStdHandle(handle)) == FILE_TYPE_CHAR; +#else + return isatty(fd); +#endif +} + +/* Change the process' curretnt directory. Return zero on success, + and -1 on failure. */ +OPENAXIOM_C_EXPORT int +oa_chdir(const char* path) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + return SetCurrentDirectory(path) ? 0 : -1; +#else + return chdir(path); +#endif /* OPENAXIOM_MS_WINDOWS_HOST */ +} + + +/* return true if path is `.' or `..'. */ +static inline int +is_dot_or_dotdot(const char* path) +{ + return strcmp(path, ".") == 0 || strcmp(path, "..") == 0; +} + +/* Remove a directory entry. Files are removed, directories are + recursively walked and removed. + Return 0 on success, and -1 on falure. + In practice, OpenAxiom does not remove directories with + non-trivial recursive structues. */ +OPENAXIOM_C_EXPORT int +oa_unlink(const char* path) +{ + const char* curdir; + int status = -1; +#ifdef OPENAXIOM_MS_WINDOWS_HOST + WIN32_FIND_DATA findData; + HANDLE walkHandle; + + if (is_dot_or_dotdot(path)) + return -1; + + walkHandle = FindFirstFile(path, &findData); + if (walkHandle == INVALID_HANDLE_VALUE) + return -1; + + /* Remember where we are so we can return back properly. */ + curdir = oa_getcwd(); + + do { + if (is_dot_or_dotdot(findData.cFileName)) + continue; + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + if ((status = oa_chdir(findData.cFileName)) < 0) + goto sortie; + if ((status = oa_unlink("*")) < 0) + goto sortie; + if ((status = oa_chdir("..")) < 0) + goto sortie; + if(!RemoveDirectory(findData.cFileName)) { + status = -1; + goto sortie; + } + } + else if (!DeleteFile(findData.cFileName)) { + status = -1; + goto sortie; + } + status = 0; + } while (FindNextFile(walkHandle, &findData)); + if (!FindClose(walkHandle)) { + status = -1; + goto sortie; + } +#else + struct stat pathstat; + DIR* dir; + struct dirent* entry; + + /* Don't ever try to remove `.' or `..'. */ + if (is_dot_or_dotdot(path)) + return -1; + + if (stat(path, &pathstat) < 0) + return -1; + + /* handle non directories first. */ + if (!S_ISDIR(pathstat.st_mode)) + return unlink(path); + + /* change into the path so that we don't have to form full + pathnames. */ + curdir = oa_getcwd(); + if ((dir = opendir(path)) == NULL || oa_chdir(path) < 0) + goto sortie; + + while (errno = 0, (entry = readdir(dir)) != NULL) { + struct stat s; + if (is_dot_or_dotdot(entry->d_name)) + continue; + if ((status = stat(entry->d_name, &s)) < 0) + goto sortie; + if (S_ISDIR(s.st_mode)) { + if ((status = oa_unlink(entry->d_name)) < 0) + goto sortie; + } + else if ((status = unlink(entry->d_name)) < 0) + goto sortie; + } + if (errno != 0) { + status = -1; + goto sortie; + } + + /* Now, get one level up, and remove the empty directory. */ + if (oa_chdir("..") < 0 || closedir(dir) < 0 || rmdir(path) < 0) + status = -1; + else + status = 0; +#endif /* OPENAXIOM_MS_WINDOWS_HOST */ + + sortie: + oa_chdir(curdir); + free((char*) curdir); + return status; +} + +OPENAXIOM_C_EXPORT const char* +oa_acquire_temporary_pathname() { +#if OPENAXIOM_MS_WINDOWS_HOST + char buf[MAX_PATH]; + const char* tmpdir = oa_get_tmpdir(); + auto n = GetTempFileName(tmpdir, "oa-", random() % SHRT_MAX, buf); + /* tmpdir was malloc()ed when OPENAXIOM_MS_WINDOWS_HOST. */ + free(const_cast(tmpdir)); + if (n == 0) { + perror("oa_acquire_temporary_pathname"); + exit(1); + } + return strdup(buf); +#elif HAVE_DECL_MKTEMP + return mktemp(copy_c_str(std::string{ oa_get_tmpdir() } + "/oa-XXXXXX")); +#elif HAVE_DECL_TEMPNAM + return tempnam(oa_get_tmpdir(), "oa-"); +#else + return copy_c_str("oa-" + std::to_string(random())); +#endif +} + +OPENAXIOM_C_EXPORT void +oa_release_temporary_pathname(const char* s) +{ + free(const_cast(s)); // yuck! +} + +/* Rename a file or directory. */ +OPENAXIOM_C_EXPORT int +oa_rename(const char* old_path, const char* new_path) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + return MoveFile(old_path, new_path) ? 0 : -1; +#else + return rename(old_path, new_path); +#endif +} + +/* Create a new directory named `path'. Return 0 on success, + and -1 on failure. */ +OPENAXIOM_C_EXPORT int +oa_mkdir(const char* path) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + return CreateDirectory(path, NULL) ? 0 : -1; +#else +# define DIRECTORY_PERM ((S_IRWXU|S_IRWXG|S_IRWXO) & ~(S_IWGRP|S_IWOTH)) + return mkdir (path, DIRECTORY_PERM); +# undef DIRECTORY_PERM +#endif +} + +/* Run a shell command. Effectively forward to C's system(). */ +OPENAXIOM_C_EXPORT int +oa_system(const char* cmd) +{ + return system(cmd); +} + +OPENAXIOM_C_EXPORT int +oa_getpid(void) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + return GetCurrentProcessId(); +#else + return getpid(); +#endif +} + +/* Concatenate two strings and return a pointer to the + newly allocate resulting string. */ +OPENAXIOM_C_EXPORT const char* +oa_concatenate_string(const char* lhs, const char* rhs) +{ + if (lhs == NULL) + return rhs; + else if (rhs == NULL) + return lhs; + else { + const int lhs_length = strlen(lhs); + char* result = (char*) malloc(lhs_length + strlen(rhs) + 1); + strcpy(result, lhs); + strcpy(result + lhs_length, rhs); + return result; + } +} + +/* Return a string object that is the result of catenating the strings + designated by `left' and `right'. */ +OPENAXIOM_C_EXPORT const char* +oa_strcat(const char* left, const char* right) +{ + int left_size = strlen(left); + int right_size = strlen(right); + int size = left_size + right_size; + char* buffer = (char*) malloc(size + 1); + + memcpy(buffer, left, left_size); + memcpy(buffer + left_size, right, right_size); + buffer[size] = '\0'; + return buffer; +} + +/* Return the value of an environment variable. */ +OPENAXIOM_C_EXPORT char* +oa_getenv(const char* var) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST +#define BUFSIZE 128 + char* buf = (char*) malloc(BUFSIZE); + int len = GetEnvironmentVariable(var, buf, BUFSIZE); + if (len == 0) { + free(buf); + return NULL; + } + else if (len > BUFSIZE) { + buf = (char*) realloc(buf,len); + len = GetEnvironmentVariable(var, buf, len); + if (len == 0) { + free(buf); + return NULL; + } + } + return buf; +#else + return getenv(var); +#endif +} + +/* Set the value of environment variable VAR to VAL. + Return 1 on success, and 0 otherwise. */ +OPENAXIOM_C_EXPORT int +oa_setenv(const char* var, const char* val) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + return SetEnvironmentVariable(var, val); +#elif HAVE_DECL_SETENV + return !setenv(var, val, true); +#else + const int var_length = strlen(var); + const int val_length = strlen(val); + char* str = (char*) malloc(var_length + 1 + val_length + 1); + strcpy(str, var); + str[var_length] = '='; + strcpy(str + var_length + 1, val); + str[var_length + 1 + val_length] = '\0'; + return !putenv(str); +#endif +} + + +OPENAXIOM_C_EXPORT char* +oa_getcwd(void) +{ + size_t bufsz = 256; + char* buf = (char*) malloc(bufsz); +#ifdef OPENAXIOM_MS_WINDOWS_HOST + DWORD n = GetCurrentDirectory(bufsz, buf); + if (n == 0) { + perror("oa_getcwd"); + exit(-1); + } + else if (n > bufsz) { + buf = (char*) realloc(buf,n); + if (GetCurrentDirectory(n, buf) != n) { + perror("oa_getcwd"); + exit(-1); + } + } + return buf; +#else /* OPENAXIOM_MS_WINDOWS_HOST */ + errno = 0; + while (getcwd(buf,bufsz) == 0) { + if (errno == ERANGE) { + errno = 0; + bufsz *= 2; + buf = (char*) realloc(buf, bufsz); + } + else { + perror("oa_getcwd"); + exit(-1); + } + } + return buf; +#endif +} + +OPENAXIOM_C_EXPORT int +oa_access_file_for_read(const char* path) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + return GetFileAttributes(path) == INVALID_FILE_ATTRIBUTES ? -1 : 1; +#else + return access(path, R_OK); +#endif +} + + +OPENAXIOM_C_EXPORT const char* +oa_get_tmpdir(void) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + char* buf; + /* First, probe. */ + int bufsz = GetTempPath(0, NULL); + if (bufsz == 0) { + perror("oa_get_tmpdir"); + exit(1); + } + else { + int new_size; + buf = (char*) malloc(bufsz + 1); + new_size = GetTempPath(bufsz, buf); + if(new_size == 0 || new_size >= bufsz) { + perror("oa_get_tmpdir"); + free(buf); + exit(1); + } + buf[new_size] = '\0'; + } + return buf; +#else + return "/tmp"; +#endif +} + + +OPENAXIOM_C_EXPORT int +oa_copy_file(const char* src, const char* dst) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + return CopyFile(src,dst, /* bFailIfExists = */ 0) ? 0 : -1; +#else +#define OA_BUFSZ 512 +#define OA_DEFAULT_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) + char buf[OA_BUFSZ]; + int src_fd; + int dst_fd; + int count; + if((src_fd = open(src, O_RDONLY)) < 0) + return -1; + if ((dst_fd = creat(dst, OA_DEFAULT_MODE)) < 0) { + close(src_fd); + return -1; + } + + while ((count = read(src_fd, buf, OA_BUFSZ)) > 0) + if (write(dst_fd, buf, count) != count) + break; + +#undef OA_DEFAULT_MODE +#undef OA_BUFSZ + return (close(dst_fd) < 0 || close(src_fd) < 0 || count < 0) ? -1 : 0; +#endif +} + + +OPENAXIOM_C_EXPORT double +plus_infinity(void ) +{ +#ifdef INFINITY + return INFINITY; +#else + /* This must be a curious platform. */ + volatile double zero = 0.0; + return 1.0 / zero; /* If it traps, well, it traps. */ +#endif +} + +OPENAXIOM_C_EXPORT double +minus_infinity(void) +{ + return -plus_infinity(); +} + +OPENAXIOM_C_EXPORT double +quiet_double_NaN(void) +{ +#ifdef NAN + return NAN; +#else + return sqrt(-1.0); /* Just pick one. */ +#endif +} + + +OPENAXIOM_C_EXPORT Byteorder +oa_get_host_byteorder(void) +{ +#ifdef WORDS_BIGENDIAN + return Byteorder::big; +#else + return Byteorder::little; +#endif +} + + +OPENAXIOM_C_EXPORT void +oa_allocate_process_argv(Process* proc, int argc) +{ + proc->argc = argc; + proc->argv = (char**) malloc((1 + argc) * sizeof (char*)); + proc->argv[argc] = NULL; +} + +OPENAXIOM_C_EXPORT int +oa_spawn(Process* proc, SpawnFlags flags) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + const char* path = NULL; + char* cmd_line = NULL; + int curpos = strlen(proc->argv[0]); + int cmd_line_length = curpos; + int i; + PROCESS_INFORMATION proc_info; + STARTUPINFO startup_info = { 0 }; + DWORD status; + + for (i = 0; i < proc->argc; ++i) + cmd_line_length += 1 + strlen(proc->argv[i]); + + cmd_line = (char*) malloc(cmd_line_length + 1); + strcpy(cmd_line, proc->argv[0]); + for (i = 0; i < proc->argc; ++i) { + cmd_line[curpos++] = ' '; + strcpy(cmd_line + curpos, proc->argv[i]); + curpos += strlen(proc->argv[i]); + } + cmd_line[curpos] = '\0'; + + if ((flags & SpawnFlags::search_path) == 0) + path = proc->argv[0]; + + if(CreateProcess(/* lpApplicationName */ path, + /* lpCommandLine */ cmd_line, + /* lpProcessAttributes */ NULL, + /* lpThreadAttributes */ NULL, + /* bInheritHandles */ TRUE, + /* dwCreationFlags */ 0, + /* lpEnvironment */ NULL, + /* lpCurrentDirectory */ NULL, + /* lpstartupInfo */ &startup_info, + /* lpProcessInformation */ &proc_info) == 0) { + fprintf(stderr, "oa_spawn: error %lu\n", GetLastError()); + return proc->id = -1; + } + proc->id = proc_info.dwProcessId; + if ((flags & SpawnFlags::replace) == 0) + return proc->id; + WaitForSingleObject(proc_info.hProcess, INFINITE); + GetExitCodeProcess(proc_info.hProcess, &status); + CloseHandle(proc_info.hThread); + CloseHandle(proc_info.hProcess); + return status; + +#else + proc->id = 0; + if ((flags & SpawnFlags::replace) == 0) + proc->id = fork(); + if (proc->id == 0) { + if (flags & SpawnFlags::search_path) + execvp(proc->argv[0], proc->argv); + else + execv(proc->argv[0], proc->argv); + perror(strerror(errno)); + /* Don't keep useless clones around. */ + if ((flags & SpawnFlags::replace) == 0) + exit(-1); + } + return proc->id; +#endif +} + +OPENAXIOM_C_EXPORT char* +oa_substr(const char* str, const size_t begin, const size_t end) +{ + char* substring; + int len; + + if (str == NULL || strlen(str) == 0 || + strlen(str) < begin || end >= strlen(str) || begin > end) + return NULL; + + len = (end - begin) + 2; + substring = (char*) malloc(len * sizeof(char)); + memset(substring,'\0',len); + memcpy(substring, str+begin, len-1); + + return substring; +} + +OPENAXIOM_C_EXPORT char** +oa_split(const char* sequence, const char* delimiter, int* size) +{ + int sequence_length = 0, newsize = 0; + char* token; + char** tokens = NULL; + char* sequence_copy; + + sequence_length = strlen(sequence); + sequence_copy = (char*) malloc((sequence_length + 1) * sizeof(char*)); + strcpy(sequence_copy,sequence); + sequence_copy[sequence_length] = '\0'; + + token = strtok(sequence_copy, delimiter); + while (token != NULL) { + + tokens = (char**) realloc(tokens,(newsize + 1) * sizeof(char*)); + tokens[newsize] = token; + newsize++; + token = strtok (NULL, delimiter); + } + + *size = newsize; + + return tokens; +} + +} diff --git a/src/lib/sockio-c.c b/src/lib/sockio-c.c deleted file mode 100644 index 24b8f475..00000000 --- a/src/lib/sockio-c.c +++ /dev/null @@ -1,1307 +0,0 @@ -/* - Copyright (c) 1991-2002, The Numerical Algorithms Group Ltd. - All rights reserved. - Copyright (C) 2007-2013, 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. -*/ - -/* socket i/o primitives */ - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#ifdef __WIN32__ -# include -# include -#else -# include -# include -#endif - -#include "cfuns.h" -#include "sockio.h" -#include "com.h" -#include "bsdsignal.h" -#include "sockio.h" - -namespace OpenAxiom { - -#define TotalMaxPurposes 50 -#define MaxServerNumbers 100 -#define accept_if_needed(purpose) \ - ( purpose_table[purpose] == NULL ? sock_accept_connection(purpose) : 1 ) - -/* Note that the name AF_LOCAL is more portable than AF_UNIX, but MingW - implementation and Windows documentation don't always agree. */ - -#if HAVE_AF_LOCAL -# define OPENAXIOM_AF_LOCAL AF_LOCAL -#elif HAVE_AF_UNIX -# define OPENAXIOM_AF_LOCAL AF_UNIX -#else -# error "needs one of AF_LOCAL or AF_UNIX" -#endif - - -/* socket description of spad clients */ -openaxiom_sio clients[MaxClients]; - -/* Local socket for server */ -openaxiom_sio server; - -/* table of dedicated socket types */ -openaxiom_sio *purpose_table[TotalMaxPurposes]; - -/* bit mask of active sockets */ -fd_set socket_mask; - -/* bit mask of server sockets */ -fd_set server_mask; - -/* used to identify closed socket on SIGPIPE */ -int socket_closed; - -/* spad server number used in sman */ -int spad_server_number = -1; - - -/* Non zero if the host system module support for socket is activated. - This is needed only for MS platforms. */ -static int openaxiom_socket_module_loaded = 0; - -#ifdef __WIN32__ -/* Windows require some handshaking with the WinSock DLL before - we can even think about talking about sockets. */ - -static void -openaxiom_unload_socket_module() -{ - WSACleanup(); - openaxiom_socket_module_loaded = 0; -} -#endif - - -static void -openaxiom_load_socket_module() -{ - if (!openaxiom_socket_module_loaded) { -#ifdef __WIN32__ - WSADATA wsaData; - - /* Request version 2.0 of WinSock DLL. */ - if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) { - perror("could not find suitable WinSock DLL."); - exit(WSAGetLastError()); - } - - atexit(&openaxiom_unload_socket_module); - - if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) { - perror("could not find suitable WinSock DLL."); - exit(WSAGetLastError()); - } -#endif - } - openaxiom_socket_module_loaded = 1; -} - - -/* Convert an IP address from presentation (string or ascii form) - to numeric form. The result is stored in the last argument. - Success is indicated by a return value 0; failure is -1. */ -OPENAXIOM_C_EXPORT int -oa_inet_pton(const char* addr, int prot, Byte* bytes) -{ - openaxiom_load_socket_module(); - switch (prot) { - case 4: { -#ifdef __WIN32__ - unsigned long inet_val = inet_addr(addr); - if (inet_val == INADDR_NONE || inet_val == INADDR_ANY) - return -1; - memcpy(bytes, &inet_val, 4); - return 0; -#else - struct in_addr inet_val; - if (inet_aton(addr, &inet_val) != 0) { - memcpy(bytes, &inet_val, 4); - return 0; - } - return -1; -#endif - } - default: - return -1; - } -} - -/* Resolve a hostname to its IP address. On success return 0, - otherwise -1. */ -OPENAXIOM_C_EXPORT int -oa_get_host_address(const char* n, int prot, Byte* bytes) -{ - struct hostent* h; - openaxiom_load_socket_module(); - h = gethostbyname(n); - if (h == 0) - return -1; - - if (h->h_length != prot) - /* Protocol mismatch. */ - return -1; - memcpy(bytes, h->h_addr_list[0], prot); - return 0; -} - - -/* Get a socket identifier to a local server. We take whatever protocol - is the default for the address family in the SOCK_STREAM type. */ -static inline openaxiom_socket -openaxiom_socket_stream_link(int family) -{ - openaxiom_load_socket_module(); - return socket(family, SOCK_STREAM, 0); -} - - -/* Returns 1 if SOCKET is an invalid socket. Otherwise return 0. */ - -static inline int -openaxiom_socket_is_invalid(openaxiom_socket sock) -{ -#ifdef __WIN32__ - return sock == INVALID_SOCKET; -#else - return sock < 0; -#endif -} - -static inline int -is_invalid_socket(const openaxiom_sio* s) -{ - return openaxiom_socket_is_invalid(s->socket); -} - -/* Returns 1 if SOCKET is a valid socket. Otherwise return 0. */ - -static inline int -is_valid_socket(const openaxiom_sio* s) -{ -#ifdef __WIN32__ - return s->socket != INVALID_SOCKET; -#else - return s->socket > 0; -#endif -} - - -/* Because a socket on Windows platform is a not just a simple file - descriptor as it is in the Unix world, it is invalid to use - a socket identifier as argument for read(), or close, or - any other file descriptor function. Furthermore, Windows - requires cleanup. */ - -OPENAXIOM_C_EXPORT void -oa_close_socket(openaxiom_socket s) -{ -#ifdef __WIN32__ - shutdown(s, SD_BOTH); - closesocket(s); -#else - close(s); -#endif -} - -/* Local IPC Socket: - On POSIX systems, this is just the Local IPC Socket. - On Windows, we Windows Named Pipes. - - Please, remember that Windows Named Pipes are closer to - Unix Domain Sockets than they are to Unix Named Pipes. They - ae full duplex communication links, supporting regular - file I/O operations. */ - -OPENAXIOM_C_EXPORT openaxiom_filedesc -oa_open_local_client_stream_socket(const char* path) -{ -#ifdef __WIN32__ -# define NAMED_PIPE_PREFIX "\\\\.\\pipe" - char* pipename; - HANDLE handle; - - pipename = (char *) malloc(sizeof NAMED_PIPE_PREFIX + strlen(path)); - strcpy(pipename, NAMED_PIPE_PREFIX); - strcat(pipename, path); - - /* Try to open only an existing named pipe. */ - while (1) { - handle = CreateFile(/* lpFileName */ pipename, - /* dwDesiredAccess */ GENERIC_READ | GENERIC_WRITE, - /* dwSharedMode */ 0, - /* lpSecurityAttributes */ NULL, - /* dwCreationDisposition */ OPEN_EXISTING, - /* dwFlagsAttributes */ 0, - /* hTemplateFile */ NULL); - - if (handle != INVALID_HANDLE_VALUE) - return handle; - - if (GetLastError() != ERROR_PIPE_BUSY - || !WaitNamedPipe(pipename, NMPWAIT_WAIT_FOREVER)) - return INVALID_HANDLE_VALUE; - } -# undef NAMED_PIPE_PREFIX -#else - int sock = socket(AF_UNIX, SOCK_STREAM, 0); - struct sockaddr_un addr; - if (sock < 0) - return -1; - - memset(&addr, 0, sizeof addr); - addr.sun_family = OPENAXIOM_AF_LOCAL; - strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); - if (connect(sock, (struct sockaddr*)&addr, sizeof addr) < 0) { - close(sock); - return -1; - } - return sock; -#endif -} - -OPENAXIOM_C_EXPORT int -oa_filedesc_read(openaxiom_filedesc desc, Byte* buf, int size) -{ -#ifdef __WIN32__ - DWORD count = -1; - if (ReadFile(/* hFile */ desc, - /* lpBuffer */ buf, - /* nNumberOfBytesToRead */ size, - /* lpNumberOfBytesRead */ &count, - /* lpOverlapped */ NULL)) - return count; - return -1; -#else - return read(desc, buf, size); -#endif -} - -OPENAXIOM_C_EXPORT int -oa_filedesc_write(openaxiom_filedesc desc, const Byte* buf, int size) -{ -#ifdef __WIN32__ - DWORD count = -1; - if (WriteFile(/* hFile */ desc, - /* lpBuffer */ buf, - /* nNumberOfBytesToWrite */ size, - /* lpNumberOfBytesWritten */ &count, - /* lpOverlapped */ NULL)) - return count; - return -1; -#else - return write(desc, buf, size); -#endif -} - -OPENAXIOM_C_EXPORT int -oa_filedesc_close(openaxiom_filedesc desc) -{ -#ifdef __WIN32__ - return CloseHandle(desc) ? 0 : -1; -#else - return close(desc); -#endif -} - -/* IP sockets. -*/ - -OPENAXIOM_C_EXPORT openaxiom_socket -oa_connect_ip_port_stream(const Byte* addr, int prot, openaxiom_port port) -{ - struct sockaddr_in server; - openaxiom_socket sock; - /* IP6 is not yet supported. */ - if (prot != 4) - return OPENAXIOM_INVALID_SOCKET; - - sock = openaxiom_socket_stream_link(AF_INET); - if (openaxiom_socket_is_invalid(sock)) - return OPENAXIOM_INVALID_SOCKET; - - memset(&server, 0, sizeof server); - server.sin_family = AF_INET; - memcpy(&server.sin_addr, addr, prot); - server.sin_port = htons(port); - if (connect(sock, (struct sockaddr*)&server, sizeof server) < 0) { - oa_close_socket(sock); - return OPENAXIOM_INVALID_SOCKET; - } - return sock; -} - -/* It is idiomatic in the Unix/POSIX world to use the standard - read() and write() functions on sockets. However, in the Windows - world, that is invalid. Consequently, portability suggests that - we restrict ourselves to the POSIX standard functions recv() and - send(). */ - - -/* Read some bytes of data into buffer `buf' with capacity `size'. - On failure, return -1; otherwise return the number of bytes - actually read. */ - -OPENAXIOM_C_EXPORT int -oa_socket_read(openaxiom_socket sock, Byte* buf, int size) -{ - return recv(sock, (char*) buf, size, 0); -} - -/* Attempt to read a byte from scoket `sock'. - On failure, return -1; otherwise the actual byte read. */ - -OPENAXIOM_C_EXPORT int -oa_socket_read_byte(openaxiom_socket sock) -{ - Byte byte; - if(oa_socket_read(sock, &byte, 1) < 1) - return -1; - return byte; -} - - -/* Send `size' bytes of data contained in `buf' to the socket `sock'. - Return -1 on failured; the number of actualy write bytes on success. */ - -OPENAXIOM_C_EXPORT int -oa_socket_write(openaxiom_socket sock, const Byte* buf, int size) -{ - return send(sock, (const char*) buf, size, 0); -} - -/* Send one byte to socket `sock'. */ -OPENAXIOM_C_EXPORT int -oa_socket_write_byte(openaxiom_socket sock, Byte byte) -{ - return oa_socket_write(sock, &byte, 1) < 1 ? -1 : byte; -} - - -/* Return 1 is the last call was cancelled. */ - -static inline int -openaxiom_syscall_was_cancelled() -{ -#ifdef __WIN32__ - return WSAGetLastError() == WSAEINTR; -#else - return errno == EINTR; -#endif -} - -/* Return 1 is last connect() was refused. */ - -static inline int -openaxiom_connection_refused() -{ -#ifdef __WIN32__ - return WSAGetLastError() == WSAECONNREFUSED; -#else - return errno == ECONNREFUSED; -#endif -} - - -OPENAXIOM_C_EXPORT void -sigpipe_handler(int sig) -{ - socket_closed = 1; -} - -OPENAXIOM_C_EXPORT int -wait_for_client_read(openaxiom_sio *sock, Byte* buf, int buf_size, - const char* msg) -{ - int ret_val; - switch(sock->purpose) { - case SessionManager: - case ViewportServer: - sock_accept_connection(sock->purpose); - ret_val = sread(purpose_table[sock->purpose], buf, buf_size, msg); - sock->socket = 0; - return ret_val; - default: - sock->socket = 0; - return -1; - } -} - -OPENAXIOM_C_EXPORT int -wait_for_client_write(openaxiom_sio* sock, const Byte* buf, - int buf_size, const char* msg) -{ - int ret_val; - switch(sock->purpose) { - case SessionManager: - case ViewportServer: - sock_accept_connection(sock->purpose); - ret_val = swrite(purpose_table[sock->purpose], buf, buf_size, msg); - sock->socket = 0; - return ret_val; - default: - sock->socket = 0; - return -1; - } -} - -OPENAXIOM_C_EXPORT int -sread(openaxiom_sio* sock, Byte* buf, int buf_size, const char *msg) -{ - int ret_val; - char err_msg[256]; - errno = 0; - do { - ret_val = oa_socket_read(sock->socket, buf, buf_size); - } while (ret_val == -1 && openaxiom_syscall_was_cancelled()); - if (ret_val == 0) { - FD_CLR(sock->socket, &socket_mask); - purpose_table[sock->purpose] = NULL; - oa_close_socket(sock->socket); - return wait_for_client_read(sock, buf, buf_size, msg); - } - if (ret_val == -1) { - if (msg) { - sprintf(err_msg, "reading: %s", msg); - perror(err_msg); - } - return -1; - } - return ret_val; -} - -OPENAXIOM_C_EXPORT int -swrite(openaxiom_sio* sock, const Byte* buf, int buf_size, - const char* msg) -{ - int ret_val; - char err_msg[256]; - errno = 0; - socket_closed = 0; - ret_val = oa_socket_write(sock->socket, buf, buf_size); - if (ret_val == -1) { - if (socket_closed) { - FD_CLR(sock->socket, &socket_mask); - purpose_table[sock->purpose] = NULL; - /* printf(" closing socket %d\n", sock->socket); */ - oa_close_socket(sock->socket); - return wait_for_client_write(sock, buf, buf_size, msg); - } else { - if (msg) { - sprintf(err_msg, "writing: %s", msg); - perror(err_msg); - } - return -1; - } - } - return ret_val; -} - -OPENAXIOM_C_EXPORT int -sselect(int n,fd_set *rd, fd_set *wr, fd_set *ex, void *timeout) -{ - int ret_val; - do { - ret_val = select(n, rd, wr, ex, (struct timeval *) timeout); - } while (ret_val == -1 && openaxiom_syscall_was_cancelled()); - return ret_val; -} - -OPENAXIOM_C_EXPORT int -fill_buf(openaxiom_sio *sock, Byte* buf, int len, const char* msg) -{ - int bytes = 0, ret_val; - while(bytes < len) { - ret_val = sread(sock, buf + bytes, len - bytes, msg); - if (ret_val == -1) return -1; - bytes += ret_val; - } - return bytes; -} - -OPENAXIOM_C_EXPORT int -get_int(openaxiom_sio *sock) -{ - int val = -1, len; - len = fill_buf(sock, byte_address(val), sizeof(int), "get_int"); - if (len != sizeof(int)) { -#ifdef DEBUG - fprintf(stderr,"get_int: caught error\n",val); -#endif - return -1; - } -#ifdef DEBUG - fprintf(stderr,"get_int: received %d\n",val); -#endif - return val; -} - -OPENAXIOM_C_EXPORT int -sock_get_int(int purpose) -{ - if (accept_if_needed(purpose) != -1) - return get_int(purpose_table[purpose]); - else return -1; -} - -OPENAXIOM_C_EXPORT int -get_ints(openaxiom_sio *sock, int *vals, int num) -{ - int i; - for(i=0; i 1023) { - char *buf; - buf = (char*) malloc(len+1); - strncpy(buf,str,len); - buf[len]='\0'; - send_int(sock,len+1); - val = swrite(sock, (const Byte*) buf, len+1, "send_string_len"); - free(buf); - } else { - static char buf[1024]; - strncpy(buf, str, len); - buf[len] = '\0'; - send_int(sock, len+1); - val = swrite(sock, (const Byte*) buf, len+1, "send_string_len"); - } - if (val == -1) { - return val; - } - return 0; -} - -OPENAXIOM_C_EXPORT int -send_string(openaxiom_sio* sock, const char* str) -{ - int val, len = strlen(str); - send_int(sock, len+1); - val = swrite(sock, (const Byte*) str, len+1, "send_string"); - if (val == -1) { - return -1; - } - return 0; -} - - -OPENAXIOM_C_EXPORT int -sock_send_string(int purpose, const char *str) -{ - if (accept_if_needed(purpose) != -1) - return send_string(purpose_table[purpose], str); - return -1; -} - -OPENAXIOM_C_EXPORT int -sock_send_string_len(int purpose, const char* str, int len) -{ - if (accept_if_needed(purpose) != -1) - return send_string_len(purpose_table[purpose], str, len); - return -1; -} - -OPENAXIOM_C_EXPORT int -send_strings(openaxiom_sio *sock, const char** vals, int num) -{ - int i; - for(i=0; inbytes_pending == 0) - sock->nbytes_pending = get_int(sock); - nbytes_to_read = sock->nbytes_pending > buf_len - ? buf_len - : sock->nbytes_pending; - nbytes_read = fill_buf(sock, (Byte*)buf, nbytes_to_read, - "get_string_buf"); - if (nbytes_read == -1) { - sock->nbytes_pending = 0; - return NULL; - } - sock->nbytes_pending -= nbytes_read; - return sock->nbytes_pending == 0 ? NULL : buf; -} - -OPENAXIOM_C_EXPORT char * -sock_get_string_buf(int purpose, char* buf, int buf_len) -{ - if (accept_if_needed(purpose) != -1) - return get_string_buf(purpose_table[purpose], buf, buf_len); - return NULL; -} - -OPENAXIOM_C_EXPORT int -get_strings(openaxiom_sio *sock, char** vals,int num) -{ - int i; - for(i=0; ipurpose) { - case SessionManager: - case ViewportServer: - sock_accept_connection(sock->purpose); - ret_val = send_signal(purpose_table[sock->purpose], sig); - sock->socket = 0; - return ret_val; - default: - sock->socket = 0; - return -1; - } -} - - -OPENAXIOM_C_EXPORT int -sock_get_remote_fd(int purpose) -{ - if (accept_if_needed(purpose) != -1) - return purpose_table[purpose]->remote; - return -1; -} - -OPENAXIOM_C_EXPORT int -send_signal(openaxiom_sio *sock, int sig) -{ - int ret_val; -#if HAVE_DECL_KILL - ret_val = kill(sock->pid, sig); -#else - ret_val = raise(sig); -#endif - if (ret_val == -1 && errno == ESRCH) { - FD_CLR(sock->socket, &socket_mask); - purpose_table[sock->purpose] = NULL; -/* printf(" closing socket %d\n", sock->socket); */ - oa_close_socket(sock->socket); - return wait_for_client_kill(sock, sig); - } - return ret_val; -} - -OPENAXIOM_C_EXPORT int -sock_send_signal(int purpose,int sig) -{ - if (accept_if_needed(purpose) != -1) - return send_signal(purpose_table[purpose], sig); - return -1; -} - -OPENAXIOM_C_EXPORT int -send_wakeup(openaxiom_sio *sock) -{ -#ifdef SIGUSR1 - return send_signal(sock, SIGUSR1); -#else - return -1; -#endif -} - -OPENAXIOM_C_EXPORT int -sock_send_wakeup(int purpose) -{ - if (accept_if_needed(purpose) != -1) - return send_wakeup(purpose_table[purpose]); - return -1; -} - -OPENAXIOM_C_EXPORT openaxiom_sio * -connect_to_local_server_new(const char *server_name, int purpose, int time_out) -{ - int max_con=(time_out == 0 ? 1000000 : time_out), i, code=-1; - openaxiom_sio *sock; - char name[256]; - - make_server_name(name, server_name); - sock = (openaxiom_sio *) calloc(sizeof(openaxiom_sio), 1); - if (sock == NULL) { - perror("allocating socket space"); - return NULL; - } - - sock->socket = openaxiom_socket_stream_link(OPENAXIOM_AF_LOCAL); - if (is_invalid_socket(sock)) { - perror("opening client socket"); - free(sock); - return NULL; - } - - memset(server.addr.u_addr.sa_data, 0, - sizeof(server.addr.u_addr.sa_data)); - sock->addr.u_addr.sa_family = OPENAXIOM_AF_LOCAL; - strcpy(sock->addr.u_addr.sa_data, name); - for(i=0; isocket, &sock->addr.u_addr, - sizeof(sock->addr.u_addr)); - if (code == -1) { - if (errno != ENOENT && !openaxiom_connection_refused()) { - perror("connecting server stream socket"); - return NULL; - } else { - if (i != max_con - 1) - openaxiom_sleep(1); - continue; - } - } else break; - } - - if (code == -1) { - return NULL; - } - - send_int(sock, oa_getpid()); - send_int(sock, purpose); - send_int(sock, sock->socket); - sock->pid = get_int(sock); - sock->remote = get_int(sock); - return sock; -} - -OPENAXIOM_C_EXPORT openaxiom_sio * -connect_to_local_server(const char *server_name, int purpose, int time_out) -{ - int max_con=(time_out == 0 ? 1000000 : time_out), i, code=-1; - openaxiom_sio *sock; - char name[256]; - - make_server_name(name, server_name); - sock = (openaxiom_sio *) calloc(sizeof(openaxiom_sio), 1); - if (sock == NULL) { - perror("allocating socket space"); - return NULL; - } - - sock->purpose = purpose; - /* create the socket */ - sock->socket = openaxiom_socket_stream_link(OPENAXIOM_AF_LOCAL); - if (is_invalid_socket(sock)) { - perror("opening client socket"); - free(sock); - return NULL; - } - /* connect socket using name specified in command line */ - memset(server.addr.u_addr.sa_data, 0, - sizeof(server.addr.u_addr.sa_data)); - sock->addr.u_addr.sa_family = OPENAXIOM_AF_LOCAL; - strcpy(sock->addr.u_addr.sa_data, name); - for(i=0; isocket, &sock->addr.u_addr, - sizeof(sock->addr.u_addr)); - if (code == -1) { - if (errno != ENOENT && !openaxiom_connection_refused()) { - perror("connecting server stream socket"); - return NULL; - } else { - if (i != max_con - 1) - openaxiom_sleep(1); - continue; - } - } else break; - } - if (code == -1) { - return NULL; - } - send_int(sock, oa_getpid()); - send_int(sock, sock->purpose); - send_int(sock, sock->socket); - sock->pid = get_int(sock); -/* fprintf(stderr, "Got int form socket\n"); */ - sock->remote = get_int(sock); - return sock; -} - -/* act as terminal session for sock connected to stdin and stdout of another - process */ -OPENAXIOM_C_EXPORT void -remote_stdio(openaxiom_sio *sock) -{ - char buf[1024]; - fd_set rd; - int len; - while (1) { - FD_ZERO(&rd); - FD_SET(sock->socket,&rd); - FD_SET(0, &rd); - len = sselect(FD_SETSIZE, &rd, nullptr, nullptr, NULL); - if (len == -1) { - perror("stdio select"); - return; - } - if (FD_ISSET(0, &rd)) { - fgets(buf,1024,stdin); - len = strlen(buf); - swrite(sock, byte_address(buf), len, "remote_stdio::write"); - } - if (FD_ISSET(sock->socket, &rd)) { - len = sread(sock, byte_address(buf), 1024, "remote_stdio::read"); - if (len == -1) - return; - else { - *(buf + len) = '\0'; - fputs(buf, stdout); - fflush(stdout); - } - } - } -} - -/* initialize the table of dedicated sockets */ -static void -init_purpose_table() -{ - int i; - for(i=0; ipid = get_int(sock); - sock->purpose = get_int(sock); - sock->remote = get_int(sock); - send_int(sock, oa_getpid()); - send_int(sock, sock->socket); - purpose_table[sock->purpose] = sock; -} - -OPENAXIOM_C_EXPORT int -accept_connection() -{ - int client = 0; - while (client < MaxClients && clients[client].socket != 0) - ++client; - if (client == MaxClients) { - printf("Ran out of client openaxiom_sio structures\n"); - return -1; - } - clients[client].socket = accept(server.socket, 0, 0); - if (is_invalid_socket(&clients[client])) { - perror("accept_connection"); - clients[client].socket = 0; - return -1; - } - FD_SET(clients[client].socket, &socket_mask); - get_socket_type(&clients[client]); - return clients[client].purpose; -} - -OPENAXIOM_C_EXPORT int -sock_accept_connection(int purpose) -{ - fd_set rd; - int ret_val, p; - if (oa_getenv("SPADNUM") == NULL) return -1; - while (1) { - rd = server_mask; - ret_val = sselect(FD_SETSIZE, &rd, nullptr, nullptr, NULL); - if (ret_val == -1) { - perror ("Select"); - return -1; - } - if (is_valid_socket(&server) && FD_ISSET(server.socket, &rd)) { - p = accept_connection(); - if (p == purpose) return 1; - } - } -} - -/* Socket I/O selection called from the BOOT serverLoop function */ - -OPENAXIOM_C_EXPORT int -server_switch() -{ - int ret_val, cmd = 0; - fd_set rd, wr, ex, fds_mask; - FD_ZERO(&rd); - FD_ZERO(&wr); - FD_ZERO(&ex); - fds_mask = server_mask; - cmd = 0; - if (purpose_table[SessionManager] != NULL) { - FD_SET(0, &fds_mask); - FD_SET(purpose_table[SessionManager]->socket, &fds_mask); - } - while (1) { - do { - if (purpose_table[MenuServer] != NULL) { - FD_SET(purpose_table[MenuServer]->socket, &fds_mask); - } - rd = fds_mask; - ret_val = select(FD_SETSIZE, &rd, 0, 0, 0); - if (ret_val == -1) { - /* perror ("Select in switch"); */ - return -1; - } - if (is_valid_socket(&server) && FD_ISSET(server.socket, &rd)) - accept_connection(); - } while (purpose_table[SessionManager] == NULL); - FD_SET(purpose_table[SessionManager]->socket, &fds_mask); - if (FD_ISSET(purpose_table[SessionManager]->socket, &rd)) { - cmd = get_int(purpose_table[SessionManager]); - return cmd; - } - if (FD_ISSET(0, &rd)) { - return CallInterp; - } - if (purpose_table[MenuServer] != NULL && - (FD_ISSET(purpose_table[MenuServer]->socket, &rd))) { - cmd = get_int(purpose_table[MenuServer]); - return cmd; - } - } -} - -} diff --git a/src/lib/sockio-c.cxx b/src/lib/sockio-c.cxx new file mode 100644 index 00000000..24b8f475 --- /dev/null +++ b/src/lib/sockio-c.cxx @@ -0,0 +1,1307 @@ +/* + Copyright (c) 1991-2002, The Numerical Algorithms Group Ltd. + All rights reserved. + Copyright (C) 2007-2013, 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. +*/ + +/* socket i/o primitives */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#ifdef __WIN32__ +# include +# include +#else +# include +# include +#endif + +#include "cfuns.h" +#include "sockio.h" +#include "com.h" +#include "bsdsignal.h" +#include "sockio.h" + +namespace OpenAxiom { + +#define TotalMaxPurposes 50 +#define MaxServerNumbers 100 +#define accept_if_needed(purpose) \ + ( purpose_table[purpose] == NULL ? sock_accept_connection(purpose) : 1 ) + +/* Note that the name AF_LOCAL is more portable than AF_UNIX, but MingW + implementation and Windows documentation don't always agree. */ + +#if HAVE_AF_LOCAL +# define OPENAXIOM_AF_LOCAL AF_LOCAL +#elif HAVE_AF_UNIX +# define OPENAXIOM_AF_LOCAL AF_UNIX +#else +# error "needs one of AF_LOCAL or AF_UNIX" +#endif + + +/* socket description of spad clients */ +openaxiom_sio clients[MaxClients]; + +/* Local socket for server */ +openaxiom_sio server; + +/* table of dedicated socket types */ +openaxiom_sio *purpose_table[TotalMaxPurposes]; + +/* bit mask of active sockets */ +fd_set socket_mask; + +/* bit mask of server sockets */ +fd_set server_mask; + +/* used to identify closed socket on SIGPIPE */ +int socket_closed; + +/* spad server number used in sman */ +int spad_server_number = -1; + + +/* Non zero if the host system module support for socket is activated. + This is needed only for MS platforms. */ +static int openaxiom_socket_module_loaded = 0; + +#ifdef __WIN32__ +/* Windows require some handshaking with the WinSock DLL before + we can even think about talking about sockets. */ + +static void +openaxiom_unload_socket_module() +{ + WSACleanup(); + openaxiom_socket_module_loaded = 0; +} +#endif + + +static void +openaxiom_load_socket_module() +{ + if (!openaxiom_socket_module_loaded) { +#ifdef __WIN32__ + WSADATA wsaData; + + /* Request version 2.0 of WinSock DLL. */ + if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) { + perror("could not find suitable WinSock DLL."); + exit(WSAGetLastError()); + } + + atexit(&openaxiom_unload_socket_module); + + if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) { + perror("could not find suitable WinSock DLL."); + exit(WSAGetLastError()); + } +#endif + } + openaxiom_socket_module_loaded = 1; +} + + +/* Convert an IP address from presentation (string or ascii form) + to numeric form. The result is stored in the last argument. + Success is indicated by a return value 0; failure is -1. */ +OPENAXIOM_C_EXPORT int +oa_inet_pton(const char* addr, int prot, Byte* bytes) +{ + openaxiom_load_socket_module(); + switch (prot) { + case 4: { +#ifdef __WIN32__ + unsigned long inet_val = inet_addr(addr); + if (inet_val == INADDR_NONE || inet_val == INADDR_ANY) + return -1; + memcpy(bytes, &inet_val, 4); + return 0; +#else + struct in_addr inet_val; + if (inet_aton(addr, &inet_val) != 0) { + memcpy(bytes, &inet_val, 4); + return 0; + } + return -1; +#endif + } + default: + return -1; + } +} + +/* Resolve a hostname to its IP address. On success return 0, + otherwise -1. */ +OPENAXIOM_C_EXPORT int +oa_get_host_address(const char* n, int prot, Byte* bytes) +{ + struct hostent* h; + openaxiom_load_socket_module(); + h = gethostbyname(n); + if (h == 0) + return -1; + + if (h->h_length != prot) + /* Protocol mismatch. */ + return -1; + memcpy(bytes, h->h_addr_list[0], prot); + return 0; +} + + +/* Get a socket identifier to a local server. We take whatever protocol + is the default for the address family in the SOCK_STREAM type. */ +static inline openaxiom_socket +openaxiom_socket_stream_link(int family) +{ + openaxiom_load_socket_module(); + return socket(family, SOCK_STREAM, 0); +} + + +/* Returns 1 if SOCKET is an invalid socket. Otherwise return 0. */ + +static inline int +openaxiom_socket_is_invalid(openaxiom_socket sock) +{ +#ifdef __WIN32__ + return sock == INVALID_SOCKET; +#else + return sock < 0; +#endif +} + +static inline int +is_invalid_socket(const openaxiom_sio* s) +{ + return openaxiom_socket_is_invalid(s->socket); +} + +/* Returns 1 if SOCKET is a valid socket. Otherwise return 0. */ + +static inline int +is_valid_socket(const openaxiom_sio* s) +{ +#ifdef __WIN32__ + return s->socket != INVALID_SOCKET; +#else + return s->socket > 0; +#endif +} + + +/* Because a socket on Windows platform is a not just a simple file + descriptor as it is in the Unix world, it is invalid to use + a socket identifier as argument for read(), or close, or + any other file descriptor function. Furthermore, Windows + requires cleanup. */ + +OPENAXIOM_C_EXPORT void +oa_close_socket(openaxiom_socket s) +{ +#ifdef __WIN32__ + shutdown(s, SD_BOTH); + closesocket(s); +#else + close(s); +#endif +} + +/* Local IPC Socket: + On POSIX systems, this is just the Local IPC Socket. + On Windows, we Windows Named Pipes. + + Please, remember that Windows Named Pipes are closer to + Unix Domain Sockets than they are to Unix Named Pipes. They + ae full duplex communication links, supporting regular + file I/O operations. */ + +OPENAXIOM_C_EXPORT openaxiom_filedesc +oa_open_local_client_stream_socket(const char* path) +{ +#ifdef __WIN32__ +# define NAMED_PIPE_PREFIX "\\\\.\\pipe" + char* pipename; + HANDLE handle; + + pipename = (char *) malloc(sizeof NAMED_PIPE_PREFIX + strlen(path)); + strcpy(pipename, NAMED_PIPE_PREFIX); + strcat(pipename, path); + + /* Try to open only an existing named pipe. */ + while (1) { + handle = CreateFile(/* lpFileName */ pipename, + /* dwDesiredAccess */ GENERIC_READ | GENERIC_WRITE, + /* dwSharedMode */ 0, + /* lpSecurityAttributes */ NULL, + /* dwCreationDisposition */ OPEN_EXISTING, + /* dwFlagsAttributes */ 0, + /* hTemplateFile */ NULL); + + if (handle != INVALID_HANDLE_VALUE) + return handle; + + if (GetLastError() != ERROR_PIPE_BUSY + || !WaitNamedPipe(pipename, NMPWAIT_WAIT_FOREVER)) + return INVALID_HANDLE_VALUE; + } +# undef NAMED_PIPE_PREFIX +#else + int sock = socket(AF_UNIX, SOCK_STREAM, 0); + struct sockaddr_un addr; + if (sock < 0) + return -1; + + memset(&addr, 0, sizeof addr); + addr.sun_family = OPENAXIOM_AF_LOCAL; + strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); + if (connect(sock, (struct sockaddr*)&addr, sizeof addr) < 0) { + close(sock); + return -1; + } + return sock; +#endif +} + +OPENAXIOM_C_EXPORT int +oa_filedesc_read(openaxiom_filedesc desc, Byte* buf, int size) +{ +#ifdef __WIN32__ + DWORD count = -1; + if (ReadFile(/* hFile */ desc, + /* lpBuffer */ buf, + /* nNumberOfBytesToRead */ size, + /* lpNumberOfBytesRead */ &count, + /* lpOverlapped */ NULL)) + return count; + return -1; +#else + return read(desc, buf, size); +#endif +} + +OPENAXIOM_C_EXPORT int +oa_filedesc_write(openaxiom_filedesc desc, const Byte* buf, int size) +{ +#ifdef __WIN32__ + DWORD count = -1; + if (WriteFile(/* hFile */ desc, + /* lpBuffer */ buf, + /* nNumberOfBytesToWrite */ size, + /* lpNumberOfBytesWritten */ &count, + /* lpOverlapped */ NULL)) + return count; + return -1; +#else + return write(desc, buf, size); +#endif +} + +OPENAXIOM_C_EXPORT int +oa_filedesc_close(openaxiom_filedesc desc) +{ +#ifdef __WIN32__ + return CloseHandle(desc) ? 0 : -1; +#else + return close(desc); +#endif +} + +/* IP sockets. +*/ + +OPENAXIOM_C_EXPORT openaxiom_socket +oa_connect_ip_port_stream(const Byte* addr, int prot, openaxiom_port port) +{ + struct sockaddr_in server; + openaxiom_socket sock; + /* IP6 is not yet supported. */ + if (prot != 4) + return OPENAXIOM_INVALID_SOCKET; + + sock = openaxiom_socket_stream_link(AF_INET); + if (openaxiom_socket_is_invalid(sock)) + return OPENAXIOM_INVALID_SOCKET; + + memset(&server, 0, sizeof server); + server.sin_family = AF_INET; + memcpy(&server.sin_addr, addr, prot); + server.sin_port = htons(port); + if (connect(sock, (struct sockaddr*)&server, sizeof server) < 0) { + oa_close_socket(sock); + return OPENAXIOM_INVALID_SOCKET; + } + return sock; +} + +/* It is idiomatic in the Unix/POSIX world to use the standard + read() and write() functions on sockets. However, in the Windows + world, that is invalid. Consequently, portability suggests that + we restrict ourselves to the POSIX standard functions recv() and + send(). */ + + +/* Read some bytes of data into buffer `buf' with capacity `size'. + On failure, return -1; otherwise return the number of bytes + actually read. */ + +OPENAXIOM_C_EXPORT int +oa_socket_read(openaxiom_socket sock, Byte* buf, int size) +{ + return recv(sock, (char*) buf, size, 0); +} + +/* Attempt to read a byte from scoket `sock'. + On failure, return -1; otherwise the actual byte read. */ + +OPENAXIOM_C_EXPORT int +oa_socket_read_byte(openaxiom_socket sock) +{ + Byte byte; + if(oa_socket_read(sock, &byte, 1) < 1) + return -1; + return byte; +} + + +/* Send `size' bytes of data contained in `buf' to the socket `sock'. + Return -1 on failured; the number of actualy write bytes on success. */ + +OPENAXIOM_C_EXPORT int +oa_socket_write(openaxiom_socket sock, const Byte* buf, int size) +{ + return send(sock, (const char*) buf, size, 0); +} + +/* Send one byte to socket `sock'. */ +OPENAXIOM_C_EXPORT int +oa_socket_write_byte(openaxiom_socket sock, Byte byte) +{ + return oa_socket_write(sock, &byte, 1) < 1 ? -1 : byte; +} + + +/* Return 1 is the last call was cancelled. */ + +static inline int +openaxiom_syscall_was_cancelled() +{ +#ifdef __WIN32__ + return WSAGetLastError() == WSAEINTR; +#else + return errno == EINTR; +#endif +} + +/* Return 1 is last connect() was refused. */ + +static inline int +openaxiom_connection_refused() +{ +#ifdef __WIN32__ + return WSAGetLastError() == WSAECONNREFUSED; +#else + return errno == ECONNREFUSED; +#endif +} + + +OPENAXIOM_C_EXPORT void +sigpipe_handler(int sig) +{ + socket_closed = 1; +} + +OPENAXIOM_C_EXPORT int +wait_for_client_read(openaxiom_sio *sock, Byte* buf, int buf_size, + const char* msg) +{ + int ret_val; + switch(sock->purpose) { + case SessionManager: + case ViewportServer: + sock_accept_connection(sock->purpose); + ret_val = sread(purpose_table[sock->purpose], buf, buf_size, msg); + sock->socket = 0; + return ret_val; + default: + sock->socket = 0; + return -1; + } +} + +OPENAXIOM_C_EXPORT int +wait_for_client_write(openaxiom_sio* sock, const Byte* buf, + int buf_size, const char* msg) +{ + int ret_val; + switch(sock->purpose) { + case SessionManager: + case ViewportServer: + sock_accept_connection(sock->purpose); + ret_val = swrite(purpose_table[sock->purpose], buf, buf_size, msg); + sock->socket = 0; + return ret_val; + default: + sock->socket = 0; + return -1; + } +} + +OPENAXIOM_C_EXPORT int +sread(openaxiom_sio* sock, Byte* buf, int buf_size, const char *msg) +{ + int ret_val; + char err_msg[256]; + errno = 0; + do { + ret_val = oa_socket_read(sock->socket, buf, buf_size); + } while (ret_val == -1 && openaxiom_syscall_was_cancelled()); + if (ret_val == 0) { + FD_CLR(sock->socket, &socket_mask); + purpose_table[sock->purpose] = NULL; + oa_close_socket(sock->socket); + return wait_for_client_read(sock, buf, buf_size, msg); + } + if (ret_val == -1) { + if (msg) { + sprintf(err_msg, "reading: %s", msg); + perror(err_msg); + } + return -1; + } + return ret_val; +} + +OPENAXIOM_C_EXPORT int +swrite(openaxiom_sio* sock, const Byte* buf, int buf_size, + const char* msg) +{ + int ret_val; + char err_msg[256]; + errno = 0; + socket_closed = 0; + ret_val = oa_socket_write(sock->socket, buf, buf_size); + if (ret_val == -1) { + if (socket_closed) { + FD_CLR(sock->socket, &socket_mask); + purpose_table[sock->purpose] = NULL; + /* printf(" closing socket %d\n", sock->socket); */ + oa_close_socket(sock->socket); + return wait_for_client_write(sock, buf, buf_size, msg); + } else { + if (msg) { + sprintf(err_msg, "writing: %s", msg); + perror(err_msg); + } + return -1; + } + } + return ret_val; +} + +OPENAXIOM_C_EXPORT int +sselect(int n,fd_set *rd, fd_set *wr, fd_set *ex, void *timeout) +{ + int ret_val; + do { + ret_val = select(n, rd, wr, ex, (struct timeval *) timeout); + } while (ret_val == -1 && openaxiom_syscall_was_cancelled()); + return ret_val; +} + +OPENAXIOM_C_EXPORT int +fill_buf(openaxiom_sio *sock, Byte* buf, int len, const char* msg) +{ + int bytes = 0, ret_val; + while(bytes < len) { + ret_val = sread(sock, buf + bytes, len - bytes, msg); + if (ret_val == -1) return -1; + bytes += ret_val; + } + return bytes; +} + +OPENAXIOM_C_EXPORT int +get_int(openaxiom_sio *sock) +{ + int val = -1, len; + len = fill_buf(sock, byte_address(val), sizeof(int), "get_int"); + if (len != sizeof(int)) { +#ifdef DEBUG + fprintf(stderr,"get_int: caught error\n",val); +#endif + return -1; + } +#ifdef DEBUG + fprintf(stderr,"get_int: received %d\n",val); +#endif + return val; +} + +OPENAXIOM_C_EXPORT int +sock_get_int(int purpose) +{ + if (accept_if_needed(purpose) != -1) + return get_int(purpose_table[purpose]); + else return -1; +} + +OPENAXIOM_C_EXPORT int +get_ints(openaxiom_sio *sock, int *vals, int num) +{ + int i; + for(i=0; i 1023) { + char *buf; + buf = (char*) malloc(len+1); + strncpy(buf,str,len); + buf[len]='\0'; + send_int(sock,len+1); + val = swrite(sock, (const Byte*) buf, len+1, "send_string_len"); + free(buf); + } else { + static char buf[1024]; + strncpy(buf, str, len); + buf[len] = '\0'; + send_int(sock, len+1); + val = swrite(sock, (const Byte*) buf, len+1, "send_string_len"); + } + if (val == -1) { + return val; + } + return 0; +} + +OPENAXIOM_C_EXPORT int +send_string(openaxiom_sio* sock, const char* str) +{ + int val, len = strlen(str); + send_int(sock, len+1); + val = swrite(sock, (const Byte*) str, len+1, "send_string"); + if (val == -1) { + return -1; + } + return 0; +} + + +OPENAXIOM_C_EXPORT int +sock_send_string(int purpose, const char *str) +{ + if (accept_if_needed(purpose) != -1) + return send_string(purpose_table[purpose], str); + return -1; +} + +OPENAXIOM_C_EXPORT int +sock_send_string_len(int purpose, const char* str, int len) +{ + if (accept_if_needed(purpose) != -1) + return send_string_len(purpose_table[purpose], str, len); + return -1; +} + +OPENAXIOM_C_EXPORT int +send_strings(openaxiom_sio *sock, const char** vals, int num) +{ + int i; + for(i=0; inbytes_pending == 0) + sock->nbytes_pending = get_int(sock); + nbytes_to_read = sock->nbytes_pending > buf_len + ? buf_len + : sock->nbytes_pending; + nbytes_read = fill_buf(sock, (Byte*)buf, nbytes_to_read, + "get_string_buf"); + if (nbytes_read == -1) { + sock->nbytes_pending = 0; + return NULL; + } + sock->nbytes_pending -= nbytes_read; + return sock->nbytes_pending == 0 ? NULL : buf; +} + +OPENAXIOM_C_EXPORT char * +sock_get_string_buf(int purpose, char* buf, int buf_len) +{ + if (accept_if_needed(purpose) != -1) + return get_string_buf(purpose_table[purpose], buf, buf_len); + return NULL; +} + +OPENAXIOM_C_EXPORT int +get_strings(openaxiom_sio *sock, char** vals,int num) +{ + int i; + for(i=0; ipurpose) { + case SessionManager: + case ViewportServer: + sock_accept_connection(sock->purpose); + ret_val = send_signal(purpose_table[sock->purpose], sig); + sock->socket = 0; + return ret_val; + default: + sock->socket = 0; + return -1; + } +} + + +OPENAXIOM_C_EXPORT int +sock_get_remote_fd(int purpose) +{ + if (accept_if_needed(purpose) != -1) + return purpose_table[purpose]->remote; + return -1; +} + +OPENAXIOM_C_EXPORT int +send_signal(openaxiom_sio *sock, int sig) +{ + int ret_val; +#if HAVE_DECL_KILL + ret_val = kill(sock->pid, sig); +#else + ret_val = raise(sig); +#endif + if (ret_val == -1 && errno == ESRCH) { + FD_CLR(sock->socket, &socket_mask); + purpose_table[sock->purpose] = NULL; +/* printf(" closing socket %d\n", sock->socket); */ + oa_close_socket(sock->socket); + return wait_for_client_kill(sock, sig); + } + return ret_val; +} + +OPENAXIOM_C_EXPORT int +sock_send_signal(int purpose,int sig) +{ + if (accept_if_needed(purpose) != -1) + return send_signal(purpose_table[purpose], sig); + return -1; +} + +OPENAXIOM_C_EXPORT int +send_wakeup(openaxiom_sio *sock) +{ +#ifdef SIGUSR1 + return send_signal(sock, SIGUSR1); +#else + return -1; +#endif +} + +OPENAXIOM_C_EXPORT int +sock_send_wakeup(int purpose) +{ + if (accept_if_needed(purpose) != -1) + return send_wakeup(purpose_table[purpose]); + return -1; +} + +OPENAXIOM_C_EXPORT openaxiom_sio * +connect_to_local_server_new(const char *server_name, int purpose, int time_out) +{ + int max_con=(time_out == 0 ? 1000000 : time_out), i, code=-1; + openaxiom_sio *sock; + char name[256]; + + make_server_name(name, server_name); + sock = (openaxiom_sio *) calloc(sizeof(openaxiom_sio), 1); + if (sock == NULL) { + perror("allocating socket space"); + return NULL; + } + + sock->socket = openaxiom_socket_stream_link(OPENAXIOM_AF_LOCAL); + if (is_invalid_socket(sock)) { + perror("opening client socket"); + free(sock); + return NULL; + } + + memset(server.addr.u_addr.sa_data, 0, + sizeof(server.addr.u_addr.sa_data)); + sock->addr.u_addr.sa_family = OPENAXIOM_AF_LOCAL; + strcpy(sock->addr.u_addr.sa_data, name); + for(i=0; isocket, &sock->addr.u_addr, + sizeof(sock->addr.u_addr)); + if (code == -1) { + if (errno != ENOENT && !openaxiom_connection_refused()) { + perror("connecting server stream socket"); + return NULL; + } else { + if (i != max_con - 1) + openaxiom_sleep(1); + continue; + } + } else break; + } + + if (code == -1) { + return NULL; + } + + send_int(sock, oa_getpid()); + send_int(sock, purpose); + send_int(sock, sock->socket); + sock->pid = get_int(sock); + sock->remote = get_int(sock); + return sock; +} + +OPENAXIOM_C_EXPORT openaxiom_sio * +connect_to_local_server(const char *server_name, int purpose, int time_out) +{ + int max_con=(time_out == 0 ? 1000000 : time_out), i, code=-1; + openaxiom_sio *sock; + char name[256]; + + make_server_name(name, server_name); + sock = (openaxiom_sio *) calloc(sizeof(openaxiom_sio), 1); + if (sock == NULL) { + perror("allocating socket space"); + return NULL; + } + + sock->purpose = purpose; + /* create the socket */ + sock->socket = openaxiom_socket_stream_link(OPENAXIOM_AF_LOCAL); + if (is_invalid_socket(sock)) { + perror("opening client socket"); + free(sock); + return NULL; + } + /* connect socket using name specified in command line */ + memset(server.addr.u_addr.sa_data, 0, + sizeof(server.addr.u_addr.sa_data)); + sock->addr.u_addr.sa_family = OPENAXIOM_AF_LOCAL; + strcpy(sock->addr.u_addr.sa_data, name); + for(i=0; isocket, &sock->addr.u_addr, + sizeof(sock->addr.u_addr)); + if (code == -1) { + if (errno != ENOENT && !openaxiom_connection_refused()) { + perror("connecting server stream socket"); + return NULL; + } else { + if (i != max_con - 1) + openaxiom_sleep(1); + continue; + } + } else break; + } + if (code == -1) { + return NULL; + } + send_int(sock, oa_getpid()); + send_int(sock, sock->purpose); + send_int(sock, sock->socket); + sock->pid = get_int(sock); +/* fprintf(stderr, "Got int form socket\n"); */ + sock->remote = get_int(sock); + return sock; +} + +/* act as terminal session for sock connected to stdin and stdout of another + process */ +OPENAXIOM_C_EXPORT void +remote_stdio(openaxiom_sio *sock) +{ + char buf[1024]; + fd_set rd; + int len; + while (1) { + FD_ZERO(&rd); + FD_SET(sock->socket,&rd); + FD_SET(0, &rd); + len = sselect(FD_SETSIZE, &rd, nullptr, nullptr, NULL); + if (len == -1) { + perror("stdio select"); + return; + } + if (FD_ISSET(0, &rd)) { + fgets(buf,1024,stdin); + len = strlen(buf); + swrite(sock, byte_address(buf), len, "remote_stdio::write"); + } + if (FD_ISSET(sock->socket, &rd)) { + len = sread(sock, byte_address(buf), 1024, "remote_stdio::read"); + if (len == -1) + return; + else { + *(buf + len) = '\0'; + fputs(buf, stdout); + fflush(stdout); + } + } + } +} + +/* initialize the table of dedicated sockets */ +static void +init_purpose_table() +{ + int i; + for(i=0; ipid = get_int(sock); + sock->purpose = get_int(sock); + sock->remote = get_int(sock); + send_int(sock, oa_getpid()); + send_int(sock, sock->socket); + purpose_table[sock->purpose] = sock; +} + +OPENAXIOM_C_EXPORT int +accept_connection() +{ + int client = 0; + while (client < MaxClients && clients[client].socket != 0) + ++client; + if (client == MaxClients) { + printf("Ran out of client openaxiom_sio structures\n"); + return -1; + } + clients[client].socket = accept(server.socket, 0, 0); + if (is_invalid_socket(&clients[client])) { + perror("accept_connection"); + clients[client].socket = 0; + return -1; + } + FD_SET(clients[client].socket, &socket_mask); + get_socket_type(&clients[client]); + return clients[client].purpose; +} + +OPENAXIOM_C_EXPORT int +sock_accept_connection(int purpose) +{ + fd_set rd; + int ret_val, p; + if (oa_getenv("SPADNUM") == NULL) return -1; + while (1) { + rd = server_mask; + ret_val = sselect(FD_SETSIZE, &rd, nullptr, nullptr, NULL); + if (ret_val == -1) { + perror ("Select"); + return -1; + } + if (is_valid_socket(&server) && FD_ISSET(server.socket, &rd)) { + p = accept_connection(); + if (p == purpose) return 1; + } + } +} + +/* Socket I/O selection called from the BOOT serverLoop function */ + +OPENAXIOM_C_EXPORT int +server_switch() +{ + int ret_val, cmd = 0; + fd_set rd, wr, ex, fds_mask; + FD_ZERO(&rd); + FD_ZERO(&wr); + FD_ZERO(&ex); + fds_mask = server_mask; + cmd = 0; + if (purpose_table[SessionManager] != NULL) { + FD_SET(0, &fds_mask); + FD_SET(purpose_table[SessionManager]->socket, &fds_mask); + } + while (1) { + do { + if (purpose_table[MenuServer] != NULL) { + FD_SET(purpose_table[MenuServer]->socket, &fds_mask); + } + rd = fds_mask; + ret_val = select(FD_SETSIZE, &rd, 0, 0, 0); + if (ret_val == -1) { + /* perror ("Select in switch"); */ + return -1; + } + if (is_valid_socket(&server) && FD_ISSET(server.socket, &rd)) + accept_connection(); + } while (purpose_table[SessionManager] == NULL); + FD_SET(purpose_table[SessionManager]->socket, &fds_mask); + if (FD_ISSET(purpose_table[SessionManager]->socket, &rd)) { + cmd = get_int(purpose_table[SessionManager]); + return cmd; + } + if (FD_ISSET(0, &rd)) { + return CallInterp; + } + if (purpose_table[MenuServer] != NULL && + (FD_ISSET(purpose_table[MenuServer]->socket, &rd))) { + cmd = get_int(purpose_table[MenuServer]); + return cmd; + } + } +} + +} diff --git a/src/syntax/Parser.cxx b/src/syntax/Parser.cxx new file mode 100644 index 00000000..e8759d2b --- /dev/null +++ b/src/syntax/Parser.cxx @@ -0,0 +1,134 @@ +// -*- C++ -*- +// Copyright (C) 2014-2017, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// 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 OpenAxiom. 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 +#include +#include + +#include +#include +#include +#include + +namespace { + using namespace OpenAxiom; + + using TokenSequence = TokenStream; + + // Simple wrapper around standard file streams, along with the pathname + // to the file. + template + struct FileAs { + const char* path; + T stream; + FileAs(const char* p, std::ios_base::openmode flags) + : path{ p }, stream{ p, flags } + { + if (!stream) + throw Error::CannotOpenFile{ path }; + } + }; + + using InputFile = FileAs; + using OutputFile = FileAs; + + // Helper function for streaming out details of tokens. + std::ostream& operator<<(std::ostream& os, const Token& t) { + os << t.category << '{' << t.start << '-' << t.end << '}'; + return os; + } + + // FIXME: This is just a stub to get a native parsing entry point + // into the bootsys and interpsys images. + void transpile_boot_to_lisp(InputFile& in, OutputFile& out) { + SourceInput src { in.stream }; + while (auto f = src.get()) { + out.stream << "================================================\n"; + out.stream << f; + try { + TokenSequence ts { f, Language::Boot }; + for (auto& t : ts) { + out.stream << '\t' << t; + switch (t.category) { + case TokenCategory::Junk: + case TokenCategory::Unclassified: + out.stream //<< f[t.start.line].sub_string(t.start.column, t.end.column) + << " in file " << in.path + << " at line " << t.start.line + << ", column " << t.start.column; + break; + default: + break; + } + out.stream << '\n'; + } + } + catch(const EndOfStringUnseen& e) { + std::cerr << in.path << ": syntax error: " + << "premature end of line before matching quote " + << "of string literal on line " << e.line + << " at column " << e.column + << std::endl; + } + catch (const MissingExponent& e) { + std::cerr << in.path << ": syntax error: " + << "missing exponent of floating point constant " + << "on line " << e.line + << ", column " << e.column + << std::endl; + } + out.stream << "================================================\n"; + } + out.stream << std::flush; + } +} + +namespace OpenAxiom { + + int boot_to_lisp(const char* boot_path, const char* lisp_path) try { + InputFile in { boot_path, std::ios_base::binary }; + OutputFile out { lisp_path, std::ios_base::binary }; + transpile_boot_to_lisp(in, out); + return 0; + } + catch (const Error::CannotOpenFile& e) { + Diagnostics::StandardStream diagnostics { }; + diagnostics.error() << "error: could not open file `" + << e.path << "'\n"; + return -1; + } +} diff --git a/src/syntax/token.cc b/src/syntax/token.cc deleted file mode 100644 index 74b58fa2..00000000 --- a/src/syntax/token.cc +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (C) 2013-2014, Gabriel Dos Reis. -// All rights reserved. -// Written by Gabriel Dos Reis. -// -// 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 OpenAxiom. 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 - -namespace OpenAxiom { - std::ostream& operator<<(std::ostream& os, const Locus& l) { - return os << '{' << l.line << ", " << l.column << '}'; - } - - std::ostream& - operator<<(std::ostream& os, TokenCategory tc) { - switch (tc) { - case TokenCategory::Unclassified: os << "UNCLASSIFIED"; break; - case TokenCategory::Whitespace: os << "WHITESPACE"; break; - case TokenCategory::Comment: os << "COMMENT"; break; - case TokenCategory::Punctuator: os << "PUNCTUATOR"; break; - case TokenCategory::Operator: os << "OPERATOR"; break; - case TokenCategory::Integer: os << "INTEGER"; break; - case TokenCategory::FloatingPoint: os << "FLOATINGPOINT"; break; - case TokenCategory::String: os << "STRING"; break; - case TokenCategory::Keyword: os << "KEYWORD"; break; - case TokenCategory::Identifier: os << "IDENTIFIER"; break; - case TokenCategory::Formatting: os << "FORMATTING"; break; - case TokenCategory::Junk: os << "JUNK"; break; - default: os << "????"; break; - } - return os; - } - - - bool separator_or_punctuator(uint8_t c) { - switch (c) { - case '.': case '`': case '^': case '&': case '~': case '*': - case '-': case '+': case ';': case ',': case '@': case '|': - case '\'': case ':': case '=': case '\\': case '"': case '/': - case '(': case ')': case '{': case '}': case '[': case ']': - case '<': case '>': case '#': case ' ': - return true; - default: - return false; - } - } - - namespace { - struct TokenMapEntry { - const char* const text; - const TokenCategory category; - const TokenValue value; - const Language dialect; // = Language::Spad - }; - } - - const TokenMapEntry token_map[] { -#undef OPENAXIOM_DEFINE_TOKEN -#define OPENAXIOM_DEFINE_TOKEN(T, N, C, ...) \ - { N, TokenCategory::C, TokenValue::T, __VA_ARGS__ }, -#include -#undef OPENAXIOM_DEFINE_TOKEN - }; - - TokenClassification - classify(const std::string& s) { - for (auto& t : token_map) { - if (t.text == s) - return { t.category, t.value }; - } - return { TokenCategory::Identifier, TokenValue::Unknown }; - } - - std::ostream& - operator<<(std::ostream& os, TokenValue tv) { - if (tv < TokenValue::Artificial) - os << token_map[uint8_t(tv)].text; - else switch (tv) { - case TokenValue::Indent: os << "%INDENT"; break; - case TokenValue::Unindent: os << "%UNIDENT"; break; - case TokenValue::Justify: os << "%JUSTIFY"; break; - default: os << "%ALIEN"; break; - } - - return os; - } - -} diff --git a/src/syntax/token.cxx b/src/syntax/token.cxx new file mode 100644 index 00000000..74b58fa2 --- /dev/null +++ b/src/syntax/token.cxx @@ -0,0 +1,116 @@ +// Copyright (C) 2013-2014, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// 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 OpenAxiom. 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 + +namespace OpenAxiom { + std::ostream& operator<<(std::ostream& os, const Locus& l) { + return os << '{' << l.line << ", " << l.column << '}'; + } + + std::ostream& + operator<<(std::ostream& os, TokenCategory tc) { + switch (tc) { + case TokenCategory::Unclassified: os << "UNCLASSIFIED"; break; + case TokenCategory::Whitespace: os << "WHITESPACE"; break; + case TokenCategory::Comment: os << "COMMENT"; break; + case TokenCategory::Punctuator: os << "PUNCTUATOR"; break; + case TokenCategory::Operator: os << "OPERATOR"; break; + case TokenCategory::Integer: os << "INTEGER"; break; + case TokenCategory::FloatingPoint: os << "FLOATINGPOINT"; break; + case TokenCategory::String: os << "STRING"; break; + case TokenCategory::Keyword: os << "KEYWORD"; break; + case TokenCategory::Identifier: os << "IDENTIFIER"; break; + case TokenCategory::Formatting: os << "FORMATTING"; break; + case TokenCategory::Junk: os << "JUNK"; break; + default: os << "????"; break; + } + return os; + } + + + bool separator_or_punctuator(uint8_t c) { + switch (c) { + case '.': case '`': case '^': case '&': case '~': case '*': + case '-': case '+': case ';': case ',': case '@': case '|': + case '\'': case ':': case '=': case '\\': case '"': case '/': + case '(': case ')': case '{': case '}': case '[': case ']': + case '<': case '>': case '#': case ' ': + return true; + default: + return false; + } + } + + namespace { + struct TokenMapEntry { + const char* const text; + const TokenCategory category; + const TokenValue value; + const Language dialect; // = Language::Spad + }; + } + + const TokenMapEntry token_map[] { +#undef OPENAXIOM_DEFINE_TOKEN +#define OPENAXIOM_DEFINE_TOKEN(T, N, C, ...) \ + { N, TokenCategory::C, TokenValue::T, __VA_ARGS__ }, +#include +#undef OPENAXIOM_DEFINE_TOKEN + }; + + TokenClassification + classify(const std::string& s) { + for (auto& t : token_map) { + if (t.text == s) + return { t.category, t.value }; + } + return { TokenCategory::Identifier, TokenValue::Unknown }; + } + + std::ostream& + operator<<(std::ostream& os, TokenValue tv) { + if (tv < TokenValue::Artificial) + os << token_map[uint8_t(tv)].text; + else switch (tv) { + case TokenValue::Indent: os << "%INDENT"; break; + case TokenValue::Unindent: os << "%UNIDENT"; break; + case TokenValue::Justify: os << "%JUSTIFY"; break; + default: os << "%ALIEN"; break; + } + + return os; + } + +} diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am index dc138e11..d2f49303 100644 --- a/src/utils/Makefile.am +++ b/src/utils/Makefile.am @@ -1,4 +1,4 @@ -# Copyright (C) 2011-2014, Gabriel Dos Reis. +# Copyright (C) 2011-2017, Gabriel Dos Reis. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -40,9 +40,6 @@ libOpenAxiom_a_SOURCES = \ storage.cc string-pool.cc command.cc \ filesystem.cc \ ../io/Input.cc \ - ../io/std-streams.cc \ - ../io/InputFragment.cxx \ - ../syntax/token.cc \ ../syntax/sexpr.cc \ ../rt/vm.cc \ ../rt/Lisp.cc \ diff --git a/src/utils/Makefile.in b/src/utils/Makefile.in index 95e438e6..2e2d184c 100644 --- a/src/utils/Makefile.in +++ b/src/utils/Makefile.in @@ -14,7 +14,7 @@ @SET_MAKE@ -# Copyright (C) 2011-2014, Gabriel Dos Reis. +# Copyright (C) 2011-2017, Gabriel Dos Reis. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -147,10 +147,8 @@ libOpenAxiom_a_LIBADD = am__dirstamp = $(am__leading_dot)dirstamp am_libOpenAxiom_a_OBJECTS = storage.$(OBJEXT) string-pool.$(OBJEXT) \ command.$(OBJEXT) filesystem.$(OBJEXT) ../io/Input.$(OBJEXT) \ - ../io/std-streams.$(OBJEXT) ../io/InputFragment.$(OBJEXT) \ - ../syntax/token.$(OBJEXT) ../syntax/sexpr.$(OBJEXT) \ - ../rt/vm.$(OBJEXT) ../rt/Lisp.$(OBJEXT) \ - ../rt/Database.$(OBJEXT) + ../syntax/sexpr.$(OBJEXT) ../rt/vm.$(OBJEXT) \ + ../rt/Lisp.$(OBJEXT) ../rt/Database.$(OBJEXT) libOpenAxiom_a_OBJECTS = $(am_libOpenAxiom_a_OBJECTS) PROGRAMS = $(noinst_PROGRAMS) am_hammer_OBJECTS = hammer.$(OBJEXT) @@ -425,9 +423,6 @@ libOpenAxiom_a_SOURCES = \ storage.cc string-pool.cc command.cc \ filesystem.cc \ ../io/Input.cc \ - ../io/std-streams.cc \ - ../io/InputFragment.cxx \ - ../syntax/token.cc \ ../syntax/sexpr.cc \ ../rt/vm.cc \ ../rt/Lisp.cc \ @@ -488,18 +483,12 @@ clean-noinstLIBRARIES: @: > ../io/$(DEPDIR)/$(am__dirstamp) ../io/Input.$(OBJEXT): ../io/$(am__dirstamp) \ ../io/$(DEPDIR)/$(am__dirstamp) -../io/std-streams.$(OBJEXT): ../io/$(am__dirstamp) \ - ../io/$(DEPDIR)/$(am__dirstamp) -../io/InputFragment.$(OBJEXT): ../io/$(am__dirstamp) \ - ../io/$(DEPDIR)/$(am__dirstamp) ../syntax/$(am__dirstamp): @$(MKDIR_P) ../syntax @: > ../syntax/$(am__dirstamp) ../syntax/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) ../syntax/$(DEPDIR) @: > ../syntax/$(DEPDIR)/$(am__dirstamp) -../syntax/token.$(OBJEXT): ../syntax/$(am__dirstamp) \ - ../syntax/$(DEPDIR)/$(am__dirstamp) ../syntax/sexpr.$(OBJEXT): ../syntax/$(am__dirstamp) \ ../syntax/$(DEPDIR)/$(am__dirstamp) ../rt/$(am__dirstamp): @@ -543,13 +532,10 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@../io/$(DEPDIR)/Input.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@../io/$(DEPDIR)/InputFragment.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@../io/$(DEPDIR)/std-streams.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@../rt/$(DEPDIR)/Database.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@../rt/$(DEPDIR)/Lisp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@../rt/$(DEPDIR)/vm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@../syntax/$(DEPDIR)/sexpr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@../syntax/$(DEPDIR)/token.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/command.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filesystem.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hammer.Po@am__quote@ @@ -580,30 +566,6 @@ distclean-compile: @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< -.cxx.o: -@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ -@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ -@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< - -.cxx.obj: -@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ -@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ -@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` - -.cxx.lo: -@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ -@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ -@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< - mostlyclean-libtool: -rm -f *.lo -- cgit v1.2.3