>From 2521dedb696298e87e8763a71613813d3fe9cd9f Mon Sep 17 00:00:00 2001 From: dmh <[email protected]> Date: Tue, 3 Sep 2013 15:47:46 -0600 Subject: [PATCH 2/2] Add support for parsers using the python language. Part 2: new files
* gnulib/build-aux/pythoncomp.sh.in: New. * gnulib/build-aux/pythonexec.sh.in: New. * gnulib/lib/pythoncomp.c: New. * gnulib/lib/pythoncomp.h: New. * gnulib/lib/pythonexec.c: New. * gnulib/lib/pythonexec.h: New. * gnulib/m4/pythoncomp.m4: New. * gnulib/m4/pythonexec.m4: New. * gnulib/modules/pythoncomp: New. * gnulib/modules/pythoncomp-script: New. * gnulib/modules/pythonexec: New. * gnulib/modules/pythonexec-script: New. --- build-aux/pythoncomp.sh.in | 34 +++++++++ build-aux/pythonexec.sh.in | 34 +++++++++ lib/pythoncomp.c | 110 +++++++++++++++++++++++++++ lib/pythoncomp.h | 31 ++++++++ lib/pythonexec.c | 180 +++++++++++++++++++++++++++++++++++++++++++++ lib/pythonexec.h | 40 ++++++++++ m4/pythoncomp.m4 | 55 ++++++++++++++ m4/pythonexec.m4 | 55 ++++++++++++++ modules/pythoncomp | 46 ++++++++++++ modules/pythoncomp-script | 20 +++++ modules/pythonexec | 36 +++++++++ modules/pythonexec-script | 24 ++++++ 12 files changed, 665 insertions(+) create mode 100644 build-aux/pythoncomp.sh.in create mode 100644 build-aux/pythonexec.sh.in create mode 100644 lib/pythoncomp.c create mode 100644 lib/pythoncomp.h create mode 100644 lib/pythonexec.c create mode 100644 lib/pythonexec.h create mode 100644 m4/pythoncomp.m4 create mode 100644 m4/pythonexec.m4 create mode 100644 modules/pythoncomp create mode 100644 modules/pythoncomp-script create mode 100644 modules/pythonexec create mode 100644 modules/pythonexec-script diff --git a/build-aux/pythoncomp.sh.in b/build-aux/pythoncomp.sh.in new file mode 100644 index 0000000..0840fad --- /dev/null +++ b/build-aux/pythoncomp.sh.in @@ -0,0 +1,34 @@ +#!/bin/sh +# Compile a Python program. + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Written by Bruno Haible <[email protected]>, 2001. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# This uses the same choices as pythonexec.c, but instead of relying on the +# environment settings at run time, it uses the environment variables +# present at configuration time. +# +# This is a separate shell script, because it must be able to unset PYTHON_HOME +# in some cases, which a simple shell command cannot do. +# + +CONF_PYTHONC='@CONF_PYTHONC@' +unset PYTHON_HOME +if test -n "@HAVE_PYTHON@"; then + # In this case, $CONF_PYTHONC is "python". + test -z "$PYTHON_VERBOSE" || echo "$CONF_PYTHONC $@" + exec $CONF_PYTHONC "$@" +fi diff --git a/build-aux/pythonexec.sh.in b/build-aux/pythonexec.sh.in new file mode 100644 index 0000000..1a655ec --- /dev/null +++ b/build-aux/pythonexec.sh.in @@ -0,0 +1,34 @@ +#!/bin/sh +# Execute a Python program. + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Written by Bruno Haible <[email protected]>, 2001. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# This uses the same choices as pythonexec.c, but instead of relying on the +# environment settings at run time, it uses the environment variables +# present at configuration time. +# +# This is a separate shell script, because it must be able to unset PYTHON_HOME +# in some cases, which a simple shell command cannot do. +# + +CONF_PYTHON='@CONF_PYTHON@' +unset PYTHON_HOME +if test -n "@HAVE_PYTHON@"; then + # In this case, $CONF_PYTHON is "python". + test -z "$PYTHON_VERBOSE" || echo "$CONF_PYTHON $@" + exec $CONF_PYTHON "$@" +fi diff --git a/lib/pythoncomp.c b/lib/pythoncomp.c new file mode 100644 index 0000000..4f58e07 --- /dev/null +++ b/lib/pythoncomp.c @@ -0,0 +1,110 @@ +/* Compile (Syntax Check) a Python program. + Copyright (C) 2001-2003, 2006-2013 Free Software Foundation, Inc. + Written by Bruno Haible <[email protected]>, 2001. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> +#include <alloca.h> + +/* Specification. */ +#include "pythoncomp.h" + +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "pythonversion.h" +#include "execute.h" +#include "spawn-pipe.h" +#include "wait-process.h" +#include "classpath.h" +#include "xsetenv.h" +#include "sh-quote.h" +#include "binary-io.h" +#include "safe-read.h" +#include "xalloc.h" +#include "xmalloca.h" +#include "concat-filename.h" +#include "fwriteerror.h" +#include "clean-temp.h" +#include "error.h" +#include "xvasprintf.h" +#include "c-strstr.h" +#include "gettext.h" + +#define _(str) gettext (str) + + +/* Try to compile a set of Python sources with python. + Return a failure indicator (true upon error). */ +static bool +compile_using_pythonc (const char * const *python_sources, + unsigned int python_sources_count, + bool verbose, bool null_stderr) +{ + bool err; + unsigned int argc; + char **argv; + char **argp; + int exitstatus; + unsigned int i; + + argc = + 1 + python_sources_count + 4; + *argp++ = "-t"; + *argp++ = "-t"; + *argp++ = "-m"; + *argp++ = "py_compile"; + for (i = 0; i < python_sources_count; i++) + *argp++ = (char *) python_sources[i]; + *argp = NULL; + /* Ensure argv length was correctly calculated. */ + if (argp - argv != argc) + abort (); + + if (verbose) + { + char *command = shell_quote_argv (argv); + printf ("%s\n", command); + free (command); + } + + exitstatus = execute ("python", "python", argv, false, false, false, + null_stderr, true, true, NULL); + err = (exitstatus != 0); + + freea (argv); + + return err; +} +/* ============================= Main function ============================= */ + +bool +compile_python_class (const char * const *python_sources, + unsigned int python_sources_count, + bool verbose) +{ + bool err = false; + err = compile_using_python (python_sources, python_sources_count, + verbose, + false); + false); + return err; +} diff --git a/lib/pythoncomp.h b/lib/pythoncomp.h new file mode 100644 index 0000000..0f1efc6 --- /dev/null +++ b/lib/pythoncomp.h @@ -0,0 +1,31 @@ +/* Compile a Python program. + Copyright (C) 2001-2002, 2009-2013 Free Software Foundation, Inc. + Copied from javaexec.h. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _PYTHONCOMP_H +#define _PYTHONCOMP_H + +#include <stdbool.h> + +/* Compile (Really Syntax Check) a Python source file + python_sources is an array of source file names. + If verbose, the command to be executed will be printed. + Return false if OK, true on error. */ +extern bool compile_python_class (const char * const *python_sources, + unsigned int python_sources_count, + bool verbose); + +#endif /* _PYTHONCOMP_H */ diff --git a/lib/pythonexec.c b/lib/pythonexec.c new file mode 100644 index 0000000..b87c9ae --- /dev/null +++ b/lib/pythonexec.c @@ -0,0 +1,180 @@ +/* Execute a Python program. + Copyright (C) 2001-2003, 2006-2013 Free Software Foundation, Inc. + Written by Bruno Haible <[email protected]>, 2001. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> +#include <alloca.h> + +/* Specification. */ +#include "pythonexec.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "execute.h" +#include "classpath.h" +#include "xsetenv.h" +#include "sh-quote.h" +#include "concat-filename.h" +#include "xalloc.h" +#include "xmalloca.h" +#include "error.h" +#include "gettext.h" + +#define _(str) gettext (str) + + +bool +execute_python_class (const char *program_name, + const char * const *args, + bool verbose, bool quiet, + execute_fn *executer, void *private_data) +{ + bool err = false; + unsigned int nargs; + char *old_PYTHON_HOME; + + /* Count args. */ + { + const char * const *arg; + + for (nargs = 0, arg = args; *arg != NULL; nargs++, arg++) + ; + } + + { + const char *python = getenv ("PYTHON"); + if (python != NULL && python[0] != '\0') + { + /* Because $PYTHON may consist of a command and options, we use the + shell. Because $PYTHON has been set by the user, we leave all + all environment variables in place, including PYTHON_HOME. + */ + unsigned int command_length; + char *command; + char *argv[4]; + const char * const *arg; + char *p; + + command_length = strlen (python); + command_length += 1 + shell_quote_length (program_name); + for (arg = args; *arg != NULL; arg++) + command_length += 1 + shell_quote_length (*arg); + command_length += 1; + + command = (char *) xmalloca (command_length); + p = command; + /* Don't shell_quote $PYTHON, because it may consist of a command + and options. */ + memcpy (p, python, strlen (python)); + p += strlen (python); + *p++ = ' '; + p = shell_quote_copy (p, program_name); + for (arg = args; *arg != NULL; arg++) + { + *p++ = ' '; + p = shell_quote_copy (p, *arg); + } + *p++ = '\0'; + /* Ensure command_length was correctly calculated. */ + if (p - command > command_length) + abort (); + + if (verbose) + printf ("%s\n", command); + + argv[0] = "/bin/sh"; + argv[1] = "-c"; + argv[2] = command; + argv[3] = NULL; + err = executer (python, "/bin/sh", argv, private_data); + + freea (command); + + /* Reset CLASSPATH. */ + reset_classpath (old_classpath); + + goto done1; + } + } + + /* Unset the PYTHON_HOME environment variable. */ + old_PYTHON_HOME = getenv ("PYTHON_HOME"); + if (old_PYTHON_HOME != NULL) + { + old_PYTHON_HOME = xstrdup (old_PYTHON_HOME); + unsetenv ("PYTHON_HOME"); + } + + { + static bool python_tested; + static bool python_present; + + if (!python_tested) + { + /* Test for presence of python: "python --version 2> /dev/null" */ + char *argv[3]; + int exitstatus; + + argv[0] = "python"; + argv[1] = "--version"; + argv[2] = NULL; + exitstatus = execute ("python", "python", argv, false, false, true, true, + true, false, NULL); + python_present = (exitstatus == 0); + python_tested = true; + } + + if (python_present) + { + char **argv = (char **) xmalloca ((2 + nargs + 1) * sizeof (char *)); + unsigned int i; + + argv[0] = "python"; + argv[1] = (char *) program_name; + for (i = 0; i <= nargs; i++) + argv[2 + i] = (char *) args[i]; + + if (verbose) + { + char *command = shell_quote_argv (argv); + printf ("%s\n", command); + free (command); + } + + err = executer ("python", "python", argv, private_data); + + freea (argv); + + goto done2; + } + } + + if (!quiet) + error (0, 0, _("Python virtual machine not found.")); + err = true; + + done2: + if (old_PYTHON_HOME != NULL) + { + xsetenv ("PYTHON_HOME", old_PYTHON_HOME, 1); + free (old_PYTHON_HOME); + } + + done1: + return err; +} diff --git a/lib/pythonexec.h b/lib/pythonexec.h new file mode 100644 index 0000000..1cd8bce --- /dev/null +++ b/lib/pythonexec.h @@ -0,0 +1,40 @@ +/* Execute a Python program. + Copyright (C) 2001-2002, 2009-2013 Free Software Foundation, Inc. + Copied from javaexec.h. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _PYTHONEXEC_H +#define _PYTHONEXEC_H + +#include <stdbool.h> + +typedef bool execute_fn (const char *progname, + const char *prog_path, char **prog_argv, + void *private_data); + +/* Execute a Python program + program_name is the Python program name to be executed. + args is a NULL terminated list of arguments to be passed to the program. + If verbose, the command to be executed will be printed. + Then the command is passed to the execute function together with the + private_data argument. This function returns false if OK, true on error. + Return false if OK, true on error. + If quiet, error messages will not be printed. */ +extern bool execute_python_class (const char *program_name, + const char * const *args, + bool verbose, bool quiet, + execute_fn *executer, void *private_data); + +#endif /* _PYTHONEXEC_H */ diff --git a/m4/pythoncomp.m4 b/m4/pythoncomp.m4 new file mode 100644 index 0000000..218f2f0 --- /dev/null +++ b/m4/pythoncomp.m4 @@ -0,0 +1,55 @@ +# pythoncomp.m4 serial 5 +dnl Copyright (C) 2001-2003, 2006, 2009-2013 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +# Prerequisites of pythoncomp.sh. +# gt_PYTHONCOMP or gt_PYTHONCOMP(testclass, its-directory) +# Sets HAVE_PYTHONCOMP to nonempty if pythoncomp.sh will work. + +AC_DEFUN([gt_PYTHONCOMP], +[ + AC_MSG_CHECKING([for Python]) + AC_EGREP_CPP([yes], [ +#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__ + yes +#endif +], CLASSPATH_SEPARATOR=';', CLASSPATH_SEPARATOR=':') + CONF_PYTHONC= + HAVE_PYTHON_ENVVAR= + HAVE_PYTHON= + HAVE_PYTHONCOMP=1 + if test -n "$PYTHON"; then + HAVE_PYTHON_ENVVAR=1 + CONF_PYTHONC="$PYTHON -t -t -m py_compile" + else + pushdef([AC_MSG_CHECKING],[:])dnl + pushdef([AC_CHECKING],[:])dnl + pushdef([AC_MSG_RESULT],[:])dnl + AC_CHECK_PROG([HAVE_PYTHON_IN_PATH], [python], [yes]) + popdef([AC_MSG_RESULT])dnl + popdef([AC_CHECKING])dnl + popdef([AC_MSG_CHECKING])dnl + if test -n "$HAVE_PYTHON_IN_PATH" \ + && python --version >/dev/null 2>/dev/null \ + ifelse([$1], , , [&& { + echo "$as_me:__oline__: gij $1" >&AS_MESSAGE_LOG_FD + python $1 >&AS_MESSAGE_LOG_FD 2>&1 + }]); then + HAVE_PYTHON=1 + CONF_PYTHONC="python -t -t -m py_compile" + fi + fi + if test -n "$HAVE_PYTHONCOMP"; then + ac_result="$CONF_PYTHONC" + else + ac_result="no" + fi + AC_MSG_RESULT([$ac_result]) + AC_SUBST([CONF_PYTHONC]) + AC_SUBST([CLASSPATH]) + AC_SUBST([CLASSPATH_SEPARATOR]) + AC_SUBST([HAVE_PYTHON_ENVVAR]) + AC_SUBST([HAVE_PYTHON]) +]) diff --git a/m4/pythonexec.m4 b/m4/pythonexec.m4 new file mode 100644 index 0000000..1c2d3a7 --- /dev/null +++ b/m4/pythonexec.m4 @@ -0,0 +1,55 @@ +# pythonexec.m4 serial 5 +dnl Copyright (C) 2001-2003, 2006, 2009-2013 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +# Prerequisites of pythonexec.sh. +# gt_PYTHONEXEC or gt_PYTHONEXEC(testclass, its-directory) +# Sets HAVE_PYTHONEXEC to nonempty if pythonexec.sh will work. + +AC_DEFUN([gt_PYTHONEXEC], +[ + AC_MSG_CHECKING([for Python]) + AC_EGREP_CPP([yes], [ +#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__ + yes +#endif +], CLASSPATH_SEPARATOR=';', CLASSPATH_SEPARATOR=':') + CONF_PYTHON= + HAVE_PYTHON_ENVVAR= + HAVE_PYTHON= + HAVE_PYTHONEXEC=1 + if test -n "$PYTHON"; then + HAVE_PYTHON_ENVVAR=1 + CONF_PYTHON="$PYTHON" + else + pushdef([AC_MSG_CHECKING],[:])dnl + pushdef([AC_CHECKING],[:])dnl + pushdef([AC_MSG_RESULT],[:])dnl + AC_CHECK_PROG([HAVE_PYTHON_IN_PATH], [python], [yes]) + popdef([AC_MSG_RESULT])dnl + popdef([AC_CHECKING])dnl + popdef([AC_MSG_CHECKING])dnl + if test -n "$HAVE_PYTHON_IN_PATH" \ + && python --version >/dev/null 2>/dev/null \ + ifelse([$1], , , [&& { + echo "$as_me:__oline__: gij $1" >&AS_MESSAGE_LOG_FD + python $1 >&AS_MESSAGE_LOG_FD 2>&1 + }]); then + HAVE_PYTHON=1 + CONF_PYTHON="python" + fi + fi + if test -n "$HAVE_PYTHONEXEC"; then + ac_result="$CONF_PYTHON" + else + ac_result="no" + fi + AC_MSG_RESULT([$ac_result]) + AC_SUBST([CONF_PYTHON]) + AC_SUBST([CLASSPATH]) + AC_SUBST([CLASSPATH_SEPARATOR]) + AC_SUBST([HAVE_PYTHON_ENVVAR]) + AC_SUBST([HAVE_PYTHON]) +]) diff --git a/modules/pythoncomp b/modules/pythoncomp new file mode 100644 index 0000000..ea5710f --- /dev/null +++ b/modules/pythoncomp @@ -0,0 +1,46 @@ +Description: +Compile a Python program. + +Files: +lib/pythoncomp.h +lib/pythoncomp.c + +Depends-on: +stdbool +unistd +pythonversion +execute +spawn-pipe +wait-process +classpath +xsetenv +sh-quote +binary-io +safe-read +xalloc +xmalloca +getline +xconcat-filename +fwriteerror +clean-temp +error +xvasprintf +c-strstr +gettext-h +pythoncomp-script + +configure.ac: + +Makefile.am: +lib_SOURCES += pythoncomp.h pythoncomp.c + +Include: +"pythoncomp.h" + +License: +GPL + +Maintainer: +Dennis Heimbigner + + diff --git a/modules/pythoncomp-script b/modules/pythoncomp-script new file mode 100644 index 0000000..8536a37 --- /dev/null +++ b/modules/pythoncomp-script @@ -0,0 +1,20 @@ +Description: +Script to compile a Python program. + +Files: +build-aux/pythoncomp.sh.in +m4/pythoncomp.m4 + +Depends-on: + +configure.ac: +# You need to invoke gt_PYTHONCOMP yourself, possibly with arguments. +AC_CONFIG_FILES([pythoncomp.sh:build-aux/pythoncomp.sh.in]) + +Makefile.am: + +License: +GPLed build tool + +Maintainer: +Dennis Heimbigner diff --git a/modules/pythonexec b/modules/pythonexec new file mode 100644 index 0000000..92209b7 --- /dev/null +++ b/modules/pythonexec @@ -0,0 +1,36 @@ +Description: +Execute a Python program. + +Files: +lib/pythonexec.h +lib/pythonexec.c + +Depends-on: +stdbool +execute +classpath +xsetenv +sh-quote +xconcat-filename +xalloc +xmalloca +error +gettext-h +pythonexec-script + +configure.ac: + +Makefile.am: +DEFS += -DEXEEXT=\"@EXEEXT@\" +lib_SOURCES += pythonexec.h pythonexec.c + +Include: +"pythonexec.h" + +License: +GPL + +Maintainer: +Dennis Heimbigner + + diff --git a/modules/pythonexec-script b/modules/pythonexec-script new file mode 100644 index 0000000..6ef6b41 --- /dev/null +++ b/modules/pythonexec-script @@ -0,0 +1,24 @@ +Description: +Execute a Python program. + +Files: +build-aux/pythonexec.sh.in +m4/pythonexec.m4 + +Depends-on: + +configure.ac: +# You need to invoke gt_PYTHONEXEC yourself, possibly with arguments. +AC_CONFIG_FILES([pythonexec.sh:build-aux/pythonexec.sh.in]) + +Makefile.am: + +Include: + +License: +GPLed build tool + +Maintainer: +Dennis Heimbigner + + -- 1.8.4.rc0.1.g8f6a3e5
