summaryrefslogtreecommitdiffstats
path: root/tools/gimptool.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tools/gimptool.c1142
1 files changed, 1142 insertions, 0 deletions
diff --git a/tools/gimptool.c b/tools/gimptool.c
new file mode 100644
index 0000000..21fc043
--- /dev/null
+++ b/tools/gimptool.c
@@ -0,0 +1,1142 @@
+/* gimptool in C
+ * Copyright (C) 2001-2007 Tor Lillqvist
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Gimptool rewritten in C, originally for Win32, where end-users who
+ * might want to build and install a plug-in from source don't
+ * necessarily have any Bourne-compatible shell to run the gimptool
+ * script in. Later fixed up to replace the gimptool script on all
+ * platforms.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/stat.h>
+
+#include <gio/gio.h>
+
+#include "libgimpbase/gimpbase.h"
+
+#ifdef G_OS_WIN32
+#include "libgimpbase/gimpwin32-io.h"
+#endif
+
+
+static gboolean silent = FALSE;
+static gboolean dry_run = FALSE;
+static const gchar *cli_prefix;
+static const gchar *cli_exec_prefix;
+
+static gboolean msvc_syntax = FALSE;
+static const gchar *env_cc;
+static const gchar *env_cflags;
+static const gchar *env_ldflags;
+static const gchar *env_libs;
+
+
+#ifdef G_OS_WIN32
+#define EXEEXT ".exe"
+#else
+#define EXEEXT ""
+#endif
+
+#ifdef G_OS_WIN32
+#define COPY win32_command ("copy")
+#define REMOVE win32_command ("del")
+#define REMOVE_DIR win32_command ("rd /s /q")
+#else
+#define COPY "cp"
+#define REMOVE "rm -f"
+#define REMOVE_DIR "rm -Rf"
+#endif
+
+static struct {
+ const gchar *option;
+ const gchar *value;
+} dirs[] = {
+ { "prefix", PREFIX },
+ { "exec-prefix", EXEC_PREFIX },
+ { "bindir", BINDIR },
+ { "sbindir", SBINDIR },
+ { "libexecdir", LIBEXECDIR },
+ { "datadir", DATADIR },
+ { "datarootdir", DATAROOTDIR },
+ { "sysconfdir", SYSCONFDIR },
+ { "sharedstatedir", SHAREDSTATEDIR },
+ { "localstatedir", LOCALSTATEDIR },
+ { "libdir", LIBDIR },
+ { "infodir", INFODIR },
+ { "mandir", MANDIR },
+#if 0
+ /* For --includedir we want the includedir of the developer package,
+ * not an includedir under the runtime installation prefix.
+ */
+ { "includedir", INCLUDEDIR },
+#endif
+ { "gimpplugindir", GIMPPLUGINDIR },
+ { "gimpdatadir", GIMPDATADIR }
+};
+
+
+static void usage (int exit_status) G_GNUC_NORETURN;
+
+
+#ifdef G_OS_WIN32
+
+static gchar *
+win32_command (const gchar *command)
+{
+ const gchar *comspec = getenv ("COMSPEC");
+
+ if (!comspec)
+ comspec = "cmd.exe";
+
+ return g_strdup_printf ("%s /c %s", comspec, command);
+}
+
+#endif
+
+static gboolean
+starts_with_dir (const gchar *string,
+ const gchar *dir)
+{
+ gchar *dirslash = g_strconcat (dir, "/", NULL);
+ gboolean retval;
+
+ retval = (g_str_has_prefix (string, dirslash) ||
+ g_strcmp0 (string, dir) == 0);
+ g_free (dirslash);
+
+ return retval;
+}
+
+static gchar *
+one_line_output (const gchar *program,
+ const gchar *args)
+{
+ gchar *command = g_strconcat (program, " ", args, NULL);
+ FILE *pipe = popen (command, "r");
+ gchar line[4096];
+
+ if (pipe == NULL)
+ {
+ g_printerr ("Cannot run '%s'\n", command);
+ g_free (command);
+ exit (EXIT_FAILURE);
+ }
+
+ if (fgets (line, sizeof (line), pipe) == NULL)
+ line[0] = '\0';
+
+ if (strlen (line) > 0 && line [strlen (line) - 1] == '\n')
+ line [strlen (line) - 1] = '\0';
+ if (strlen (line) > 0 && line [strlen (line) - 1] == '\r')
+ line [strlen (line) - 1] = '\0';
+
+ pclose (pipe);
+
+ if (strlen (line) == 0)
+ {
+ g_printerr ("No output from '%s'\n", command);
+ g_free (command);
+ exit (EXIT_FAILURE);
+ }
+ g_free (command);
+
+ return g_strdup (line);
+}
+
+static gchar *
+pkg_config (const gchar *args)
+{
+#ifdef G_OS_WIN32
+ if (msvc_syntax)
+ return one_line_output ("pkg-config --msvc-syntax", args);
+#endif
+
+ return one_line_output ("pkg-config", args);
+}
+
+static gchar *
+get_runtime_prefix (gchar slash)
+{
+#ifdef G_OS_WIN32
+
+ /* Don't use the developer package prefix, but deduce the
+ * installation-time prefix from where gimp-x.y.exe can be found.
+ */
+
+ gchar *path;
+ gchar *p, *r;
+
+ path = g_find_program_in_path ("gimp-" GIMP_APP_VERSION ".exe");
+
+ if (path == NULL)
+ path = g_find_program_in_path ("gimp.exe");
+
+ if (path != NULL)
+ {
+ r = strrchr (path, G_DIR_SEPARATOR);
+ if (r != NULL)
+ {
+ *r = '\0';
+ if (strlen (path) >= 4 &&
+ g_ascii_strcasecmp (r - 4, G_DIR_SEPARATOR_S "bin") == 0)
+ {
+ r[-4] = '\0';
+ if (slash == '/')
+ {
+ /* Use forward slashes, less quoting trouble in Makefiles */
+ while ((p = strchr (path, '\\')) != NULL)
+ *p = '/';
+ }
+ return path;
+ }
+ }
+ }
+
+ g_printerr ("Cannot determine GIMP " GIMP_APP_VERSION " installation location\n");
+
+ exit (EXIT_FAILURE);
+#else
+ /* On Unix assume the executable package is in the same prefix as the developer stuff */
+ return pkg_config ("--variable=prefix gimp-" GIMP_PKGCONFIG_VERSION);
+#endif
+}
+
+static gchar *
+get_exec_prefix (gchar slash)
+{
+#ifdef G_OS_WIN32
+ if (cli_exec_prefix != NULL)
+ return g_strdup (cli_exec_prefix);
+
+ /* On Win32, exec_prefix is always same as prefix. Or is it? Maybe not,
+ * but at least in tml's prebuilt stuff it is. If somebody else does
+ * it another way, feel free to hack this.
+ */
+ return get_runtime_prefix (slash);
+#else
+ return g_strdup (EXEC_PREFIX);
+#endif
+}
+
+static gchar *
+expand_and_munge (const gchar *value)
+{
+ gchar *retval;
+
+ if (starts_with_dir (value, "${prefix}"))
+ retval = g_strconcat (PREFIX, value + strlen ("${prefix}"), NULL);
+ else if (starts_with_dir (value, "${exec_prefix}"))
+ retval = g_strconcat (EXEC_PREFIX, value + strlen ("${exec_prefix}"), NULL);
+ else
+ retval = g_strdup (value);
+
+ if (starts_with_dir (retval, EXEC_PREFIX))
+ {
+ gchar *exec_prefix = get_exec_prefix ('/');
+
+ retval = g_strconcat (exec_prefix, retval + strlen (EXEC_PREFIX), NULL);
+ g_free (exec_prefix);
+ }
+
+ if (starts_with_dir (retval, PREFIX))
+ {
+ gchar *runtime_prefix = get_runtime_prefix ('/');
+
+ retval = g_strconcat (runtime_prefix, retval + strlen (PREFIX), NULL);
+ g_free (runtime_prefix);
+ }
+
+ return retval;
+}
+
+static void
+find_out_env_flags (void)
+{
+ gchar *p;
+
+ if ((p = getenv ("CC")) != NULL && *p != '\0')
+ env_cc = p;
+ else if (msvc_syntax)
+ env_cc = "cl -MD";
+ else
+ env_cc = CC;
+
+ if (g_ascii_strncasecmp (env_cc, "cl", 2) == 0 &&
+ g_ascii_strncasecmp (env_cc, "clang", 5) != 0)
+ msvc_syntax = TRUE;
+
+ if ((p = getenv ("CFLAGS")) != NULL)
+ env_cflags = p;
+ else
+ env_cflags = "";
+
+ if ((p = getenv ("LDFLAGS")) != NULL)
+ env_ldflags = p;
+ else
+ env_ldflags = "";
+
+ if ((p = getenv ("LIBS")) != NULL && *p != '\0')
+ env_libs = p;
+ else
+ env_libs = "";
+}
+
+static void
+usage (int exit_status)
+{
+ g_print ("\
+Usage: gimptool-" GIMP_TOOL_VERSION " [OPTION]...\n\
+\n\
+General options:\n\
+ --help print this message\n\
+ --quiet, --silent don't echo build commands\n\
+ --version print the version of GIMP associated with this script\n\
+ -n, --just-print, --dry-run, --recon\n\
+ don't actually run any commands; just print them\n\
+Developer options:\n\
+ --cflags print the compiler flags that are necessary to\n\
+ compile a plug-in\n\
+ --libs print the linker flags that are necessary to link a\n\
+ plug-in\n\
+ --prefix=PREFIX use PREFIX instead of the installation prefix that\n\
+ GIMP was built when computing the output for --cflags\n\
+ and --libs\n\
+ --exec-prefix=PREFIX use PREFIX instead of the installation exec prefix\n\
+ that GIMP was built when computing the output for\n\
+ --cflags and --libs\n\
+ --msvc-syntax print flags in MSVC syntax\n\
+\n\
+Installation directory options:\n\
+ --prefix --exec-prefix --bindir --sbindir --libexecdir --datadir --sysconfdir\n\
+ --sharedstatedir --localstatedir --libdir --infodir --mandir --includedir\n\
+ --gimpplugindir --gimpdatadir\n\
+\n\
+The --cflags and --libs options can be appended with -noui to get appropriate\n\
+settings for plug-ins which do not use GTK+.\n\
+\n\
+User options:\n\
+ --build plug-in.c build a plug-in from a source file\n\
+ --install plug-in.c same as --build, but installs the built\n\
+ plug-in as well\n\
+ --install-bin plug-in install a compiled plug-in\n\
+ --install-script script.scm install a script-fu script\n\
+\n\
+ --uninstall-bin plug-in remove a plug-in again\n\
+ --uninstall-script plug-in remove a script-fu script\n\
+\n\
+The --install and --uninstall options have \"admin\" counterparts (with\n\
+prefix --install-admin instead of --install) that can be used instead to\n\
+install/uninstall a plug-in or script in the machine directory instead of a\n\
+user directory.\n\
+\n\
+For plug-ins which do not use GTK+, the --build and --install options can be\n\
+appended with -noui for appropriate settings. For plug-ins that use GTK+ but\n\
+not libgimpui, append -nogimpui.\n");
+ exit (exit_status);
+}
+
+static gchar *
+get_includedir (void)
+{
+ return pkg_config ("--variable=includedir gimp-" GIMP_PKGCONFIG_VERSION);
+}
+
+static void
+do_includedir (void)
+{
+ gchar *includedir = get_includedir ();
+
+ g_print ("%s\n", includedir);
+ g_free (includedir);
+}
+
+static gchar *
+get_cflags (void)
+{
+ return pkg_config ("--cflags gimpui-" GIMP_PKGCONFIG_VERSION);
+}
+
+static void
+do_cflags (void)
+{
+ gchar *cflags = get_cflags ();
+
+ g_print ("%s\n", cflags);
+ g_free (cflags);
+}
+
+static gchar *
+get_cflags_noui (void)
+{
+ return pkg_config ("--cflags gimp-" GIMP_PKGCONFIG_VERSION);
+}
+
+static void
+do_cflags_noui (void)
+{
+ gchar *cflags = get_cflags_noui ();
+
+ g_print ("%s\n", cflags);
+ g_free (cflags);
+}
+
+static gchar *
+get_cflags_nogimpui (void)
+{
+ return pkg_config ("--cflags gimp-" GIMP_PKGCONFIG_VERSION " gtk+-2.0");
+}
+
+static void
+do_cflags_nogimpui (void)
+{
+ gchar *cflags = get_cflags_nogimpui ();
+
+ g_print ("%s\n", cflags);
+ g_free (cflags);
+}
+
+static gchar *
+get_libs (void)
+{
+ return pkg_config ("--libs gimpui-" GIMP_PKGCONFIG_VERSION);
+}
+
+static void
+do_libs (void)
+{
+ gchar *libs = get_libs ();
+
+ g_print ("%s\n", libs);
+ g_free (libs);
+}
+
+static gchar *
+get_libs_noui (void)
+{
+ return pkg_config ("--libs gimp-" GIMP_PKGCONFIG_VERSION);
+}
+
+static void
+do_libs_noui (void)
+{
+ gchar *libs = get_libs_noui ();
+
+ g_print ("%s\n", libs);
+ g_free (libs);
+}
+
+static gchar *
+get_libs_nogimpui (void)
+{
+ return pkg_config ("--libs gimp-" GIMP_PKGCONFIG_VERSION " gtk+-2.0");
+}
+
+static void
+do_libs_nogimpui (void)
+{
+ gchar *libs = get_libs_nogimpui ();
+
+ g_print ("%s\n", libs);
+ g_free (libs);
+}
+
+static void
+maybe_run (gchar *cmd)
+{
+ if (!silent)
+ g_print ("%s\n", cmd);
+
+ /* system() declared with attribute warn_unused_result.
+ * Trick to get rid of the compilation warning without using the result.
+ */
+ if (dry_run || system (cmd))
+ ;
+}
+
+static void
+do_build_2 (const gchar *cflags,
+ const gchar *libs,
+ const gchar *install_dir,
+ const gchar *what)
+{
+ const gchar *lang_flag = "";
+ const gchar *output_flag;
+ const gchar *here_comes_linker_flags = "";
+ const gchar *windows_subsystem_flag = "";
+ gchar *cmd;
+ gchar *dest_dir;
+ gchar *dest_exe;
+ gchar *source = g_shell_quote (what);
+
+ gchar *tmp;
+ gchar *p, *q;
+
+ if (install_dir != NULL)
+ dest_dir = g_strconcat (install_dir, "/", NULL);
+ else
+ dest_dir = g_strdup ("");
+
+ dest_exe = g_strdup (what);
+
+ p = strrchr (dest_exe, '.');
+ if (p == NULL ||
+ !(strcmp (p, ".c") == 0 ||
+ strcmp (p, ".cc") == 0 ||
+ strcmp (p, ".cpp") == 0))
+ {
+ /* If the file doesn't have a "standard" C/C++ suffix and:
+ * 1) if the compiler is known as a C++ compiler, then treat the file as a
+ * C++ file if possible.
+ * It's known that G++ and Clang++ treat a file as a C file if they are
+ * run with the "-x c++" option.
+ * 2) if the compiler is known as a C compiler or a multiple-language
+ * compiler, then treat the file as a C file if possible.
+ * It's known that GCC and Clang treat a file as a C file if they are
+ * run with the "-x c" option.
+ * TODO We may want to further support compilation with a source file
+ * without a standard suffix in more compilers as far as possible.
+ */
+ if (strcmp (env_cc, "g++") == 0 ||
+ strncmp (env_cc, "g++-", sizeof ("g++-") - 1) == 0 ||
+ strcmp (env_cc, "clang++") == 0 ||
+ strncmp (env_cc, "clang++-", sizeof ("clang++-") - 1) == 0)
+ lang_flag = "-x c++ ";
+ else if (strcmp (env_cc, "gcc") == 0 ||
+ strncmp (env_cc, "gcc-", sizeof ("gcc-") - 1) == 0)
+ {
+ /* It's known GCC recognizes .CPP and .cxx, so bypass these suffixes */
+ if (p != NULL && strcmp (p, ".CPP") != 0 && strcmp (p, ".cxx") != 0)
+ lang_flag = "-x c ";
+ }
+ else if (strcmp (env_cc, "clang") == 0 ||
+ strncmp (env_cc, "clang-", sizeof ("clang-") - 1) == 0)
+ {
+ /* It's known Clang recognizes .CC, .CPP, .cxx and .CXX,
+ * so bypass these suffixes
+ */
+ if (p != NULL && strcmp (p, ".CC") != 0 && strcmp (p, ".CPP") != 0 &&
+ strcmp (p, ".cxx") != 0 && strcmp (p, ".CXX") != 0)
+ lang_flag = "-x c ";
+ }
+ else
+ {
+ g_printerr ("The source file (%s) doesn't have a \"standard\" C or C++ suffix, "
+ "and the tool failed to confirm the language of the file.\n"
+ "Please be explicit about the language of the file "
+ "by renaming it with one of the suffixes: .c .cc .cpp\n",
+ what);
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ if (p)
+ *p = '\0';
+ q = strrchr (dest_exe, G_DIR_SEPARATOR);
+#ifdef G_OS_WIN32
+ {
+ gchar *r = strrchr (dest_exe, '/');
+ if (r != NULL && (q == NULL || r > q))
+ q = r;
+ }
+#endif
+ if (q == NULL)
+ q = dest_exe;
+ else
+ q++;
+
+ if (install_dir)
+ {
+ tmp = dest_dir;
+ dest_dir = g_strconcat (dest_dir, q, G_DIR_SEPARATOR_S, NULL);
+ g_free (tmp);
+
+ g_mkdir_with_parents (dest_dir,
+ S_IRUSR | S_IXUSR | S_IWUSR |
+ S_IRGRP | S_IXGRP |
+ S_IROTH | S_IXOTH);
+ }
+
+ tmp = g_strconcat (dest_dir, q, NULL);
+ g_free (dest_dir);
+
+ dest_exe = g_shell_quote (tmp);
+ g_free (tmp);
+
+ if (msvc_syntax)
+ {
+ output_flag = "-Fe";
+ here_comes_linker_flags = " -link";
+ windows_subsystem_flag = " -subsystem:windows";
+ }
+ else
+ {
+ output_flag = "-o ";
+#ifdef G_OS_WIN32
+ windows_subsystem_flag = " -mwindows";
+#endif
+ }
+
+ cmd = g_strdup_printf ("%s %s%s %s %s%s %s%s %s%s %s %s",
+ env_cc,
+ lang_flag,
+ env_cflags,
+ cflags,
+ output_flag,
+ dest_exe,
+ source,
+ here_comes_linker_flags,
+ env_ldflags,
+ windows_subsystem_flag,
+ libs,
+ env_libs);
+
+ maybe_run (cmd);
+
+ g_free (dest_exe);
+ g_free (source);
+}
+
+static void
+do_build (const gchar *what)
+{
+ gchar *cflags = get_cflags ();
+ gchar *libs = get_libs ();
+
+ do_build_2 (cflags, libs, NULL, what);
+
+ g_free (cflags);
+ g_free (libs);
+}
+
+static void
+do_build_noui (const gchar *what)
+{
+ gchar *cflags = get_cflags_noui ();
+ gchar *libs = get_libs_noui ();
+
+ do_build_2 (cflags, libs, NULL, what);
+
+ g_free (cflags);
+ g_free (libs);
+}
+
+static void
+do_build_nogimpui (const gchar *what)
+{
+ do_build (what);
+}
+
+static gchar *
+get_user_plugin_dir (void)
+{
+ return g_build_filename (gimp_directory (),
+ "plug-ins",
+ NULL);
+}
+
+static gchar *
+get_plugin_dir (const gchar *base_dir,
+ const gchar *what)
+{
+ gchar *separator, *dot, *plugin_name, *plugin_dir;
+ gchar *tmp = g_strdup (what);
+
+ separator = strrchr (tmp, G_DIR_SEPARATOR);
+#ifdef G_OS_WIN32
+ {
+ gchar *alt_separator = strrchr (tmp, '/');
+
+ if (alt_separator != NULL &&
+ (separator == NULL || alt_separator > separator))
+ {
+ separator = alt_separator;
+ }
+ }
+#endif
+
+ dot = strrchr (tmp, '.');
+
+ if (separator)
+ plugin_name = separator + 1;
+ else
+ plugin_name = tmp;
+
+ if (dot)
+ *dot = '\0';
+
+ plugin_dir = g_strconcat (base_dir,
+ G_DIR_SEPARATOR_S,
+ plugin_name,
+ NULL);
+
+ g_free (tmp);
+
+ return plugin_dir;
+}
+
+static void
+do_install (const gchar *what)
+{
+ gchar *cflags = get_cflags ();
+ gchar *libs = get_libs ();
+ gchar *dir = get_user_plugin_dir ();
+
+ do_build_2 (cflags, libs, dir, what);
+
+ g_free (cflags);
+ g_free (libs);
+ g_free (dir);
+}
+
+static void
+do_install_noui (const gchar *what)
+{
+ gchar *cflags = get_cflags_noui ();
+ gchar *libs = get_libs_noui ();
+ gchar *dir = get_user_plugin_dir ();
+
+ do_build_2 (cflags, libs, dir, what);
+
+ g_free (cflags);
+ g_free (libs);
+ g_free (dir);
+}
+
+static void
+do_install_nogimpui (const gchar *what)
+{
+ do_install (what);
+}
+
+static gchar *
+get_sys_plugin_dir (gboolean forward_slashes)
+{
+ gchar *dir;
+
+#ifdef G_OS_WIN32
+ gchar *rprefix;
+
+ rprefix = get_runtime_prefix (forward_slashes ? '/' : G_DIR_SEPARATOR);
+
+ dir = g_build_path (forward_slashes ? "/" : G_DIR_SEPARATOR_S,
+ rprefix,
+ "lib", "gimp",
+ GIMP_PLUGIN_VERSION,
+ "plug-ins",
+ NULL);
+ g_free (rprefix);
+#else
+ dir = g_build_path (forward_slashes ? "/" : G_DIR_SEPARATOR_S,
+ LIBDIR,
+ "gimp",
+ GIMP_PLUGIN_VERSION,
+ "plug-ins",
+ NULL);
+#endif
+
+ return dir;
+}
+
+static void
+do_install_admin (const gchar *what)
+{
+ gchar *cflags = get_cflags ();
+ gchar *libs = get_libs ();
+ gchar *dir = get_sys_plugin_dir (TRUE);
+
+ do_build_2 (cflags, libs, dir, what);
+
+ g_free (cflags);
+ g_free (libs);
+ g_free (dir);
+}
+
+static void
+do_install_admin_noui (const gchar *what)
+{
+ gchar *cflags = get_cflags_noui ();
+ gchar *libs = get_libs_noui ();
+ gchar *dir = get_sys_plugin_dir (TRUE);
+
+ do_build_2 (cflags, libs, dir, what);
+
+ g_free (cflags);
+ g_free (libs);
+ g_free (dir);
+}
+
+static void
+do_install_admin_nogimpui (const gchar *what)
+{
+ gchar *cflags = get_cflags ();
+ gchar *libs = get_libs ();
+ gchar *dir = get_sys_plugin_dir (TRUE);
+
+ do_build_2 (cflags, libs, dir, what);
+
+ g_free (cflags);
+ g_free (libs);
+ g_free (dir);
+}
+
+static void
+do_install_bin_2 (const gchar *dir,
+ const gchar *what)
+{
+ gchar *cmd;
+ gchar *quoted_src;
+ gchar *quoted_dir;
+
+ gchar *dest_dir = g_strconcat (dir, G_DIR_SEPARATOR_S, NULL);
+
+ g_mkdir_with_parents (dest_dir,
+ S_IRUSR | S_IXUSR | S_IWUSR |
+ S_IRGRP | S_IXGRP |
+ S_IROTH | S_IXOTH);
+
+ quoted_src = g_shell_quote (what);
+ quoted_dir = g_shell_quote (dest_dir);
+ cmd = g_strconcat (COPY, " ", quoted_src, " ", quoted_dir, NULL);
+ maybe_run (cmd);
+
+ g_free (dest_dir);
+ g_free (cmd);
+ g_free (quoted_src);
+ g_free (quoted_dir);
+}
+
+static void
+do_install_bin (const gchar *what)
+{
+ gchar *dir = get_user_plugin_dir ();
+ gchar *plugin_dir = get_plugin_dir (dir, what);
+
+ do_install_bin_2 (plugin_dir, what);
+
+ g_free (plugin_dir);
+ g_free (dir);
+}
+
+static void
+do_install_admin_bin (const gchar *what)
+{
+ gchar *dir = get_sys_plugin_dir (FALSE);
+ gchar *plugin_dir = get_plugin_dir (dir, what);
+
+ do_install_bin_2 (dir, what);
+
+ g_free (plugin_dir);
+ g_free (dir);
+}
+
+static void
+do_uninstall (const gchar *dir)
+{
+ gchar *cmd;
+ gchar *quoted_src;
+
+ quoted_src = g_shell_quote (dir);
+
+ cmd = g_strconcat (REMOVE_DIR, " ", quoted_src, NULL);
+ maybe_run (cmd);
+
+ g_free (cmd);
+ g_free (quoted_src);
+}
+
+static void
+do_uninstall_script_2 (const gchar *dir,
+ const gchar *what)
+{
+ gchar *cmd;
+ gchar *quoted_src;
+ gchar *src;
+
+ src = g_strconcat (dir, G_DIR_SEPARATOR_S, what, NULL);
+ quoted_src = g_shell_quote (src);
+
+ cmd = g_strconcat (REMOVE, " ", quoted_src, NULL);
+ maybe_run (cmd);
+
+ g_free (cmd);
+ g_free (quoted_src);
+ g_free (src);
+}
+
+static gchar *
+maybe_append_exe (const gchar *what)
+{
+#ifdef G_OS_WIN32
+ gchar *p = strrchr (what, '.');
+
+ if (p == NULL || g_ascii_strcasecmp (p, ".exe") != 0)
+ return g_strconcat (what, ".exe", NULL);
+#endif
+
+ return g_strdup (what);
+}
+
+static void
+do_uninstall_bin (const gchar *what)
+{
+ gchar *dir = get_user_plugin_dir ();
+ gchar *exe = maybe_append_exe (what);
+ gchar *plugin_dir = get_plugin_dir (dir, what);
+
+ do_uninstall (plugin_dir);
+
+ g_free (plugin_dir);
+ g_free (dir);
+ g_free (exe);
+}
+
+static void
+do_uninstall_admin_bin (const gchar *what)
+{
+ gchar *dir = get_sys_plugin_dir (FALSE);
+ gchar *exe = maybe_append_exe (what);
+ gchar *plugin_dir = get_plugin_dir (dir, what);
+
+ do_uninstall (plugin_dir);
+
+ g_free (plugin_dir);
+ g_free (dir);
+ g_free (exe);
+}
+
+static gchar *
+get_user_script_dir (void)
+{
+ return g_build_filename (gimp_directory (),
+ "scripts",
+ NULL);
+}
+
+static void
+do_install_script (const gchar *what)
+{
+ gchar *dir = get_user_script_dir ();
+
+ do_install_bin_2 (dir, what);
+ g_free (dir);
+}
+
+static gchar *
+get_sys_script_dir (void)
+{
+ gchar *dir;
+ gchar *prefix = get_runtime_prefix (G_DIR_SEPARATOR);
+
+ dir = g_build_filename (prefix, "share", "gimp",
+ GIMP_PLUGIN_VERSION, "scripts",
+ NULL);
+ g_free (prefix);
+
+ return dir;
+}
+
+static void
+do_install_admin_script (const gchar *what)
+{
+ gchar *dir = get_sys_script_dir ();
+
+ do_install_bin_2 (dir, what);
+ g_free (dir);
+}
+
+static void
+do_uninstall_script (const gchar *what)
+{
+ gchar *dir = get_user_script_dir ();
+
+ do_uninstall_script_2 (dir, what);
+ g_free (dir);
+}
+
+static void
+do_uninstall_admin_script (const gchar *what)
+{
+ gchar *dir = get_sys_script_dir ();
+
+ do_uninstall_script_2 (dir, what);
+ g_free (dir);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ gint argi;
+ gint i;
+
+ if (argc == 1)
+ usage (EXIT_SUCCESS);
+
+ /* First scan for flags that affect our behaviour globally, but
+ * are still allowed late on the command line.
+ */
+ argi = 0;
+ while (++argi < argc)
+ {
+ if (strcmp (argv[argi], "-n") == 0 ||
+ strcmp (argv[argi], "--just-print") == 0 ||
+ strcmp (argv[argi], "--dry-run") == 0 ||
+ strcmp (argv[argi], "--recon") == 0)
+ {
+ dry_run = TRUE;
+ }
+ else if (strcmp (argv[argi], "--help") == 0)
+ {
+ usage (EXIT_SUCCESS);
+ }
+ else if (g_str_has_prefix (argv[argi], "--prefix="))
+ {
+ cli_prefix = argv[argi] + strlen ("--prefix=");
+ }
+ else if (g_str_has_prefix (argv[argi], "--exec-prefix="))
+ {
+ cli_exec_prefix = argv[argi] + strlen ("--exec_prefix=");
+ }
+ else if (strcmp (argv[argi], "--msvc-syntax") == 0)
+ {
+#ifdef G_OS_WIN32
+ msvc_syntax = TRUE;
+#else
+ g_printerr ("Ignoring --msvc-syntax\n");
+#endif
+ }
+ }
+
+ find_out_env_flags ();
+
+ /* Second pass, actually do something. */
+ argi = 0;
+ while (++argi < argc)
+ {
+ for (i = 0; i < G_N_ELEMENTS (dirs); i++)
+ {
+ gchar *test = g_strconcat ("--", dirs[i].option, NULL);
+
+ if (strcmp (argv[argi], test) == 0)
+ {
+ g_free (test);
+ break;
+ }
+ else
+ {
+ g_free (test);
+ }
+ }
+
+ if (i < G_N_ELEMENTS (dirs))
+ {
+ gchar *expanded = expand_and_munge (dirs[i].value);
+
+ g_print ("%s\n", expanded);
+ g_free (expanded);
+ }
+ else if (strcmp (argv[argi], "--quiet") == 0 ||
+ strcmp (argv[argi], "--silent") == 0)
+ {
+ silent = TRUE;
+ }
+ else if (strcmp (argv[argi], "--version") == 0)
+ {
+ g_print ("%d.%d.%d\n",
+ GIMP_MAJOR_VERSION, GIMP_MINOR_VERSION, GIMP_MICRO_VERSION);
+ exit (EXIT_SUCCESS);
+ }
+ else if (strcmp (argv[argi], "-n") == 0 ||
+ strcmp (argv[argi], "--just-print") == 0 ||
+ strcmp (argv[argi], "--dry-run") == 0 ||
+ strcmp (argv[argi], "--recon") == 0)
+ ; /* Already handled */
+ else if (strcmp (argv[argi], "--includedir") == 0)
+ do_includedir ();
+ else if (strcmp (argv[argi], "--cflags") == 0)
+ do_cflags ();
+ else if (strcmp (argv[argi], "--cflags-noui") == 0)
+ do_cflags_noui ();
+ else if (strcmp (argv[argi], "--cflags-nogimpui") == 0)
+ do_cflags_nogimpui ();
+ else if (strcmp (argv[argi], "--libs") == 0)
+ do_libs ();
+ else if (strcmp (argv[argi], "--libs-noui") == 0)
+ do_libs_noui ();
+ else if (strcmp (argv[argi], "--libs-nogimpui") == 0)
+ do_libs_nogimpui ();
+ else if (g_str_has_prefix (argv[argi], "--prefix="))
+ ;
+ else if (g_str_has_prefix (argv[argi], "--exec-prefix="))
+ ;
+ else if (strcmp (argv[argi], "--msvc-syntax") == 0)
+ ;
+ else if (strcmp (argv[argi], "--build") == 0)
+ do_build (argv[++argi]);
+ else if (strcmp (argv[argi], "--build-noui") == 0)
+ do_build_noui (argv[++argi]);
+ else if (strcmp (argv[argi], "--build-nogimpui") == 0)
+ do_build_nogimpui (argv[++argi]);
+ else if (strcmp (argv[argi], "--install") == 0)
+ do_install (argv[++argi]);
+ else if (strcmp (argv[argi], "--install-noui") == 0)
+ do_install_noui (argv[++argi]);
+ else if (strcmp (argv[argi], "--install-nogimpui") == 0)
+ do_install_nogimpui (argv[++argi]);
+ else if (strcmp (argv[argi], "--install-admin") == 0)
+ do_install_admin (argv[++argi]);
+ else if (strcmp (argv[argi], "--install-admin-noui") == 0)
+ do_install_admin_noui (argv[++argi]);
+ else if (strcmp (argv[argi], "--install-admin-nogimpui") == 0)
+ do_install_admin_nogimpui (argv[++argi]);
+ else if (strcmp (argv[argi], "--install-bin") == 0)
+ do_install_bin (argv[++argi]);
+ else if (strcmp (argv[argi], "--install-admin-bin") == 0)
+ do_install_admin_bin (argv[++argi]);
+ else if (strcmp (argv[argi], "--uninstall-bin") == 0)
+ do_uninstall_bin (argv[++argi]);
+ else if (strcmp (argv[argi], "--uninstall-admin-bin") == 0)
+ do_uninstall_admin_bin (argv[++argi]);
+ else if (strcmp (argv[argi], "--install-script") == 0)
+ do_install_script (argv[++argi]);
+ else if (strcmp (argv[argi], "--install-admin-script") == 0)
+ do_install_admin_script (argv[++argi]);
+ else if (strcmp (argv[argi], "--uninstall-script") == 0)
+ do_uninstall_script (argv[++argi]);
+ else if (strcmp (argv[argi], "--uninstall-admin-script") == 0)
+ do_uninstall_admin_script (argv[++argi]);
+ else
+ {
+ g_printerr ("Unrecognized switch %s\n", argv[argi]);
+ usage (EXIT_FAILURE);
+ }
+ }
+
+ exit (EXIT_SUCCESS);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */