+static void
+at_delete_names( AttributeType *at )
+{
+ char **names = at->sat_names;
+
+ while (*names) {
+ struct aindexrec tmpair, *air;
+
+ ber_str2bv( *names, 0, 0, &tmpair.air_name );
+ tmpair.air_at = at;
+ air = (struct aindexrec *)avl_delete( &attr_index,
+ (caddr_t)&tmpair, attr_index_cmp );
+ assert( air != NULL );
+ ldap_memfree( air );
+ names++;
+ }
+}
+
+/* Mark the attribute as deleted, remove from list, and remove all its
+ * names from the AVL tree. Leave the OID in the tree.
+ */
+void
+at_delete( AttributeType *at )
+{
+ at->sat_flags |= SLAP_AT_DELETED;
+
+ LDAP_STAILQ_REMOVE(&attr_list,at,slap_attribute_type,sat_next);
+
+ at_delete_names( at );
+}
+
+static void
+at_clean( AttributeType *a )
+{
+ if ( a->sat_equality ) {
+ MatchingRule *mr;
+
+ mr = mr_find( a->sat_equality->smr_oid );
+ assert( mr != NULL );
+ if ( mr != a->sat_equality ) {
+ ch_free( a->sat_equality );
+ a->sat_equality = NULL;
+ }
+ }
+
+ assert( a->sat_syntax != NULL );
+ if ( a->sat_syntax != NULL ) {
+ Syntax *syn;
+
+ syn = syn_find( a->sat_syntax->ssyn_oid );
+ assert( syn != NULL );
+ if ( syn != a->sat_syntax ) {
+ ch_free( a->sat_syntax );
+ a->sat_syntax = NULL;
+ }
+ }
+
+ if ( a->sat_oidmacro ) ldap_memfree( a->sat_oidmacro );
+ if ( a->sat_subtypes ) ldap_memfree( a->sat_subtypes );
+}
+
+static void
+at_destroy_one( void *v )
+{
+ struct aindexrec *air = v;
+ AttributeType *a = air->air_at;
+
+ at_clean( a );
+ ad_destroy(a->sat_ad);
+ ldap_pvt_thread_mutex_destroy(&a->sat_ad_mutex);
+ ldap_attributetype_free((LDAPAttributeType *)a);
+ ldap_memfree(air);
+}
+
+void
+at_destroy( void )
+{
+ AttributeType *a;
+
+ while( !LDAP_STAILQ_EMPTY(&attr_list) ) {
+ a = LDAP_STAILQ_FIRST(&attr_list);
+ LDAP_STAILQ_REMOVE_HEAD(&attr_list, sat_next);
+
+ at_delete_names( a );
+ }
+
+ avl_free(attr_index, at_destroy_one);
+
+ if ( slap_schema.si_at_undefined ) {
+ ad_destroy(slap_schema.si_at_undefined->sat_ad);
+ }
+
+ if ( slap_schema.si_at_proxied ) {
+ ad_destroy(slap_schema.si_at_proxied->sat_ad);
+ }
+}
+
+int
+at_start( AttributeType **at )
+{
+ assert( at != NULL );
+
+ *at = LDAP_STAILQ_FIRST(&attr_list);
+
+ return (*at != NULL);
+}
+
+int
+at_next( AttributeType **at )
+{
+ assert( at != NULL );
+
+#if 1 /* pedantic check */
+ {
+ AttributeType *tmp = NULL;
+
+ LDAP_STAILQ_FOREACH(tmp,&attr_list,sat_next) {
+ if ( tmp == *at ) {
+ break;
+ }
+ }
+
+ assert( tmp != NULL );
+ }
+#endif
+
+ *at = LDAP_STAILQ_NEXT(*at,sat_next);
+
+ return (*at != NULL);
+}
+
+/*
+ * check whether the two attributeTypes actually __are__ identical,
+ * or rather inconsistent
+ */
+static int
+at_check_dup(
+ AttributeType *sat,
+ AttributeType *new_sat )
+{
+ if ( new_sat->sat_oid != NULL ) {
+ if ( sat->sat_oid == NULL ) {
+ return SLAP_SCHERR_ATTR_INCONSISTENT;
+ }
+
+ if ( strcmp( sat->sat_oid, new_sat->sat_oid ) != 0 ) {
+ return SLAP_SCHERR_ATTR_INCONSISTENT;
+ }
+
+ } else {
+ if ( sat->sat_oid != NULL ) {
+ return SLAP_SCHERR_ATTR_INCONSISTENT;
+ }
+ }
+
+ if ( new_sat->sat_names ) {
+ int i;
+
+ if ( sat->sat_names == NULL ) {
+ return SLAP_SCHERR_ATTR_INCONSISTENT;
+ }
+
+ for ( i = 0; new_sat->sat_names[ i ]; i++ ) {
+ if ( sat->sat_names[ i ] == NULL ) {
+ return SLAP_SCHERR_ATTR_INCONSISTENT;
+ }
+
+ if ( strcasecmp( sat->sat_names[ i ],
+ new_sat->sat_names[ i ] ) != 0 )
+ {
+ return SLAP_SCHERR_ATTR_INCONSISTENT;
+ }
+ }
+ } else {
+ if ( sat->sat_names != NULL ) {
+ return SLAP_SCHERR_ATTR_INCONSISTENT;
+ }
+ }
+
+ return SLAP_SCHERR_ATTR_DUP;
+}
+
+static struct aindexrec *air_old;
+
+static int
+at_dup_error( void *left, void *right )
+{
+ air_old = left;
+ return -1;
+}
+