// DtdRegistry.cxx #include "dataset_util/DtdRegistry.h" #include using std::ostream; using std::endl; typedef DtdRegistry::Status Status; typedef DtdRegistry::Name Name; typedef DtdRegistry::NameList NameList; typedef std::map RegistryMap; //********************************************************************** // Local definitions. //********************************************************************** namespace { // Map of registries indexed by name. RegistryMap& regs() { static RegistryMap sregs; return sregs; } // Map of registries indexed by XML type. RegistryMap& regs_by_type() { static RegistryMap sregs; return sregs; } } // end unnamed namespace //********************************************************************** // Static member functions. //********************************************************************** // Return a registry. DtdRegistry& DtdRegistry::instance(Name rname) { Name name = rname; // Replace blanks with underscores. Name::size_type ipos = 0; while ( ipos != Name::npos ) { ipos = name.find(' '); if ( ipos != Name::npos ) name[ipos] = '_'; } // Create registry if it does not yet exist. if ( regs().find(name) == regs().end() ) { regs()[name] = new DtdRegistry(name); } return *regs()[name]; } //********************************************************************** // Display all known registries. ostream& DtdRegistry::display(std::ostream& str) { RegistryMap::size_type nreg = regs().size(); str << "DTD registry has " << nreg << " entr"; if ( nreg == 1 ) str << "y"; else str << "ies"; if ( nreg > 0 ) str << ":"; for ( RegistryMap::const_iterator ireg=regs().begin(); ireg!=regs().end(); ++ireg ) { str << "\n" << *ireg->second; } return str; } //********************************************************************** // Return whether a type has been registered in any registry. bool DtdRegistry::is_registered(Name type) { return regs_by_type().find(type) != regs_by_type().end(); } //********************************************************************** // Return the registry for the given type. DtdRegistry* DtdRegistry::system(Name type) { RegistryMap::iterator ireg = regs_by_type().find(type); if ( ireg == regs_by_type().end() ) return 0; return ireg->second; } //********************************************************************** // Non-static non-const member functions. //********************************************************************** // Constructor. DtdRegistry::DtdRegistry(Name name) : m_name(name) { } //********************************************************************** // Clear the DTD. void DtdRegistry::clear_dtd() const { m_dtd = Text(); } //********************************************************************** // Build the DTD. void DtdRegistry::build_dtd() const { m_dtd = Text(); m_dtd.append(""); m_dtd.append(""); for ( NameList::const_reverse_iterator itype=m_types.rbegin(); itype!=m_types.rend(); ++itype ) { Name name = *itype; const Dtd& dtd = m_dtds.find(name)->second; m_dtd.append(""); m_dtd.append(""); m_dtd.append(dtd); } BoolList::const_iterator icopy = m_copy.begin(); for ( NameList::const_iterator ireg=m_subs.begin(); ireg!=m_subs.end(); ++ireg ) { assert( icopy != m_copy.end() ); bool copy = *icopy++; Name name = *ireg; const DtdRegistry& subdtd = instance(name); if ( copy ) { m_dtd.append(subdtd.text()); } else { Name fname = subdtd.filename(); m_dtd.append(""); m_dtd.append(""); m_dtd.append("%include_" + name + ";"); } } } //********************************************************************** // Add a type. Status DtdRegistry::add_type(Name type, const Dtd& dtd) { // Check name is already used in this registry. if ( has_type(type) ) return 1; if ( is_registered(type) ) return 2; m_types.push_back(type); m_dtds[type] = dtd; regs_by_type()[type] = this; clear_dtd(); return 0; } //********************************************************************** // Add another DTD registry. Status DtdRegistry::add_dtd(Name rname, bool copy) { // Check name is already used in this registry. if ( has_dtd(rname) ) return 1; instance(rname); m_subs.push_back(rname); m_copy.push_back(copy); clear_dtd(); return 0; } //********************************************************************** // Non-static const member functions. //********************************************************************** // Return the name. Name DtdRegistry::name() const { return m_name; } //********************************************************************** // Return the file name. Name DtdRegistry::filename() const { return m_name + ".dtd"; } //********************************************************************** // Return the list of types in this DTD. const NameList& DtdRegistry::types() const { return m_types; } //********************************************************************** // Return if a type name is included in this registry. bool DtdRegistry::has_type(Name type) const { return m_dtds.find(type) != m_dtds.end(); } //********************************************************************** // Return the list of registries used by this registry. const NameList& DtdRegistry::dtds() const { return m_subs; } //********************************************************************** // Return if a DTD name is included in this DTD. bool DtdRegistry::has_dtd(Name name) const { return find(m_subs.begin(), m_subs.end(), name) != m_subs.end(); } //********************************************************************** // Return if a registry name is included in this registry. //********************************************************************** // Return the DTD text. const Text& DtdRegistry::text() const { if ( m_dtd.size() == 0 ) build_dtd(); return m_dtd; } //********************************************************************** // Write the file. Name DtdRegistry::write() const { text().write(filename()); return filename(); } //********************************************************************** // Free functions. //********************************************************************** // Output stream. ostream& operator<<(ostream& lhs, const DtdRegistry& rhs) { const NameList types = rhs.types(); lhs << "DTD for " << rhs.name() << " holds " << types.size() << " type"; if ( types.size() != 1 ) lhs << "s"; if ( types.size() > 0 ) lhs << ":"; for ( NameList::const_iterator itype=types.begin(); itype!=types.end(); ++itype ) { lhs << "\n " << *itype; } return lhs; } //**********************************************************************