+ return LDAP_SUCCESS;
+}
+
+int
+an_find(
+ AttributeName *a,
+ struct berval *s
+)
+{
+ if( a == NULL ) return 0;
+
+ for ( ; a->an_name.bv_val; a++ ) {
+ if ( a->an_name.bv_len != s->bv_len) continue;
+ if ( strcasecmp( s->bv_val, a->an_name.bv_val ) == 0 ) {
+ return( 1 );
+ }
+ }
+
+ return( 0 );
+}
+
+/*
+ * Convert a delimited string into a list of AttributeNames;
+ * add on to an existing list if it was given. If the string
+ * is not a valid attribute name, if a '-' is prepended it is
+ * skipped and the remaining name is tried again; if a '+' is
+ * prepended, an objectclass name is searched instead.
+ *
+ * NOTE: currently, if a valid attribute name is not found,
+ * the same string is also checked as valid objectclass name;
+ * however, this behavior is deprecated.
+ */
+AttributeName *
+str2anlist( AttributeName *an, char *in, const char *brkstr )
+{
+ char *str;
+ char *s;
+ char *lasts;
+ int i, j;
+ const char *text;
+ AttributeName *anew;
+
+ /* find last element in list */
+ for (i = 0; an && an[i].an_name.bv_val; i++);
+
+ /* protect the input string from strtok */
+ str = ch_strdup( in );
+
+ /* Count words in string */
+ j=1;
+ for ( s = str; *s; s++ ) {
+ if ( strchr( brkstr, *s ) != NULL ) {
+ j++;
+ }
+ }
+
+ an = ch_realloc( an, ( i + j + 1 ) * sizeof( AttributeName ) );
+ anew = an + i;
+ for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
+ s != NULL;
+ s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
+ {
+ anew->an_desc = NULL;
+ anew->an_oc = NULL;
+ ber_str2bv(s, 0, 1, &anew->an_name);
+ slap_bv2ad(&anew->an_name, &anew->an_desc, &text);
+ if ( !anew->an_desc ) {
+ switch( anew->an_name.bv_val[0] ) {
+ case '-': {
+ struct berval adname;
+ adname.bv_len = anew->an_name.bv_len - 1;
+ adname.bv_val = &anew->an_name.bv_val[1];
+ slap_bv2ad(&adname, &anew->an_desc, &text);
+ if ( !anew->an_desc ) {
+ free( an );
+ /*
+ * overwrites input string
+ * on error!
+ */
+ strcpy( in, s );
+ return NULL;
+ }
+ } break;
+
+ case '+': {
+ struct berval ocname;
+ ocname.bv_len = anew->an_name.bv_len - 1;
+ ocname.bv_val = &anew->an_name.bv_val[1];
+ anew->an_oc = oc_bvfind( &ocname );
+ if ( !anew->an_oc ) {
+ free( an );
+ /*
+ * overwrites input string
+ * on error!
+ */
+ strcpy( in, s );
+ return NULL;
+ }
+ } break;
+
+ default:
+ /* old (deprecated) way */
+ anew->an_oc = oc_bvfind( &anew->an_name );
+ if ( !anew->an_oc ) {
+ free( an );
+ /* overwrites input string on error! */
+ strcpy( in, s );
+ return NULL;
+ }
+ }
+ }
+ anew++;
+ }
+
+ anew->an_name.bv_val = NULL;
+ free( str );
+ return( an );
+}
+
+
+/* Define an attribute option. */
+int
+ad_define_option( const char *name, const char *fname, int lineno )
+{
+ int i;
+ unsigned int optlen;
+
+ if ( options == &lang_option ) {
+ options = NULL;
+ option_count = 0;
+ }
+ if ( name == NULL )
+ return 0;
+
+ optlen = 0;
+ do {
+ if ( !DESC_CHAR( name[optlen] ) ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG( CONFIG, CRIT,
+ "%s: line %d: illegal option name \"%s\"\n",
+ fname, lineno, name );
+#else
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: illegal option name \"%s\"\n",
+ fname, lineno, name );
+#endif
+ return 1;
+ }
+ } while ( name[++optlen] );
+
+ options = ch_realloc( options,
+ (option_count+1) * sizeof(Attr_option) );
+
+ if ( strcasecmp( name, "binary" ) == 0
+ || ad_find_option_definition( name, optlen ) ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG( CONFIG, CRIT,
+ "%s: line %d: option \"%s\" is already defined\n",
+ fname, lineno, name );
+#else
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: option \"%s\" is already defined\n",
+ fname, lineno, name );
+#endif