+
+//================================================================================
+/*!
+ * \brief Adds an object ID to some family of IDs with a common prefix
+ * \param [in] str - the object ID
+ * \return bool - \c false if \a str does not have the same prefix as \a this family
+ * (for internal usage)
+ */
+//================================================================================
+
+bool _pyStringFamily::Add( const char* str )
+{
+ if ( strncmp( str, _prefix.ToCString(), _prefix.Length() ) != 0 )
+ return false; // expected prefix is missing
+
+ str += _prefix.Length(); // skip _prefix
+
+ // try to add to some of child falimies
+ std::list< _pyStringFamily >::iterator itSub = _subFams.begin();
+ for ( ; itSub != _subFams.end(); ++itSub )
+ if ( itSub->Add( str ))
+ return true;
+
+ // no suitable family found - add str to _strings or create a new child family
+
+ // look for a proper place within sorted _strings
+ std::list< _AString >::iterator itStr = _strings.begin();
+ while ( itStr != _strings.end() && itStr->IsLess( str ))
+ ++itStr;
+ if ( itStr != _strings.end() && itStr->IsEqual( str ))
+ return true; // same ID already kept
+
+ const int minPrefixSize = 4;
+
+ // count "smaller" strings with the same prefix
+ int nbLess = 0;
+ std::list< _AString >::iterator itLess = itStr;
+ while ( itLess != _strings.begin() )
+ {
+ --itLess;
+ if ( strncmp( str, itLess->ToCString(), minPrefixSize ) == 0 )
+ ++nbLess;
+ else
+ {
+ ++itLess;
+ break;
+ }
+ }
+ // itLess points to the 1st string with same prefix
+
+ // count "greater" strings with the same prefix
+ int nbMore = 0;
+ std::list< _AString >::iterator itMore = itStr;
+ for ( ; itMore != _strings.end(); ++itMore )
+ if ( strncmp( str, itMore->ToCString(), minPrefixSize ) == 0 )
+ ++nbMore;
+ else
+ break;
+ // itMore points to the 1st string with greater prefix
+
+ if ( nbLess + nbMore > 1 ) // ------- ADD a NEW CHILD FAMILY -------------
+ {
+ int prefixSize = minPrefixSize;
+ _AString newPrefix ( str, prefixSize );
+
+ // look for a proper place within _subFams sorted by _prefix
+ for ( itSub = _subFams.begin(); itSub != _subFams.end(); ++itSub )
+ if ( !itSub->_prefix.IsLess( newPrefix ))
+ break;
+
+ // add the new _pyStringFamily
+ itSub = _subFams.insert( itSub, _pyStringFamily());
+ _pyStringFamily& newSubFam = *itSub;
+ newSubFam._prefix = newPrefix;
+
+ // pass this->_strings to newSubFam._strings
+ for ( itStr = itLess; nbLess > 0; --nbLess, ++itStr )
+ newSubFam._strings.push_back( itStr->ToCString() + prefixSize );
+ newSubFam._strings.push_back( str + prefixSize );
+ for ( ; nbMore > 0; --nbMore, ++itStr )
+ newSubFam._strings.push_back( itStr->ToCString() + prefixSize );
+
+ _strings.erase( itLess, itMore );
+ }
+ else // too few string to make a family for them
+ {
+ _strings.insert( itStr, str );
+ }
+ return true;
+}
+
+//================================================================================
+/*!
+ * \brief Finds an object ID in the command
+ * \param [in] longStr - the command string
+ * \param [out] subStr - the found object ID
+ * \return bool - \c true if the object ID found
+ */
+//================================================================================
+
+bool _pyStringFamily::IsInArgs( Handle( _pyCommand)& cmd, std::list<_AString>& subStr )
+{
+ const _AString& longStr = cmd->GetString();
+ const char* s = longStr.ToCString();
+
+ // look in _subFams
+ std::list< _pyStringFamily >::iterator itSub = _subFams.begin();
+ int nbFound = 0, pos, len, from, argBeg = cmd->GetArgBeginning();
+ if ( argBeg < 4 || argBeg > longStr.Length() )
+ return false;
+ for ( ; itSub != _subFams.end(); ++itSub )
+ {
+ from = argBeg;
+ while (( pos = longStr.Location( itSub->_prefix, from, longStr.Length() )))
+ if (( len = itSub->isIn( s + pos-1 + itSub->_prefix.Length() )) >= 0 )
+ {
+ subStr.push_back( _AString( s + pos-1, len + itSub->_prefix.Length() ));
+ from = pos + len + itSub->_prefix.Length();
+ nbFound++;
+ }
+ else
+ {
+ from += itSub->_prefix.Length();
+ }
+ }
+ // look among _strings
+ std::list< _AString >::iterator itStr = _strings.begin();
+ for ( ; itStr != _strings.end(); ++itStr )
+ if (( pos = longStr.Location( *itStr, argBeg, longStr.Length() )))
+ // check that object ID does not continue after len
+ if ( !cmd->IsIDChar( s[ pos + itStr->Length() - 1 ] ))
+ {
+ subStr.push_back( *itStr );
+ nbFound++;
+ }
+ return nbFound;
+}
+
+//================================================================================
+/*!
+ * \brief Return remainder length of the object ID after my _prefix
+ * \param [in] str - remainder of the command after my _prefix
+ * \return int - length of the object ID or -1 if not found
+ */
+//================================================================================
+
+int _pyStringFamily::isIn( const char* str )
+{
+ std::list< _pyStringFamily >::iterator itSub = _subFams.begin();
+ int len = -1;
+ for ( ; itSub != _subFams.end(); ++itSub )
+ {
+ int cmp = strncmp( str, itSub->_prefix.ToCString(), itSub->_prefix.Length() );
+ if ( cmp == 0 )
+ {
+ if (( len = itSub->isIn( str + itSub->_prefix.Length() )) >= 0 )
+ return itSub->_prefix.Length() + len;
+ }
+ else if ( cmp < 0 )
+ break;
+ }
+ if ( !_strings.empty() )
+ {
+ std::list< _AString >::iterator itStr = _strings.begin();
+ bool firstEmpty = itStr->IsEmpty();
+ if ( firstEmpty )
+ ++itStr, len = 0;
+ for ( ; itStr != _strings.end(); ++itStr )
+ {
+ int cmp = strncmp( str, itStr->ToCString(), itStr->Length() );
+ if ( cmp == 0 )
+ {
+ len = itStr->Length();
+ break;
+ }
+ else if ( cmp < 0 )
+ {
+ break;
+ }
+ }
+
+ // check that object ID does not continue after len
+ if ( len >= 0 && _pyCommand::IsIDChar( str[len] ))
+ len = -1;
+ }
+
+ return len;
+}
+
+//================================================================================
+/*!
+ * \brief DEBUG
+ */
+//================================================================================
+
+void _pyStringFamily::Print( int level )
+{
+ cout << string( level, ' ' ) << "prefix = '" << _prefix << "' : ";
+ std::list< _AString >::iterator itStr = _strings.begin();
+ for ( ; itStr != _strings.end(); ++itStr )
+ cout << *itStr << " | ";
+ cout << endl;
+ std::list< _pyStringFamily >::iterator itSub = _subFams.begin();
+ for ( ; itSub != _subFams.end(); ++itSub )
+ itSub->Print( level + 1 );
+ if ( level == 0 )
+ cout << string( 70, '-' ) << endl;
+}
+