aboutsummaryrefslogtreecommitdiff
path: root/lib/cpluff/loader/loader.c
diff options
context:
space:
mode:
authoralcoheca <alcoheca@svn>2010-03-26 13:35:35 +0000
committeralcoheca <alcoheca@svn>2010-03-26 13:35:35 +0000
commitb632a42d5cacdda7bb07a3fee995a4f0de1deba9 (patch)
treeb174ecd7ce4830785293fa6d18ab65d30c0cc375 /lib/cpluff/loader/loader.c
parent5ccef76d00e1dc22d6ae5d1c08172630f5972e58 (diff)
copied cpluff-0.1.3 from vendor branch
git-svn-id: https://xbmc.svn.sourceforge.net/svnroot/xbmc/trunk@28834 568bbfeb-2a22-0410-94d2-cc84cf5bfa90
Diffstat (limited to 'lib/cpluff/loader/loader.c')
-rw-r--r--lib/cpluff/loader/loader.c416
1 files changed, 416 insertions, 0 deletions
diff --git a/lib/cpluff/loader/loader.c b/lib/cpluff/loader/loader.c
new file mode 100644
index 0000000000..c2e1175970
--- /dev/null
+++ b/lib/cpluff/loader/loader.c
@@ -0,0 +1,416 @@
+/*-------------------------------------------------------------------------
+ * C-Pluff, a plug-in framework for C
+ * Copyright 2007 Johannes Lehtinen
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *-----------------------------------------------------------------------*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef HAVE_GETTEXT
+#include <libintl.h>
+#include <locale.h>
+#endif
+#include <cpluff.h>
+
+
+/* -----------------------------------------------------------------------
+ * Defines
+ * ---------------------------------------------------------------------*/
+
+// Gettext defines
+#ifdef HAVE_GETTEXT
+#define _(String) gettext(String)
+#define gettext_noop(String) String
+#define N_(String) gettext_noop(String)
+#else
+#define _(String) (String)
+#define N_(String) String
+#define textdomain(Domain)
+#define bindtextdomain(Package, Directory)
+#endif
+
+// GNU C attribute defines
+#ifndef CP_GCC_NORETURN
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5)
+#define CP_GCC_NORETURN __attribute__((noreturn))
+#else
+#define CP_GCC_NORETURN
+#endif
+#endif
+
+// Initializer for empty list
+#define STR_LIST_INITIALIZER { NULL, NULL }
+
+
+/* -----------------------------------------------------------------------
+ * Data types
+ * ---------------------------------------------------------------------*/
+
+/// A type for str_list_t structure
+typedef struct str_list_t str_list_t;
+
+/// A type for str_list_entry_t structure
+typedef struct str_list_entry_t str_list_entry_t;
+
+/// A string list container
+struct str_list_t {
+
+ /// The first entry or NULL if empty
+ str_list_entry_t *first;
+
+ /// The last entry or NULL if empty
+ str_list_entry_t *last;
+
+};
+
+/// A holder for a string list entry
+struct str_list_entry_t {
+
+ /// The string
+ const char *str;
+
+ /// Next entry
+ str_list_entry_t *next;
+};
+
+
+/* -----------------------------------------------------------------------
+ * Variables
+ * ---------------------------------------------------------------------*/
+
+/// The level of verbosity
+static int verbosity = 1;
+
+
+/* -----------------------------------------------------------------------
+ * Functions
+ * ---------------------------------------------------------------------*/
+
+/**
+ * Prints an error message and exits. In quiet mode the error message is
+ * not printed.
+ *
+ * @param msg the error message
+ */
+CP_GCC_NORETURN static void error(const char *msg) {
+ if (verbosity >= 1) {
+ /* TRANSLATORS: A formatting string for loader error messages. */
+ fprintf(stderr, _("C-Pluff Loader: ERROR: %s\n"), msg);
+ }
+ exit(1);
+}
+
+/**
+ * Formats and prints an error message and exits. In quiet mode the error
+ * message is not printed.
+ *
+ * @param msg the error message
+ */
+CP_GCC_NORETURN static void errorf(const char *msg, ...) {
+ char buffer[256];
+ va_list va;
+
+ va_start(va, msg);
+ vsnprintf(buffer, sizeof(buffer), _(msg), va);
+ va_end(va);
+ strcpy(buffer + sizeof(buffer)/sizeof(char) - 4, "...");
+ error(buffer);
+}
+
+/**
+ * Allocates memory using malloc and checks for failures.
+ *
+ * @param size the amount of memory to allocate
+ * @return the allocated memory (always non-NULL)
+ */
+static void *chk_malloc(size_t size) {
+ void *ptr = malloc(size);
+ if (ptr == NULL) {
+ error(_("Memory allocation failed."));
+ } else {
+ return ptr;
+ }
+}
+
+/**
+ * Appends a new string to a string list. Copies strings by pointers.
+ */
+static void str_list_append(str_list_t *list, const char *str) {
+ str_list_entry_t *entry = chk_malloc(sizeof(str_list_entry_t));
+ entry->str = str;
+ entry->next = NULL;
+ if (list->last != NULL) {
+ list->last->next = entry;
+ }
+ if (list->first == NULL) {
+ list->first = entry;
+ }
+ list->last = entry;
+}
+
+/**
+ * Removes all entries from a string list. Does not free contained strings.
+ */
+static void str_list_clear(str_list_t *list) {
+ str_list_entry_t *entry = list->first;
+ while (entry != NULL) {
+ str_list_entry_t *n = entry->next;
+ free(entry);
+ entry = n;
+ }
+ list->first = NULL;
+ list->last = NULL;
+}
+
+/**
+ * Prints the help text.
+ */
+static void print_help(void) {
+ printf(_("C-Pluff Loader, version %s\n"), PACKAGE_VERSION);
+ putchar('\n');
+ fputs(_("usage: cpluff-loader <option>... [--] <arguments passed to plug-ins>\n"
+ "options:\n"
+ " -h print this help text\n"
+ " -c DIR add plug-in collection in directory DIR\n"
+ " -p DIR add plug-in in directory DIR\n"
+ " -s PID start plug-in PID\n"
+ " -v be more verbose (repeat for increased verbosity)\n"
+ " -q be quiet\n"
+ " -V print C-Pluff version number and exit\n"
+ ), stdout);
+}
+
+static void logger(cp_log_severity_t severity, const char *msg, const char *apid, void *dummy) {
+ const char *level;
+ int minv;
+ switch (severity) {
+ case CP_LOG_DEBUG:
+ /* TRANSLATORS: A tag for debug level log entries. */
+ level = _("DEBUG");
+ minv = 4;
+ break;
+ case CP_LOG_INFO:
+ /* TRANSLATORS: A tag for info level log entries. */
+ level = _("INFO");
+ minv = 3;
+ break;
+ case CP_LOG_WARNING:
+ /* TRANSLATORS: A tag for warning level log entries. */
+ level = _("WARNING");
+ minv = 2;
+ break;
+ case CP_LOG_ERROR:
+ /* TRANSLATORS: A tag for error level log entries. */
+ level = _("ERROR");
+ minv = 1;
+ break;
+ default:
+ /* TRANSLATORS: A tag for unknown severity level. */
+ level = _("UNKNOWN");
+ minv = 1;
+ break;
+ }
+ if (verbosity >= minv) {
+ if (apid != NULL) {
+ /* TRANSLATORS: A formatting string for log messages caused by plug-in activity. */
+ fprintf(stderr, _("C-Pluff: %s: [%s] %s\n"), level, apid, msg);
+ } else {
+ /* TRANSLATORS: A formatting string for log messages caused by loader activity. */
+ fprintf(stderr, _("C-Pluff: %s: [loader] %s\n"), level, msg);
+ }
+ }
+}
+
+/// The main function
+int main(int argc, char *argv[]) {
+ int i;
+ str_list_t lst_plugin_collections = STR_LIST_INITIALIZER;
+ str_list_t lst_plugin_dirs = STR_LIST_INITIALIZER;
+ str_list_t lst_start = STR_LIST_INITIALIZER;
+ cp_context_t *context;
+ char **ctx_argv;
+ str_list_entry_t *entry;
+
+ // Set locale
+#ifdef HAVE_GETTEXT
+ setlocale(LC_ALL, "");
+#endif
+
+ // Initialize the framework
+ if (cp_init() != CP_OK) {
+ error(_("The C-Pluff initialization failed."));
+ }
+
+ // Set gettext domain
+#ifdef HAVE_GETTEXT
+ textdomain(PACKAGE);
+#endif
+
+ // Parse arguments
+ while ((i = getopt(argc, argv, "hc:p:s:vqV")) != -1) {
+ switch (i) {
+
+ // Display help and exit
+ case 'h':
+ print_help();
+ exit(0);
+
+ // Add a plug-in collection
+ case 'c':
+ str_list_append(&lst_plugin_collections, optarg);
+ break;
+
+ // Add a single plug-in
+ case 'p':
+ str_list_append(&lst_plugin_dirs, optarg);
+ break;
+
+ // Add a plug-in to be started
+ case 's':
+ str_list_append(&lst_start, optarg);
+ break;
+
+ // Be more verbose
+ case 'v':
+ if (verbosity < 1) {
+ error(_("Quiet and verbose modes are mutually exclusive."));
+ }
+ verbosity++;
+ break;
+
+ // Quiet mode
+ case 'q':
+ if (verbosity > 1) {
+ error(_("Quiet and verbose modes are mutually exclusive."));
+ }
+ verbosity--;
+ break;
+
+ // Display release version and exit
+ case 'V':
+ fputs(cp_get_version(), stdout);
+ putchar('\n');
+ exit(0);
+
+ // Unrecognized option
+ default:
+ error(_("Unrecognized option or argument. Try option -h for help."));
+ }
+ }
+
+ // Display startup information
+ if (verbosity >= 1) {
+
+ /* TRANSLATORS: This is a version string displayed on startup. */
+ fprintf(stderr, _("C-Pluff Loader, version %s\n"), PACKAGE_VERSION);
+
+ /* TRANSLATORS: This is a version string displayed on startup.
+ The first %s is version and the second %s is platform type. */
+ fprintf(stderr, _("C-Pluff Library, version %s for %s\n"),
+ cp_get_version(), cp_get_host_type());
+ }
+
+ // Check arguments
+ if (lst_plugin_dirs.first == NULL && lst_plugin_collections.first == NULL) {
+ error(_("No plug-ins to load. Try option -h for help."));
+ }
+
+ // Create the context
+ if ((context = cp_create_context(NULL)) == NULL) {
+ error(_("Plug-in context creation failed."));
+ }
+
+ // Register logger
+ if (verbosity >= 1) {
+ cp_log_severity_t mv = CP_LOG_DEBUG;
+ switch (verbosity) {
+ case 1:
+ mv = CP_LOG_ERROR;
+ break;
+ case 2:
+ mv = CP_LOG_WARNING;
+ break;
+ case 3:
+ mv = CP_LOG_INFO;
+ break;
+ }
+ cp_register_logger(context, logger, NULL, mv);
+ }
+
+ // Set context arguments
+ ctx_argv = chk_malloc((argc - optind + 2) * sizeof(char *));
+ ctx_argv[0] = "";
+ for (i = optind; i < argc; i++) {
+ ctx_argv[i - optind + 1] = argv[i];
+ }
+ ctx_argv[argc - optind + 1] = NULL;
+ cp_set_context_args(context, ctx_argv);
+
+ // Load individual plug-ins
+ for (entry = lst_plugin_dirs.first; entry != NULL; entry = entry->next) {
+ cp_plugin_info_t *pi = cp_load_plugin_descriptor(context, entry->str, NULL);
+ if (pi == NULL) {
+ errorf(_("Failed to load a plug-in from path %s."), entry->str);
+ }
+ if (cp_install_plugin(context, pi) != CP_OK) {
+ errorf(_("Failed to install plug-in %s."), pi->identifier);
+ }
+ cp_release_info(context, pi);
+ }
+ str_list_clear(&lst_plugin_dirs);
+
+ // Load plug-in collections
+ for (entry = lst_plugin_collections.first; entry != NULL; entry = entry->next) {
+ if (cp_register_pcollection(context, entry->str) != CP_OK) {
+ errorf(_("Failed to register a plug-in collection at path %s."), entry->str);
+ }
+ }
+ if (lst_plugin_collections.first != NULL
+ && cp_scan_plugins(context, 0) != CP_OK) {
+ error(_("Failed to load and install plug-ins from plug-in collections."));
+ }
+ str_list_clear(&lst_plugin_collections);
+
+ // Start plug-ins
+ for (entry = lst_start.first; entry != NULL; entry = entry->next) {
+ if (cp_start_plugin(context, entry->str) != CP_OK) {
+ errorf(_("Failed to start plug-in %s."), entry->str);
+ }
+ }
+ str_list_clear(&lst_start);
+
+ // Run plug-ins
+ cp_run_plugins(context);
+
+ // Destroy framework
+ cp_destroy();
+
+ // Release context argument data
+ free(ctx_argv);
+
+ // Return from the main program
+ return 0;
+}