/* AbiSource Application Framework * * Copyright (C) 2002 Francis James Franklin * * 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 2 * 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include "ut_spi.h" #include "xap_Module.h" #include "xap_Spider.h" XAP_Spider::XAP_Spider () : m_spies_max(0), m_spies_count(0), m_spies(0) { // } XAP_Spider::~XAP_Spider () { if (m_spies) { while (*m_spies) unregister_spi (*m_spies); free (m_spies); } } UT_uint32 XAP_Spider::register_spies () { if (m_spies_count == 0) return 0; UT_uint32 total = 0; UT_uint32 count; do { count = 0; for (UT_uint32 i = 0; i < m_spies_count; i++) if (!spi_registered (m_spies[i])) { UT_uint32 ret = register_spi (m_spies[i]); if (ret > 0) count++; else if (ret < 0) break; // registration failed & 'pending' list altered } total += count; } while (count); /* remove any unregistered plugins (cyclic dependencies?) from 'pending' list */ struct ABI_Foreign_SPI * bad_spi = 0; do { bad_spi = 0; for (UT_uint32 i = 0; i < m_spies_count; i++) if (!spi_registered (m_spies[i])) { bad_spi = m_spies[i]; break; } unregister_spi (bad_spi); } while (bad_spi); return total; } UT_sint32 XAP_Spider::register_spi (const char * name) { if ( name == 0) return 0; if (*name == 0) return 0; struct ABI_Foreign_SPI * spi = find_spi (name); return register_spi (spi); } UT_sint32 XAP_Spider::register_spi (struct ABI_Foreign_SPI * spi) { if (spi == 0) return 0; bool satisfied = true; if (char ** dependence = spi->dependencies) while (*dependence) { if (!spi_registered (*dependence)) { satisfied = false; break; } dependence++; } if (!satisfied) return 0; UT_SPI * spi_glass = UT_SPI::load (spi->plugin_register, spi->plugin_unregister, m_spies, spi->version); if (spi_glass == 0) { unregister_spi (spi); // remove plugin from 'pending' list return -1; } spi->spi = spi_glass->SPI (); spi->spi_data = reinterpret_cast(spi_glass); return 1; } bool XAP_Spider::spi_registered (const char * name) { if ( name == 0) return false; if (*name == 0) return false; if (strcmp (name, "AbiWord-"ABI_BUILD_VERSION) == 0) return true; struct ABI_Foreign_SPI * spi = find_spi (name); return spi_registered (spi); } bool XAP_Spider::spi_registered (struct ABI_Foreign_SPI * spi) { if (spi == 0) return false; return (spi->spi_data ? true : false); } void XAP_Spider::unregister_spi (const char * name) { if ( name == 0) return; if (*name == 0) return; struct ABI_Foreign_SPI * spi = find_spi (name); unregister_spi (spi); } void XAP_Spider::unregister_spi (struct ABI_Foreign_SPI * spi) { if (spi == 0) return; if (spi_registered (spi)) { struct ABI_Foreign_SPI * dependant = 0; do { dependant = 0; for (UT_uint32 i = 0; i < m_spies_count; i++) { if (char ** dependence = m_spies[i]->dependencies) while (*dependence) { if (strcmp (*dependence, spi->name) == 0) { dependant = m_spies[i]; break; } dependence++; } if (dependant) break; } if (dependant) unregister_spi (dependant); } while (dependant); UT_SPI * spi_glass = reinterpret_cast(spi->spi_data); delete spi_glass; spi->spi = 0; spi->spi_data = 0; } for (UT_uint32 i = 0; i < m_spies_count; i++) if (m_spies[i] == spi) { m_spies[i] = m_spies[--m_spies_count]; m_spies[m_spies_count] = 0; free (spi); break; } } struct ABI_Foreign_SPI * XAP_Spider::find_spi (const char * name) { struct ABI_Foreign_SPI * spi = 0; for (UT_uint32 i = 0; i < m_spies_count; i++) if (strcmp (m_spies[i]->name, name) == 0) { spi = m_spies[i]; break; } return spi; } UT_SPI * XAP_Spider::lookup_spi (const char * name) { if ( name == 0) return 0; if (*name == 0) return 0; struct ABI_Foreign_SPI * spi = find_spi (name); return reinterpret_cast(spi->spi_data); } const char * XAP_Spider::add_spi (XAP_Module * module) { ABI_SPI_Version fn_version = 0; if (!module->resolveSymbol ("abi_spi_version", reinterpret_cast(&fn_version))) return 0; if (fn_version == 0) return 0; ABI_SPI_Register fn_register = 0; if (!module->resolveSymbol ("abi_spi_register", reinterpret_cast(&fn_register))) return 0; if (fn_register == 0) return 0; ABI_SPI_Unregister fn_unregister = 0; if (!module->resolveSymbol ("abi_spi_unregister", reinterpret_cast(&fn_unregister))) return 0; if (fn_unregister == 0) return 0; char ** dependencies = 0; char * name = 0; int version = fn_version (ABI_SPI_VERSION, &name, &dependencies); if (version == ABI_SPI_ERROR) return 0; if ( name == 0) return 0; if (*name == 0) return 0; if (const char * const * dependency = dependencies) { bool version_conflict = false; while (*dependency) { if (strncmp (*dependency, "AbiWord-", 8) == 0) if (strcmp (*dependency, "AbiWord-"ABI_BUILD_VERSION) != 0) { version_conflict = true; break; } dependency++; } if (version_conflict) return 0; } if (find_spi (name)) return 0; if (!spies_grow ()) return 0; UT_uint32 bytes = sizeof (struct ABI_Foreign_SPI); if ((m_spies[m_spies_count] = static_cast(malloc (bytes))) == 0) return 0; m_spies[m_spies_count]->version = version; m_spies[m_spies_count]->dependencies = dependencies; m_spies[m_spies_count]->name = name; m_spies[m_spies_count]->plugin_version = fn_version; m_spies[m_spies_count]->plugin_register = fn_register; m_spies[m_spies_count]->plugin_unregister = fn_unregister; m_spies[m_spies_count]->spi = 0; m_spies[m_spies_count]->spi_data = 0; m_spies[++m_spies_count] = 0; return name; } bool XAP_Spider::spies_grow () { if (m_spies == 0) { m_spies = static_cast(malloc (8 * sizeof (struct ABI_Foreign_SPI *))); if (m_spies == 0) return false; m_spies_max = 8; m_spies[0] = 0; } if (m_spies_count + 1 == m_spies_max) { UT_uint32 bytes = (m_spies_max + 8) * sizeof (struct ABI_Foreign_SPI *); struct ABI_Foreign_SPI ** more = static_cast(realloc (m_spies, bytes)); if (more == 0) return false; m_spies = more; m_spies_max += 8; } return true; }