ソースを参照

libdpkg: New command module

This should ease refactoring some of the duplicate code dealing with
command execution. It will also make the code clearer.
Guillem Jover 16 年 前
コミット
08c0dd2529
共有7 個のファイルを変更した383 個の追加0 個の削除を含む
  1. 1 0
      lib/dpkg/Makefile.am
  2. 184 0
      lib/dpkg/command.c
  3. 54 0
      lib/dpkg/command.h
  4. 1 0
      lib/dpkg/test/.gitignore
  5. 2 0
      lib/dpkg/test/Makefile.am
  6. 140 0
      lib/dpkg/test/t-command.c
  7. 1 0
      po/POTFILES.in

+ 1 - 0
lib/dpkg/Makefile.am

@@ -22,6 +22,7 @@ libdpkg_a_SOURCES = \
 	ar.c ar.h \
 	buffer.c buffer.h \
 	cleanup.c \
+	command.c command.h \
 	compress.c compress.h \
 	database.c \
 	dbmodify.c \

+ 184 - 0
lib/dpkg/command.c

@@ -0,0 +1,184 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * command.c - command execution support
+ *
+ * Copyright © 2010 Guillem Jover <guillem@debian.org>
+ *
+ * This 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 <compat.h>
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <dpkg/dpkg.h>
+#include <dpkg/i18n.h>
+#include <dpkg/command.h>
+
+/**
+ * Initialize a command structure.
+ *
+ * If name is NULL, then the last component of the filename path will be
+ * used to initialize the name member.
+ *
+ * @param cmd The command structure to initialize.
+ * @param filename The filename of the command to execute.
+ * @param name The description of the command to execute.
+ */
+void
+command_init(struct command *cmd, const char *filename, const char *name)
+{
+	cmd->filename = filename;
+	if (name == NULL) {
+		const char *progname = strrchr(filename, '/');
+
+		cmd->name = progname ? progname + 1 : filename;
+	} else
+		cmd->name = name;
+	cmd->argc = 0;
+	cmd->argv_size = 10;
+	cmd->argv = m_malloc(cmd->argv_size * sizeof(const char *));
+	cmd->argv[0] = NULL;
+}
+
+/**
+ * Destroy a command structure.
+ *
+ * Free the members managed by the command functions (i.e. the argv pointer
+ * array), and zero all members of a command structure.
+ *
+ * @param cmd The command structure to free.
+ */
+void
+command_destroy(struct command *cmd)
+{
+	cmd->filename = NULL;
+	cmd->name = NULL;
+	cmd->argc = 0;
+	cmd->argv_size = 0;
+	free(cmd->argv);
+	cmd->argv = NULL;
+}
+
+static void
+command_grow_argv(struct command *cmd, int need)
+{
+	/* Check if we already have enough room. */
+	if ((cmd->argv_size - cmd->argc) >= need)
+		return;
+
+	cmd->argv_size = (cmd->argv_size + need) * 2;
+	cmd->argv = m_realloc(cmd->argv, cmd->argv_size * sizeof(const char *));
+}
+
+/**
+ * Append an argument to the command's argv.
+ *
+ * @param cmd The command structure to act on.
+ * @param arg The argument to append to argv.
+ */
+void
+command_add_arg(struct command *cmd, const char *arg)
+{
+	command_grow_argv(cmd, 1);
+
+	cmd->argv[cmd->argc++] = arg;
+	cmd->argv[cmd->argc] = NULL;
+}
+
+/**
+ * Append an argument array to the command's argv.
+ *
+ * @param cmd The command structure to act on.
+ * @param argv The NULL terminated argument array to append to argv.
+ */
+void
+command_add_argl(struct command *cmd, const char **argv)
+{
+	int i, add_argc = 0;
+
+	while (argv[add_argc] != NULL)
+		add_argc++;
+
+	command_grow_argv(cmd, add_argc);
+
+	for (i = 0; i < add_argc; i++)
+		cmd->argv[cmd->argc++] = argv[i];
+
+	cmd->argv[cmd->argc] = NULL;
+}
+
+/**
+ * Append a va_list of argument to the command's argv.
+ *
+ * @param cmd The command structure to act on.
+ * @param al The NULL terminated va_list of argument array to append to argv.
+ */
+void
+command_add_argv(struct command *cmd, va_list al)
+{
+	va_list at;
+	int i, add_argc = 0;
+
+	va_copy(at, al);
+	while (va_arg(at, const char *) != NULL)
+		add_argc++;
+	va_end(at);
+
+	command_grow_argv(cmd, add_argc);
+
+	for (i = 0; i < add_argc; i++)
+		cmd->argv[cmd->argc++] = va_arg(al, const char *);
+
+	cmd->argv[cmd->argc] = NULL;
+}
+
+/**
+ * Append a variable list of argument to the command's argv.
+ *
+ * @param cmd The command structure to act on.
+ * @param ... The NULL terminated variable list of argument to append to argv.
+ */
+void
+command_add_args(struct command *cmd, ...)
+{
+	va_list al;
+
+	va_start(al, cmd);
+	command_add_argv(cmd, al);
+	va_end(al);
+}
+
+/**
+ * Execute the command specified.
+ *
+ * The command is executed searching the PATH if the filename does not
+ * contain any slashes, or using the full path if it's either a relative or
+ * absolute pathname. This functions does not return.
+ *
+ * @param cmd The command structure to act on.
+ */
+void
+command_exec(struct command *cmd)
+{
+	if (strchr(cmd->filename, '/'))
+		execv(cmd->filename, (char * const *)cmd->argv);
+	else
+		execvp(cmd->filename, (char * const *)cmd->argv);
+	ohshite(_("unable to execute %s (%s)"), cmd->name, cmd->filename);
+}
+

