1 /*-------------------------------------------------------------------------
2 * C-Pluff, a plug-in framework for C
3 * Copyright 2007 Johannes Lehtinen
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *-----------------------------------------------------------------------*/
39 /* -----------------------------------------------------------------------
41 * ---------------------------------------------------------------------*/
45 #define _(String) gettext(String)
46 #define gettext_noop(String) String
47 #define N_(String) gettext_noop(String)
49 #define _(String) (String)
50 #define N_(String) String
51 #define textdomain(Domain)
52 #define bindtextdomain(Package, Directory)
55 // GNU C attribute defines
56 #ifndef CP_GCC_NORETURN
57 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5)
58 #define CP_GCC_NORETURN __attribute__((noreturn))
60 #define CP_GCC_NORETURN
64 // Initializer for empty list
65 #define STR_LIST_INITIALIZER { NULL, NULL }
68 /* -----------------------------------------------------------------------
70 * ---------------------------------------------------------------------*/
72 /// A type for str_list_t structure
73 typedef struct str_list_t str_list_t;
75 /// A type for str_list_entry_t structure
76 typedef struct str_list_entry_t str_list_entry_t;
78 /// A string list container
81 /// The first entry or NULL if empty
82 str_list_entry_t *first;
84 /// The last entry or NULL if empty
85 str_list_entry_t *last;
89 /// A holder for a string list entry
90 struct str_list_entry_t {
96 str_list_entry_t *next;
100 /* -----------------------------------------------------------------------
102 * ---------------------------------------------------------------------*/
104 /// The level of verbosity
105 static int verbosity = 1;
108 /* -----------------------------------------------------------------------
110 * ---------------------------------------------------------------------*/
113 * Prints an error message and exits. In quiet mode the error message is
116 * @param msg the error message
118 CP_GCC_NORETURN static void error(const char *msg) {
119 if (verbosity >= 1) {
120 /* TRANSLATORS: A formatting string for loader error messages. */
121 fprintf(stderr, _("C-Pluff Loader: ERROR: %s\n"), msg);
127 * Formats and prints an error message and exits. In quiet mode the error
128 * message is not printed.
130 * @param msg the error message
132 CP_GCC_NORETURN static void errorf(const char *msg, ...) {
137 vsnprintf(buffer, sizeof(buffer), _(msg), va);
139 strcpy(buffer + sizeof(buffer)/sizeof(char) - 4, "...");
144 * Allocates memory using malloc and checks for failures.
146 * @param size the amount of memory to allocate
147 * @return the allocated memory (always non-NULL)
149 static void *chk_malloc(size_t size) {
150 void *ptr = malloc(size);
152 error(_("Memory allocation failed."));
159 * Appends a new string to a string list. Copies strings by pointers.
161 static void str_list_append(str_list_t *list, const char *str) {
162 str_list_entry_t *entry = chk_malloc(sizeof(str_list_entry_t));
165 if (list->last != NULL) {
166 list->last->next = entry;
168 if (list->first == NULL) {
175 * Removes all entries from a string list. Does not free contained strings.
177 static void str_list_clear(str_list_t *list) {
178 str_list_entry_t *entry = list->first;
179 while (entry != NULL) {
180 str_list_entry_t *n = entry->next;
189 * Prints the help text.
191 static void print_help(void) {
192 printf(_("C-Pluff Loader, version %s\n"), PACKAGE_VERSION);
194 fputs(_("usage: cpluff-loader <option>... [--] <arguments passed to plug-ins>\n"
196 " -h print this help text\n"
197 " -c DIR add plug-in collection in directory DIR\n"
198 " -p DIR add plug-in in directory DIR\n"
199 " -s PID start plug-in PID\n"
200 " -v be more verbose (repeat for increased verbosity)\n"
202 " -V print C-Pluff version number and exit\n"
206 static void logger(cp_log_severity_t severity, const char *msg, const char *apid, void *dummy) {
211 /* TRANSLATORS: A tag for debug level log entries. */
216 /* TRANSLATORS: A tag for info level log entries. */
221 /* TRANSLATORS: A tag for warning level log entries. */
222 level = _("WARNING");
226 /* TRANSLATORS: A tag for error level log entries. */
231 /* TRANSLATORS: A tag for unknown severity level. */
232 level = _("UNKNOWN");
236 if (verbosity >= minv) {
238 /* TRANSLATORS: A formatting string for log messages caused by plug-in activity. */
239 fprintf(stderr, _("C-Pluff: %s: [%s] %s\n"), level, apid, msg);
241 /* TRANSLATORS: A formatting string for log messages caused by loader activity. */
242 fprintf(stderr, _("C-Pluff: %s: [loader] %s\n"), level, msg);
247 /// The main function
248 int main(int argc, char *argv[]) {
250 str_list_t lst_plugin_collections = STR_LIST_INITIALIZER;
251 str_list_t lst_plugin_dirs = STR_LIST_INITIALIZER;
252 str_list_t lst_start = STR_LIST_INITIALIZER;
253 cp_context_t *context;
255 str_list_entry_t *entry;
259 setlocale(LC_ALL, "");
262 // Initialize the framework
263 if (cp_init() != CP_OK) {
264 error(_("The C-Pluff initialization failed."));
267 // Set gettext domain
273 while ((i = getopt(argc, argv, "hc:p:s:vqV")) != -1) {
276 // Display help and exit
281 // Add a plug-in collection
283 str_list_append(&lst_plugin_collections, optarg);
286 // Add a single plug-in
288 str_list_append(&lst_plugin_dirs, optarg);
291 // Add a plug-in to be started
293 str_list_append(&lst_start, optarg);
299 error(_("Quiet and verbose modes are mutually exclusive."));
307 error(_("Quiet and verbose modes are mutually exclusive."));
312 // Display release version and exit
314 fputs(cp_get_version(), stdout);
318 // Unrecognized option
320 error(_("Unrecognized option or argument. Try option -h for help."));
324 // Display startup information
325 if (verbosity >= 1) {
327 /* TRANSLATORS: This is a version string displayed on startup. */
328 fprintf(stderr, _("C-Pluff Loader, version %s\n"), PACKAGE_VERSION);
330 /* TRANSLATORS: This is a version string displayed on startup.
331 The first %s is version and the second %s is platform type. */
332 fprintf(stderr, _("C-Pluff Library, version %s for %s\n"),
333 cp_get_version(), cp_get_host_type());
337 if (lst_plugin_dirs.first == NULL && lst_plugin_collections.first == NULL) {
338 error(_("No plug-ins to load. Try option -h for help."));
341 // Create the context
342 if ((context = cp_create_context(NULL)) == NULL) {
343 error(_("Plug-in context creation failed."));
347 if (verbosity >= 1) {
348 cp_log_severity_t mv = CP_LOG_DEBUG;
360 cp_register_logger(context, logger, NULL, mv);
363 // Set context arguments
364 ctx_argv = chk_malloc((argc - optind + 2) * sizeof(char *));
366 for (i = optind; i < argc; i++) {
367 ctx_argv[i - optind + 1] = argv[i];
369 ctx_argv[argc - optind + 1] = NULL;
370 cp_set_context_args(context, ctx_argv);
372 // Load individual plug-ins
373 for (entry = lst_plugin_dirs.first; entry != NULL; entry = entry->next) {
374 cp_plugin_info_t *pi = cp_load_plugin_descriptor(context, entry->str, NULL);
376 errorf(_("Failed to load a plug-in from path %s."), entry->str);
378 if (cp_install_plugin(context, pi) != CP_OK) {
379 errorf(_("Failed to install plug-in %s."), pi->identifier);
381 cp_release_info(context, pi);
383 str_list_clear(&lst_plugin_dirs);
385 // Load plug-in collections
386 for (entry = lst_plugin_collections.first; entry != NULL; entry = entry->next) {
387 if (cp_register_pcollection(context, entry->str) != CP_OK) {
388 errorf(_("Failed to register a plug-in collection at path %s."), entry->str);
391 if (lst_plugin_collections.first != NULL
392 && cp_scan_plugins(context, 0) != CP_OK) {
393 error(_("Failed to load and install plug-ins from plug-in collections."));
395 str_list_clear(&lst_plugin_collections);
398 for (entry = lst_start.first; entry != NULL; entry = entry->next) {
399 if (cp_start_plugin(context, entry->str) != CP_OK) {
400 errorf(_("Failed to start plug-in %s."), entry->str);
403 str_list_clear(&lst_start);
406 cp_run_plugins(context);
411 // Release context argument data
414 // Return from the main program