static gboolean loader_supports_file(PurplePlugin *loader, const char *filename) { GList *exts; for (exts = PURPLE_PLUGIN_LOADER_INFO(loader)->exts; exts != NULL; exts = exts->next) { if (has_file_extension(filename, (char *)exts->data)) { return TRUE; } } return FALSE; }
/** * \brief Process compiler options. * \param argc The number of input parameters. * \param argv The input parameter strings. * \return Indicates if processing was successful. * 0 = processing successful * 1 = processing not successful * * Processes the input options passed to the compiler * and fill the compiler options structure as appropriate. * * The following options are supported: * -h: print help * -p: print the IR to a file * -t: test modus, only success/failure log * -o: the output file name (different from 'input'.o) */ int process_options(int argc, char *argv[]) { int opt; int ret = 0; /* add a handler to resource manager to free resources * in the case of an error during option processing */ rm_register_handler(&resource_mgr, free_options, NULL); while ((opt = getopt(argc, argv, "hpto:")) != -1) { switch (opt) { case 'p': cc_options.print_ir = 1; break; case 't': /* fewer logs, for automated testing */ cc_options.print_only_errors = 1; break; case 'o': /* output file */ cc_options.output_file = strdup(optarg); if (cc_options.output_file == NULL) { fatal_os_error(OUT_OF_MEMORY, 1, __FILE__, __LINE__, ""); return 1; } break; case 'h': /* print help */ print_usage(argv[0]); rm_cleanup_resources(&resource_mgr); exit(EXIT_SUCCESS); default: /* '?' */ /* print usage */ fprintf(stderr, "ERROR: unknown parameter: %s\n", argv[optind]); print_usage(argv[0]); return 1; } } if (optind >= argc) { fprintf(stderr, "ERROR: missing input file\n"); print_usage(argv[0]); ret = 1; } else if (optind < argc - 1) { fprintf(stderr, "ERROR: too many input files\n"); print_usage(argv[0]); ret = 1; } else { cc_options.input_file = strdup(argv[optind]); if (cc_options.input_file == NULL) { fatal_os_error(OUT_OF_MEMORY, 1, __FILE__, __LINE__, ""); return 1; } char *filebase = get_file_basename(cc_options.input_file); ; if (filebase == NULL) { return 1; } if (!has_file_extension(cc_options.input_file, C_EXT)) { fprintf(stderr, "ERROR: no C file (.c) as input\n"); ret = 1; } else { /* The file name has a valid .c extension */ if (cc_options.output_file == NULL) { /* create output file name <input>.o */ cc_options.output_file = get_filename_with_ext(filebase, OUTPUT_EXT); if (cc_options.output_file == NULL) { ret = 1; } } if (cc_options.print_ir == 1) { /* create IR file name <input>.ir */ cc_options.ir_file = get_filename_with_ext(filebase, IR_EXT); if (cc_options.ir_file == NULL) { ret = 1; } } } free(filebase); } return ret; }
void purple_plugin_destroy(PurplePlugin *plugin) { #ifdef PURPLE_PLUGINS g_return_if_fail(plugin != NULL); if (purple_plugin_is_loaded(plugin)) purple_plugin_unload(plugin); plugins = g_list_remove(plugins, plugin); if (load_queue != NULL) load_queue = g_list_remove(load_queue, plugin); /* true, this may leak a little memory if there is a major version * mismatch, but it's a lot better than trying to free something * we shouldn't, and crashing while trying to load an old plugin */ if(plugin->info == NULL || plugin->info->magic != PURPLE_PLUGIN_MAGIC || plugin->info->major_version != PURPLE_MAJOR_VERSION) { if(plugin->handle) g_module_close(plugin->handle); g_free(plugin->path); g_free(plugin->error); PURPLE_DBUS_UNREGISTER_POINTER(plugin); g_free(plugin); return; } if (plugin->info != NULL) g_list_free(plugin->info->dependencies); if (plugin->native_plugin) { if (plugin->info != NULL && plugin->info->type == PURPLE_PLUGIN_LOADER) { PurplePluginLoaderInfo *loader_info; GList *exts, *l, *next_l; PurplePlugin *p2; loader_info = PURPLE_PLUGIN_LOADER_INFO(plugin); if (loader_info != NULL && loader_info->exts != NULL) { for (exts = PURPLE_PLUGIN_LOADER_INFO(plugin)->exts; exts != NULL; exts = exts->next) { for (l = purple_plugins_get_all(); l != NULL; l = next_l) { next_l = l->next; p2 = l->data; if (p2->path != NULL && has_file_extension(p2->path, exts->data)) { purple_plugin_destroy(p2); } } } g_list_free(loader_info->exts); loader_info->exts = NULL; } plugin_loaders = g_list_remove(plugin_loaders, plugin); } if (plugin->info != NULL && plugin->info->destroy != NULL) plugin->info->destroy(plugin); /* * I find it extremely useful to do this when using valgrind, as * it keeps all the plugins open, meaning that valgrind is able to * resolve symbol names in leak traces from plugins. */ if (!g_getenv("PURPLE_LEAKCHECK_HELP") && !RUNNING_ON_VALGRIND) { if (plugin->handle != NULL) g_module_close(plugin->handle); } } else { PurplePlugin *loader; PurplePluginLoaderInfo *loader_info; loader = find_loader_for_plugin(plugin); if (loader != NULL) { loader_info = PURPLE_PLUGIN_LOADER_INFO(loader); if (loader_info->destroy != NULL) loader_info->destroy(plugin); } } g_free(plugin->path); g_free(plugin->error); PURPLE_DBUS_UNREGISTER_POINTER(plugin); g_free(plugin); #endif /* !PURPLE_PLUGINS */ }
PurplePlugin * purple_plugin_probe(const char *filename) { #ifdef PURPLE_PLUGINS PurplePlugin *plugin = NULL; PurplePlugin *loader; gpointer unpunned; gchar *basename = NULL; gboolean (*purple_init_plugin)(PurplePlugin *); purple_debug_misc("plugins", "probing %s\n", filename); g_return_val_if_fail(filename != NULL, NULL); if (!g_file_test(filename, G_FILE_TEST_EXISTS)) return NULL; /* If this plugin has already been probed then exit */ basename = purple_plugin_get_basename(filename); plugin = purple_plugins_find_with_basename(basename); g_free(basename); if (plugin != NULL) { if (purple_strequal(filename, plugin->path)) return plugin; else if (!purple_plugin_is_unloadable(plugin)) { purple_debug_warning("plugins", "Not loading %s. " "Another plugin with the same name (%s) has already been loaded.\n", filename, plugin->path); return plugin; } else { /* The old plugin was a different file and it was unloadable. * There's no guarantee that this new file with the same name * will be loadable, but unless it fails in one of the silent * ways and the first one didn't, it's not any worse. The user * will still see a greyed-out plugin, which is what we want. */ purple_plugin_destroy(plugin); } } plugin = purple_plugin_new(has_file_extension(filename, G_MODULE_SUFFIX), filename); if (plugin->native_plugin) { const char *error; #ifdef _WIN32 /* Suppress error popups for failing to load plugins */ UINT old_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS); #endif /* * We pass G_MODULE_BIND_LOCAL here to prevent symbols from * plugins being added to the global name space. * * G_MODULE_BIND_LOCAL was added in glib 2.3.3. */ plugin->handle = g_module_open(filename, G_MODULE_BIND_LOCAL); if (plugin->handle == NULL) { const char *error = g_module_error(); if (error != NULL && purple_str_has_prefix(error, filename)) { error = error + strlen(filename); /* These are just so we don't crash. If we * got this far, they should always be true. */ if (*error == ':') error++; if (*error == ' ') error++; } if (error == NULL || !*error) { plugin->error = g_strdup(_("Unknown error")); purple_debug_error("plugins", "%s is not loadable: Unknown error\n", plugin->path); } else { plugin->error = g_strdup(error); purple_debug_error("plugins", "%s is not loadable: %s\n", plugin->path, plugin->error); } plugin->handle = g_module_open(filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); if (plugin->handle == NULL) { #ifdef _WIN32 /* Restore the original error mode */ SetErrorMode(old_error_mode); #endif purple_plugin_destroy(plugin); return NULL; } else { /* We were able to load the plugin with lazy symbol binding. * This means we're missing some symbol. Mark it as * unloadable and keep going so we get the info to display * to the user so they know to rebuild this plugin. */ plugin->unloadable = TRUE; } } if (!g_module_symbol(plugin->handle, "purple_init_plugin", &unpunned)) { purple_debug_error("plugins", "%s is not usable because the " "'purple_init_plugin' symbol could not be " "found. Does the plugin call the " "PURPLE_INIT_PLUGIN() macro?\n", plugin->path); g_module_close(plugin->handle); error = g_module_error(); if (error != NULL) purple_debug_error("plugins", "Error closing module %s: %s\n", plugin->path, error); plugin->handle = NULL; #ifdef _WIN32 /* Restore the original error mode */ SetErrorMode(old_error_mode); #endif purple_plugin_destroy(plugin); return NULL; } purple_init_plugin = unpunned; #ifdef _WIN32 /* Restore the original error mode */ SetErrorMode(old_error_mode); #endif } else { loader = find_loader_for_plugin(plugin); if (loader == NULL) { purple_plugin_destroy(plugin); return NULL; } purple_init_plugin = PURPLE_PLUGIN_LOADER_INFO(loader)->probe; } if (!purple_init_plugin(plugin) || plugin->info == NULL) { purple_plugin_destroy(plugin); return NULL; } else if (plugin->info->ui_requirement && !purple_strequal(plugin->info->ui_requirement, purple_core_get_ui())) { plugin->error = g_strdup_printf(_("You are using %s, but this plugin requires %s."), purple_core_get_ui(), plugin->info->ui_requirement); purple_debug_error("plugins", "%s is not loadable: The UI requirement is not met. (%s)\n", plugin->path, plugin->error); plugin->unloadable = TRUE; return plugin; } /* * Check to make sure a plugin has defined an id. * Not having this check caused purple_plugin_unload to * enter an infinite loop in certain situations by passing * purple_find_plugin_by_id a NULL value. -- ecoffey */ if (plugin->info->id == NULL || *plugin->info->id == '\0') { plugin->error = g_strdup(_("This plugin has not defined an ID.")); purple_debug_error("plugins", "%s is not loadable: info->id is not defined.\n", plugin->path); plugin->unloadable = TRUE; return plugin; } /* Really old plugins. */ if (plugin->info->magic != PURPLE_PLUGIN_MAGIC) { if (plugin->info->magic >= 2 && plugin->info->magic <= 4) { struct _PurplePluginInfo2 { unsigned int api_version; PurplePluginType type; char *ui_requirement; unsigned long flags; GList *dependencies; PurplePluginPriority priority; char *id; char *name; char *version; char *summary; char *description; char *author; char *homepage; gboolean (*load)(PurplePlugin *plugin); gboolean (*unload)(PurplePlugin *plugin); void (*destroy)(PurplePlugin *plugin); void *ui_info; void *extra_info; PurplePluginUiInfo *prefs_info; GList *(*actions)(PurplePlugin *plugin, gpointer context); } *info2 = (struct _PurplePluginInfo2 *)plugin->info; /* This leaks... but only for ancient plugins, so deal with it. */ plugin->info = g_new0(PurplePluginInfo, 1); /* We don't really need all these to display the plugin info, but * I'm copying them all for good measure. */ plugin->info->magic = info2->api_version; plugin->info->type = info2->type; plugin->info->ui_requirement = info2->ui_requirement; plugin->info->flags = info2->flags; plugin->info->dependencies = info2->dependencies; plugin->info->id = info2->id; plugin->info->name = info2->name; plugin->info->version = info2->version; plugin->info->summary = info2->summary; plugin->info->description = info2->description; plugin->info->author = info2->author; plugin->info->homepage = info2->homepage; plugin->info->load = info2->load; plugin->info->unload = info2->unload; plugin->info->destroy = info2->destroy; plugin->info->ui_info = info2->ui_info; plugin->info->extra_info = info2->extra_info; if (info2->api_version >= 3) plugin->info->prefs_info = info2->prefs_info; if (info2->api_version >= 4) plugin->info->actions = info2->actions; plugin->error = g_strdup_printf(_("Plugin magic mismatch %d (need %d)"), plugin->info->magic, PURPLE_PLUGIN_MAGIC); purple_debug_error("plugins", "%s is not loadable: Plugin magic mismatch %d (need %d)\n", plugin->path, plugin->info->magic, PURPLE_PLUGIN_MAGIC); plugin->unloadable = TRUE; return plugin; } purple_debug_error("plugins", "%s is not loadable: Plugin magic mismatch %d (need %d)\n", plugin->path, plugin->info->magic, PURPLE_PLUGIN_MAGIC); purple_plugin_destroy(plugin); return NULL; } if (plugin->info->major_version != PURPLE_MAJOR_VERSION || plugin->info->minor_version > PURPLE_MINOR_VERSION) { plugin->error = g_strdup_printf(_("ABI version mismatch %d.%d.x (need %d.%d.x)"), plugin->info->major_version, plugin->info->minor_version, PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION); purple_debug_error("plugins", "%s is not loadable: ABI version mismatch %d.%d.x (need %d.%d.x)\n", plugin->path, plugin->info->major_version, plugin->info->minor_version, PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION); plugin->unloadable = TRUE; return plugin; } if (plugin->info->type == PURPLE_PLUGIN_PROTOCOL) { /* If plugin is a PRPL, make sure it implements the required functions */ if ((PURPLE_PLUGIN_PROTOCOL_INFO(plugin)->list_icon == NULL) || (PURPLE_PLUGIN_PROTOCOL_INFO(plugin)->login == NULL) || (PURPLE_PLUGIN_PROTOCOL_INFO(plugin)->close == NULL)) { plugin->error = g_strdup(_("Plugin does not implement all required functions (list_icon, login and close)")); purple_debug_error("plugins", "%s is not loadable: %s\n", plugin->path, plugin->error); plugin->unloadable = TRUE; return plugin; } /* For debugging, let's warn about prpl prefs. */ if (plugin->info->prefs_info != NULL) { purple_debug_error("plugins", "%s has a prefs_info, but is a prpl. This is no longer supported.\n", plugin->path); } } return plugin; #else return NULL; #endif /* !PURPLE_PLUGINS */ }
void purple_plugins_probe(const char *ext) { #ifdef PURPLE_PLUGINS GDir *dir; const gchar *file; gchar *path; PurplePlugin *plugin; GList *cur; const char *search_path; if (!g_module_supported()) return; /* Probe plugins */ for (cur = search_paths; cur != NULL; cur = cur->next) { search_path = cur->data; dir = g_dir_open(search_path, 0, NULL); if (dir != NULL) { while ((file = g_dir_read_name(dir)) != NULL) { path = g_build_filename(search_path, file, NULL); if (ext == NULL || has_file_extension(file, ext)) purple_plugin_probe(path); g_free(path); } g_dir_close(dir); } } /* See if we have any plugins waiting to load */ while (load_queue != NULL) { plugin = (PurplePlugin *)load_queue->data; load_queue = g_list_remove(load_queue, plugin); if (plugin == NULL || plugin->info == NULL) continue; if (plugin->info->type == PURPLE_PLUGIN_LOADER) { /* We'll just load this right now. */ if (!purple_plugin_load(plugin)) { purple_plugin_destroy(plugin); continue; } plugin_loaders = g_list_append(plugin_loaders, plugin); for (cur = PURPLE_PLUGIN_LOADER_INFO(plugin)->exts; cur != NULL; cur = cur->next) { purple_plugins_probe(cur->data); } } else if (plugin->info->type == PURPLE_PLUGIN_PROTOCOL) { /* We'll just load this right now. */ if (!purple_plugin_load(plugin)) { purple_plugin_destroy(plugin); continue; } /* Make sure we don't load two PRPLs with the same name? */ if (purple_find_prpl(plugin->info->id)) { /* Nothing to see here--move along, move along */ purple_plugin_destroy(plugin); continue; } protocol_plugins = g_list_insert_sorted(protocol_plugins, plugin, (GCompareFunc)compare_prpl); } } #endif /* PURPLE_PLUGINS */ }