+ 54 - 0
lib/dpkg/command.h

@@ -0,0 +1,54 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * command.h - command execution support
+ *
+ * Copyright © 2010 Guillem Jover <guillem@debian.org>
+ *
+ * This 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 LIBDPKG_COMMAND_H
+#define LIBDPKG_COMMAND_H
+
+#include <dpkg/macros.h>
+
+DPKG_BEGIN_DECLS
+
+/**
+ * Describe a command to execute.
+ */
+struct command {
+	/** Descriptive name of the command, used when printing. */
+	const char *name;
+	/** Filename to execute; either a path or the progname. */
+	const char *filename;
+	int argc;
+	int argv_size;
+	const char **argv;
+};
+
+void command_init(struct command *cmd, const char *filename, const char *name);
+void command_destroy(struct command *cmd);
+
+void command_add_arg(struct command *cmd, const char *arg);
+void command_add_argl(struct command *cmd, const char **argv);
+void command_add_argv(struct command *cmd, va_list al);
+void command_add_args(struct command *cmd, ...) DPKG_ATTR_SENTINEL;
+
+void command_exec(struct command *cmd) DPKG_ATTR_NORET;
+
+DPKG_END_DECLS
+
+#endif /* LIBDPKG_COMMAND_H */
+

+ 1 - 0
lib/dpkg/test/.gitignore

@@ -1,5 +1,6 @@
 t-ar
 t-buffer
+t-command
 t-macros
 t-path
 t-pkginfo

+ 2 - 0
lib/dpkg/test/Makefile.am

@@ -13,6 +13,7 @@ check_PROGRAMS = \
 	t-string \
 	t-buffer \
 	t-path \
+	t-command \
 	t-varbuf \
 	t-ar \
 	t-version \
@@ -21,6 +22,7 @@ check_PROGRAMS = \
 CHECK_LDADD = ../libdpkg.a
 
 t_ar_LDADD = $(CHECK_LDADD)
+t_command_LDADD = $(CHECK_LDADD)
 t_macros_LDADD = $(CHECK_LDADD)
 t_path_LDADD = $(CHECK_LDADD)
 t_pkginfo_LDADD = $(CHECK_LDADD)

+ 140 - 0
lib/dpkg/test/t-command.c

@@ -0,0 +1,140 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * t-command.c - test command implementation
+ *
+ * Copyright © 2010 Guillem Jover <guillem@debian.org>
+ *
+ * This 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 <dpkg/test.h>
+#include <dpkg/command.h>
+
+static void
+test_command_init(void)
+{
+	struct command cmd;
+
+	command_init(&cmd, "/absolute/path/to/progname", NULL);
+	test_str(cmd.filename, ==, "/absolute/path/to/progname");
+	test_str(cmd.name, ==, "progname");
+	test_pass(cmd.argc == 0);
+	test_pass(cmd.argv[0] == NULL);
+
+	command_destroy(&cmd);
+	test_pass(cmd.filename == NULL);
+	test_pass(cmd.name == NULL);
+	test_pass(cmd.argc == 0);
+	test_pass(cmd.argv == NULL);
+
+	command_init(&cmd, "progname", NULL);
+	test_str(cmd.filename, ==, "progname");
+	test_str(cmd.name, ==, "progname");
+	test_pass(cmd.argc == 0);
+	test_pass(cmd.argv[0] == NULL);
+
+	command_destroy(&cmd);
+
+	command_init(&cmd, "progname", "description");
+	test_str(cmd.filename, ==, "progname");
+	test_str(cmd.name, ==, "description");
+	test_pass(cmd.argc == 0);
+	test_pass(cmd.argv[0] == NULL);
+
+	command_destroy(&cmd);
+}
+
+static void
+test_command_add_arg(void)
+{
+	struct command cmd;
+
+	command_init(&cmd, "test", NULL);
+
+	command_add_arg(&cmd, "arg 0");
+	test_pass(cmd.argc == 1);
+	test_str(cmd.argv[0], ==, "arg 0");
+	test_pass(cmd.argv[1] == NULL);
+
+	command_add_arg(&cmd, "arg 1");
+	test_pass(cmd.argc == 2);
+	test_str(cmd.argv[0], ==, "arg 0");
+	test_str(cmd.argv[1], ==, "arg 1");
+	test_pass(cmd.argv[2] == NULL);
+
+	command_add_arg(&cmd, "arg 2");
+	test_pass(cmd.argc == 3);
+	test_str(cmd.argv[0], ==, "arg 0");
+	test_str(cmd.argv[1], ==, "arg 1");
+	test_str(cmd.argv[2], ==, "arg 2");
+	test_pass(cmd.argv[3] == NULL);
+
+	command_destroy(&cmd);
+}
+
+static void
+test_command_add_argl(void)
+{
+	struct command cmd;
+	const char *args[] = {
+		"arg 1",
+		"arg 2",
+		"arg 3",
+		NULL,
+	};
+
+	command_init(&cmd, "test", NULL);
+
+	command_add_arg(&cmd, "arg 0");
+
+	command_add_argl(&cmd, args);
+	test_pass(cmd.argc == 4);
+	test_str(cmd.argv[0], ==, "arg 0");
+	test_str(cmd.argv[1], ==, "arg 1");
+	test_str(cmd.argv[2], ==, "arg 2");
+	test_str(cmd.argv[3], ==, "arg 3");
+	test_pass(cmd.argv[4] == NULL);
+
+	command_destroy(&cmd);
+}
+
+static void
+test_command_add_args(void)
+{
+	struct command cmd;
+
+	command_init(&cmd, "test", NULL);
+
+	command_add_arg(&cmd, "arg 0");
+
+	command_add_args(&cmd, "arg 1", "arg 2", "arg 3", NULL);
+	test_pass(cmd.argc == 4);
+	test_str(cmd.argv[0], ==, "arg 0");
+	test_str(cmd.argv[1], ==, "arg 1");
+	test_str(cmd.argv[2], ==, "arg 2");
+	test_str(cmd.argv[3], ==, "arg 3");
+	test_pass(cmd.argv[4] == NULL);
+
+	command_destroy(&cmd);
+}
+
+static void
+test(void)
+{
+	test_command_init();
+	test_command_add_arg();
+	test_command_add_argl();
+	test_command_add_args();
+}
+

+ 1 - 0
po/POTFILES.in

@@ -3,6 +3,7 @@
 lib/dpkg/ar.c
 lib/dpkg/buffer.c
 lib/dpkg/cleanup.c
+lib/dpkg/command.c
 lib/dpkg/compression.c
 lib/dpkg/database.c
 lib/dpkg/dbmodify.c