]> git.sur5r.net Git - openldap/blob - servers/slapd/sets.c
Add index_intlen keyword for ordered indexing of integers
[openldap] / servers / slapd / sets.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2000-2007 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in the file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15
16 #include "portable.h"
17
18 #include <stdio.h>
19 #include <ac/string.h>
20
21 #include "slap.h"
22 #include "sets.h"
23
24 static BerVarray set_chase( SLAP_SET_GATHER gatherer,
25         SetCookie *cookie, BerVarray set, AttributeDescription *desc, int closure );
26
27 /* Count the array members */
28 static long
29 slap_set_size( BerVarray set )
30 {
31         long    i = 0;
32
33         if ( set != NULL ) {
34                 while ( !BER_BVISNULL( &set[ i ] ) ) {
35                         i++;
36                 }
37         }
38
39         return i;
40 }
41
42 /* Return 0 if there is at least one array member, non-zero otherwise */
43 static int
44 slap_set_isempty( BerVarray set )
45 {
46         if ( set == NULL ) {
47                 return 1;
48         }
49
50         if ( !BER_BVISNULL( &set[ 0 ] ) ) {
51                 return 0;
52         }
53
54         return 1;
55 }
56
57 /* Dispose of the contents of the array and the array itself according
58  * to the flags value.  If SLAP_SET_REFVAL, don't dispose of values;
59  * if SLAP_SET_REFARR, don't dispose of the array itself.  In case of
60  * binary operators, there are LEFT flags and RIGHT flags, referring to
61  * the first and the second operator arguments, respectively.  In this
62  * case, flags must be transformed using macros SLAP_SET_LREF2REF() and
63  * SLAP_SET_RREF2REF() before calling this function.
64  */
65 static void
66 slap_set_dispose( SetCookie *cp, BerVarray set, unsigned flags )
67 {
68         if ( flags & SLAP_SET_REFVAL ) {
69                 if ( ! ( flags & SLAP_SET_REFARR ) ) {
70                         cp->set_op->o_tmpfree( set, cp->set_op->o_tmpmemctx );
71                 }
72
73         } else {
74                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
75         }
76 }
77
78 /* Duplicate a set.  If SLAP_SET_REFARR, is not set, the original array
79  * with the original values is returned, otherwise the array is duplicated;
80  * if SLAP_SET_REFVAL is set, also the values are duplicated.
81  */
82 static BerVarray
83 set_dup( SetCookie *cp, BerVarray set, unsigned flags )
84 {
85         BerVarray       newset = NULL;
86
87         if ( set == NULL ) {
88                 return NULL;
89         }
90
91         if ( flags & SLAP_SET_REFARR ) {
92                 int     i;
93
94                 for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ )
95                         ;
96                 newset = cp->set_op->o_tmpcalloc( i + 1,
97                                 sizeof( struct berval ), 
98                                 cp->set_op->o_tmpmemctx );
99                 if ( newset == NULL ) {
100                         return NULL;
101                 }
102
103                 if ( flags & SLAP_SET_REFVAL ) {
104                         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
105                                 ber_dupbv_x( &newset[ i ], &set[ i ],
106                                                 cp->set_op->o_tmpmemctx );
107                         }
108
109                 } else {
110                         AC_MEMCPY( newset, set, ( i + 1 ) * sizeof( struct berval ) );
111                 }
112                 
113         } else {
114                 newset = set;
115         }
116
117         return newset;
118 }
119
120 /* Join two sets according to operator op and flags op_flags.
121  * op can be:
122  *      '|' (or):       the union between the two sets is returned,
123  *                      eliminating diplicates
124  *      '&' (and):      the intersection between the two sets
125  *                      is returned
126  *      '+' (add):      the inner product of the two sets is returned,
127  *                      namely a set containing the concatenation of
128  *                      all combinations of the two sets members,
129  *                      except for duplicates.
130  * The two sets are disposed of according to the flags as described
131  * for slap_set_dispose().
132  */
133 BerVarray
134 slap_set_join(
135         SetCookie       *cp,
136         BerVarray       lset,
137         unsigned        op_flags,
138         BerVarray       rset )
139 {
140         BerVarray       set;
141         long            i, j, last, rlast;
142         unsigned        op = ( op_flags & SLAP_SET_OPMASK );
143
144         set = NULL;
145         switch ( op ) {
146         case '|':       /* union */
147                 if ( lset == NULL || BER_BVISNULL( &lset[ 0 ] ) ) {
148                         if ( rset == NULL ) {
149                                 if ( lset == NULL ) {
150                                         set = cp->set_op->o_tmpcalloc( 1,
151                                                         sizeof( struct berval ),
152                                                         cp->set_op->o_tmpmemctx );
153                                         BER_BVZERO( &set[ 0 ] );
154                                         return set;
155                                 }
156                                 return set_dup( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
157                         }
158                         slap_set_dispose( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
159                         return set_dup( cp, rset, SLAP_SET_RREF2REF( op_flags ) );
160                 }
161                 if ( rset == NULL || BER_BVISNULL( &rset[ 0 ] ) ) {
162                         slap_set_dispose( cp, rset, SLAP_SET_RREF2REF( op_flags ) );
163                         return set_dup( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
164                 }
165
166                 /* worst scenario: no duplicates */
167                 rlast = slap_set_size( rset );
168                 i = slap_set_size( lset ) + rlast + 1;
169                 set = cp->set_op->o_tmpcalloc( i, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
170                 if ( set != NULL ) {
171                         /* set_chase() depends on this routine to
172                          * keep the first elements of the result
173                          * set the same (and in the same order)
174                          * as the left-set.
175                          */
176                         for ( i = 0; !BER_BVISNULL( &lset[ i ] ); i++ ) {
177                                 if ( op_flags & SLAP_SET_LREFVAL ) {
178                                         ber_dupbv_x( &set[ i ], &lset[ i ], cp->set_op->o_tmpmemctx );
179
180                                 } else {
181                                         set[ i ] = lset[ i ];
182                                 }
183                         }
184
185                         /* pointers to values have been used in set - don't free twice */
186                         op_flags |= SLAP_SET_LREFVAL;
187
188                         last = i;
189
190                         for ( i = 0; !BER_BVISNULL( &rset[ i ] ); i++ ) {
191                                 int     exists = 0;
192
193                                 for ( j = 0; !BER_BVISNULL( &set[ j ] ); j++ ) {
194                                         if ( bvmatch( &rset[ i ], &set[ j ] ) )
195                                         {
196                                                 if ( !( op_flags & SLAP_SET_RREFVAL ) ) {
197                                                         cp->set_op->o_tmpfree( rset[ i ].bv_val, cp->set_op->o_tmpmemctx );
198                                                         rset[ i ] = rset[ --rlast ];
199                                                         BER_BVZERO( &rset[ rlast ] );
200                                                 }
201                                                 exists = 1;
202                                                 break;
203                                         }
204                                 }
205
206                                 if ( !exists ) {
207                                         if ( op_flags & SLAP_SET_RREFVAL ) {
208                                                 ber_dupbv_x( &set[ last ], &rset[ i ], cp->set_op->o_tmpmemctx );
209
210                                         } else {
211                                                 set[ last ] = rset[ i ];
212                                         }
213                                         last++;
214                                 }
215                         }
216
217                         /* pointers to values have been used in set - don't free twice */
218                         op_flags |= SLAP_SET_RREFVAL;
219
220                         BER_BVZERO( &set[ last ] );
221                 }
222                 break;
223
224         case '&':       /* intersection */
225                 if ( lset == NULL || BER_BVISNULL( &lset[ 0 ] )
226                         || rset == NULL || BER_BVISNULL( &rset[ 0 ] ) )
227                 {
228                         set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
229                                         cp->set_op->o_tmpmemctx );
230                         BER_BVZERO( &set[ 0 ] );
231                         break;
232
233                 } else {
234                         long llen, rlen;
235                         BerVarray sset;
236
237                         llen = slap_set_size( lset );
238                         rlen = slap_set_size( rset );
239
240                         /* dup the shortest */
241                         if ( llen < rlen ) {
242                                 last = llen;
243                                 set = set_dup( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
244                                 lset = NULL;
245                                 sset = rset;
246
247                         } else {
248                                 last = rlen;
249                                 set = set_dup( cp, rset, SLAP_SET_RREF2REF( op_flags ) );
250                                 rset = NULL;
251                                 sset = lset;
252                         }
253
254                         if ( set == NULL ) {
255                                 break;
256                         }
257
258                         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
259                                 for ( j = 0; !BER_BVISNULL( &sset[ j ] ); j++ ) {
260                                         if ( bvmatch( &set[ i ], &sset[ j ] ) ) {
261                                                 break;
262                                         }
263                                 }
264
265                                 if ( BER_BVISNULL( &sset[ j ] ) ) {
266                                         cp->set_op->o_tmpfree( set[ i ].bv_val, cp->set_op->o_tmpmemctx );
267                                         set[ i ] = set[ --last ];
268                                         BER_BVZERO( &set[ last ] );
269                                         i--;
270                                 }
271                         }
272                 }
273                 break;
274
275         case '+':       /* string concatenation */
276                 i = slap_set_size( rset );
277                 j = slap_set_size( lset );
278
279                 /* handle empty set cases */
280                 if ( i == 0 ) {
281                         if ( j == 0 ) {
282                                 set = cp->set_op->o_tmpcalloc( i * j + 1, sizeof( struct berval ),
283                                                 cp->set_op->o_tmpmemctx );
284                                 if ( set == NULL ) {
285                                         break;
286                                 }
287                                 BER_BVZERO( &set[ 0 ] );
288                                 break;
289
290                         } else {
291                                 set = set_dup( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
292                                 lset = NULL;
293                                 break;
294                         }
295
296                 } else if ( j == 0 ) {
297                         set = set_dup( cp, rset, SLAP_SET_RREF2REF( op_flags ) );
298                         rset = NULL;
299                         break;
300                 }
301
302                 set = cp->set_op->o_tmpcalloc( i * j + 1, sizeof( struct berval ),
303                                 cp->set_op->o_tmpmemctx );
304                 if ( set == NULL ) {
305                         break;
306                 }
307
308                 for ( last = 0, i = 0; !BER_BVISNULL( &lset[ i ] ); i++ ) {
309                         for ( j = 0; !BER_BVISNULL( &rset[ j ] ); j++ ) {
310                                 struct berval   bv;
311                                 long            k;
312
313                                 /* don't concatenate with the empty string */
314                                 if ( BER_BVISEMPTY( &lset[ i ] ) ) {
315                                         ber_dupbv_x( &bv, &rset[ j ], cp->set_op->o_tmpmemctx );
316                                         if ( bv.bv_val == NULL ) {
317                                                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
318                                                 set = NULL;
319                                                 goto done;
320                                         }
321
322                                 } else if ( BER_BVISEMPTY( &rset[ j ] ) ) {
323                                         ber_dupbv_x( &bv, &lset[ i ], cp->set_op->o_tmpmemctx );
324                                         if ( bv.bv_val == NULL ) {
325                                                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
326                                                 set = NULL;
327                                                 goto done;
328                                         }
329
330                                 } else {
331                                         bv.bv_len = lset[ i ].bv_len + rset[ j ].bv_len;
332                                         bv.bv_val = cp->set_op->o_tmpalloc( bv.bv_len + 1,
333                                                         cp->set_op->o_tmpmemctx );
334                                         if ( bv.bv_val == NULL ) {
335                                                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
336                                                 set = NULL;
337                                                 goto done;
338                                         }
339                                         AC_MEMCPY( bv.bv_val, lset[ i ].bv_val, lset[ i ].bv_len );
340                                         AC_MEMCPY( &bv.bv_val[ lset[ i ].bv_len ], rset[ j ].bv_val, rset[ j ].bv_len );
341                                         bv.bv_val[ bv.bv_len ] = '\0';
342                                 }
343
344                                 for ( k = 0; k < last; k++ ) {
345                                         if ( bvmatch( &set[ k ], &bv ) ) {
346                                                 cp->set_op->o_tmpfree( bv.bv_val, cp->set_op->o_tmpmemctx );
347                                                 break;
348                                         }
349                                 }
350
351                                 if ( k == last ) {
352                                         set[ last++ ] = bv;
353                                 }
354                         }
355                 }
356                 BER_BVZERO( &set[ last ] );
357                 break;
358
359         default:
360                 break;
361         }
362
363 done:;
364         if ( lset ) slap_set_dispose( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
365         if ( rset ) slap_set_dispose( cp, rset, SLAP_SET_RREF2REF( op_flags ) );
366
367         return set;
368 }
369
370 static BerVarray
371 set_chase( SLAP_SET_GATHER gatherer,
372         SetCookie *cp, BerVarray set, AttributeDescription *desc, int closure )
373 {
374         BerVarray       vals, nset;
375         int             i;
376
377         if ( set == NULL ) {
378                 set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
379                                 cp->set_op->o_tmpmemctx );
380                 if ( set != NULL ) {
381                         BER_BVZERO( &set[ 0 ] );
382                 }
383                 return set;
384         }
385
386         if ( BER_BVISNULL( set ) ) {
387                 return set;
388         }
389
390         nset = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
391         if ( nset == NULL ) {
392                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
393                 return NULL;
394         }
395         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
396                 vals = gatherer( cp, &set[ i ], desc );
397                 if ( vals != NULL ) {
398                         nset = slap_set_join( cp, nset, '|', vals );
399                 }
400         }
401         ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
402
403         if ( closure ) {
404                 for ( i = 0; !BER_BVISNULL( &nset[ i ] ); i++ ) {
405                         vals = gatherer( cp, &nset[ i ], desc );
406                         if ( vals != NULL ) {
407                                 nset = slap_set_join( cp, nset, '|', vals );
408                                 if ( nset == NULL ) {
409                                         break;
410                                 }
411                         }
412                 }
413         }
414
415         return nset;
416 }
417
418
419 static BerVarray
420 set_parents( SetCookie *cp, BerVarray set )
421 {
422         int             i, j, last;
423         struct berval   bv, pbv;
424         BerVarray       nset, vals;
425
426         if ( set == NULL ) {
427                 set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
428                                 cp->set_op->o_tmpmemctx );
429                 if ( set != NULL ) {
430                         BER_BVZERO( &set[ 0 ] );
431                 }
432                 return set;
433         }
434
435         if ( BER_BVISNULL( &set[ 0 ] ) ) {
436                 return set;
437         }
438
439         nset = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
440         if ( nset == NULL ) {
441                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
442                 return NULL;
443         }
444
445         BER_BVZERO( &nset[ 0 ] );
446
447         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
448                 int     level = 1;
449
450                 pbv = bv = set[ i ];
451                 for ( ; !BER_BVISEMPTY( &pbv ); dnParent( &bv, &pbv ) ) {
452                         level++;
453                         bv = pbv;
454                 }
455
456                 vals = cp->set_op->o_tmpcalloc( level + 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
457                 if ( vals == NULL ) {
458                         ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
459                         ber_bvarray_free_x( nset, cp->set_op->o_tmpmemctx );
460                         return NULL;
461                 }
462                 BER_BVZERO( &vals[ 0 ] );
463                 last = 0;
464
465                 bv = set[ i ];
466                 for ( j = 0 ; j < level ; j++ ) {
467                         ber_dupbv_x( &vals[ last ], &bv, cp->set_op->o_tmpmemctx );
468                         last++;
469                         dnParent( &bv, &bv );
470                 }
471                 BER_BVZERO( &vals[ last ] );
472
473                 nset = slap_set_join( cp, nset, '|', vals );
474         }
475
476         ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
477
478         return nset;
479 }
480
481
482
483 static BerVarray
484 set_parent( SetCookie *cp, BerVarray set, int level )
485 {
486         int             i, j, last;
487         struct berval   bv;
488         BerVarray       nset;
489
490         if ( set == NULL ) {
491                 set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
492                                 cp->set_op->o_tmpmemctx );
493                 if ( set != NULL ) {
494                         BER_BVZERO( &set[ 0 ] );
495                 }
496                 return set;
497         }
498
499         if ( BER_BVISNULL( &set[ 0 ] ) ) {
500                 return set;
501         }
502
503         nset = cp->set_op->o_tmpcalloc( slap_set_size( set ) + 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
504         if ( nset == NULL ) {
505                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
506                 return NULL;
507         }
508
509         BER_BVZERO( &nset[ 0 ] );
510         last = 0;
511
512         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
513                 bv = set[ i ];
514
515                 for ( j = 0 ; j < level ; j++ ) {
516                         dnParent( &bv, &bv );
517                 }
518
519                 for ( j = 0; !BER_BVISNULL( &nset[ j ] ); j++ ) {
520                         if ( bvmatch( &bv, &nset[ j ] ) )
521                         {
522                                 break;          
523                         }       
524                 }
525
526                 if ( BER_BVISNULL( &nset[ j ] ) ) {
527                         ber_dupbv_x( &nset[ last ], &bv, cp->set_op->o_tmpmemctx );
528                         last++;
529                 }
530         }
531
532         BER_BVZERO( &nset[ last ] );
533
534         ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
535
536         return nset;
537 }
538
539 int
540 slap_set_filter( SLAP_SET_GATHER gatherer,
541         SetCookie *cp, struct berval *fbv,
542         struct berval *user, struct berval *target, BerVarray *results )
543 {
544 #define STACK_SIZE      64
545 #define IS_SET(x)       ( (unsigned long)(x) >= 256 )
546 #define IS_OP(x)        ( (unsigned long)(x) < 256 )
547 #define SF_ERROR(x)     do { rc = -1; goto _error; } while ( 0 )
548 #define SF_TOP()        ( (BerVarray)( ( stp < 0 ) ? 0 : stack[ stp ] ) )
549 #define SF_POP()        ( (BerVarray)( ( stp < 0 ) ? 0 : stack[ stp-- ] ) )
550 #define SF_PUSH(x)      do { \
551                 if ( stp >= ( STACK_SIZE - 1 ) ) SF_ERROR( overflow ); \
552                 stack[ ++stp ] = (BerVarray)(long)(x); \
553         } while ( 0 )
554
555         BerVarray       set, lset;
556         BerVarray       stack[ STACK_SIZE ] = { 0 };
557         int             len, rc, stp;
558         unsigned long   op;
559         char            c, *filter = fbv->bv_val;
560
561         if ( results ) {
562                 *results = NULL;
563         }
564
565         stp = -1;
566         while ( ( c = *filter++ ) ) {
567                 set = NULL;
568                 switch ( c ) {
569                 case ' ':
570                 case '\t':
571                 case '\x0A':
572                 case '\x0D':
573                         break;
574
575                 case '(' /* ) */ :
576                         if ( IS_SET( SF_TOP() ) ) {
577                                 SF_ERROR( syntax );
578                         }
579                         SF_PUSH( c );
580                         break;
581
582                 case /* ( */ ')':
583                         set = SF_POP();
584                         if ( IS_OP( set ) ) {
585                                 SF_ERROR( syntax );
586                         }
587                         if ( SF_TOP() == (void *)'(' /* ) */ ) {
588                                 SF_POP();
589                                 SF_PUSH( set );
590                                 set = NULL;
591
592                         } else if ( IS_OP( SF_TOP() ) ) {
593                                 op = (unsigned long)SF_POP();
594                                 lset = SF_POP();
595                                 SF_POP();
596                                 set = slap_set_join( cp, lset, op, set );
597                                 if ( set == NULL ) {
598                                         SF_ERROR( memory );
599                                 }
600                                 SF_PUSH( set );
601                                 set = NULL;
602
603                         } else {
604                                 SF_ERROR( syntax );
605                         }
606                         break;
607
608                 case '|':       /* union */
609                 case '&':       /* intersection */
610                 case '+':       /* string concatenation */
611                         set = SF_POP();
612                         if ( IS_OP( set ) ) {
613                                 SF_ERROR( syntax );
614                         }
615                         if ( SF_TOP() == 0 || SF_TOP() == (void *)'(' /* ) */ ) {
616                                 SF_PUSH( set );
617                                 set = NULL;
618
619                         } else if ( IS_OP( SF_TOP() ) ) {
620                                 op = (unsigned long)SF_POP();
621                                 lset = SF_POP();
622                                 set = slap_set_join( cp, lset, op, set );
623                                 if ( set == NULL ) {
624                                         SF_ERROR( memory );
625                                 }
626                                 SF_PUSH( set );
627                                 set = NULL;
628                                 
629                         } else {
630                                 SF_ERROR( syntax );
631                         }
632                         SF_PUSH( c );
633                         break;
634
635                 case '[' /* ] */:
636                         if ( ( SF_TOP() == (void *)'/' ) || IS_SET( SF_TOP() ) ) {
637                                 SF_ERROR( syntax );
638                         }
639                         for ( len = 0; ( c = *filter++ ) && ( c != /* [ */ ']' ); len++ )
640                                 ;
641                         if ( c == 0 ) {
642                                 SF_ERROR( syntax );
643                         }
644                         
645                         set = cp->set_op->o_tmpcalloc( 2, sizeof( struct berval ),
646                                         cp->set_op->o_tmpmemctx );
647                         if ( set == NULL ) {
648                                 SF_ERROR( memory );
649                         }
650                         set->bv_val = cp->set_op->o_tmpcalloc( len + 1, sizeof( char ),
651                                         cp->set_op->o_tmpmemctx );
652                         if ( BER_BVISNULL( set ) ) {
653                                 SF_ERROR( memory );
654                         }
655                         AC_MEMCPY( set->bv_val, &filter[ - len - 1 ], len );
656                         set->bv_len = len;
657                         SF_PUSH( set );
658                         set = NULL;
659                         break;
660
661                 case '-':
662                         if ( ( SF_TOP() == (void *)'/' )
663                                 && ( *filter == '*' || ASCII_DIGIT( *filter ) ) )
664                         {
665                                 SF_POP();
666
667                                 if ( *filter == '*' ) {
668                                         set = set_parents( cp, SF_POP() );
669                                         filter++;
670
671                                 } else {
672                                         char *next = NULL;
673                                         long parent = strtol( filter, &next, 10 );
674
675                                         if ( next == filter ) {
676                                                 SF_ERROR( syntax );
677                                         }
678
679                                         set = SF_POP();
680                                         if ( parent != 0 ) {
681                                                 set = set_parent( cp, set, parent );
682                                         }
683                                         filter = next;
684                                 }
685
686                                 if ( set == NULL ) {
687                                         SF_ERROR( memory );
688                                 }
689
690                                 SF_PUSH( set );
691                                 set = NULL;
692                                 break;
693                         } else {
694                                 c = *filter++;
695                                 if ( c != '>' ) {
696                                         SF_ERROR( syntax );
697                                 }
698                                 /* fall through to next case */
699                         }
700
701                 case '/':
702                         if ( IS_OP( SF_TOP() ) ) {
703                                 SF_ERROR( syntax );
704                         }
705                         SF_PUSH( '/' );
706                         break;
707
708                 default:
709                         if ( ( c != '_' )
710                                         && ( c < 'A' || c > 'Z' )
711                                         && ( c < 'a' || c > 'z' ) )
712                         {
713                                 SF_ERROR( syntax );
714                         }
715                         filter--;
716                         for ( len = 1;
717                                         ( c = filter[ len ] )
718                                                 && ( ( c >= '0' && c <= '9' )
719                                                         || ( c >= 'A' && c <= 'Z' )
720                                                         || ( c >= 'a' && c <= 'z' ) );
721                                         len++ )
722                                 /* count */ ;
723                         if ( len == 4
724                                 && memcmp( "this", filter, len ) == 0 )
725                         {
726                                 if ( ( SF_TOP() == (void *)'/' ) || IS_SET( SF_TOP() ) ) {
727                                         SF_ERROR( syntax );
728                                 }
729                                 set = cp->set_op->o_tmpcalloc( 2, sizeof( struct berval ),
730                                                 cp->set_op->o_tmpmemctx );
731                                 if ( set == NULL ) {
732                                         SF_ERROR( memory );
733                                 }
734                                 ber_dupbv_x( set, target, cp->set_op->o_tmpmemctx );
735                                 if ( BER_BVISNULL( set ) ) {
736                                         SF_ERROR( memory );
737                                 }
738                                 BER_BVZERO( &set[ 1 ] );
739                                 
740                         } else if ( len == 4
741                                 && memcmp( "user", filter, len ) == 0 ) 
742                         {
743                                 if ( ( SF_TOP() == (void *)'/' ) || IS_SET( SF_TOP() ) ) {
744                                         SF_ERROR( syntax );
745                                 }
746                                 set = cp->set_op->o_tmpcalloc( 2, sizeof( struct berval ),
747                                                 cp->set_op->o_tmpmemctx );
748                                 if ( set == NULL ) {
749                                         SF_ERROR( memory );
750                                 }
751                                 ber_dupbv_x( set, user, cp->set_op->o_tmpmemctx );
752                                 if ( BER_BVISNULL( set ) ) {
753                                         SF_ERROR( memory );
754                                 }
755                                 BER_BVZERO( &set[ 1 ] );
756                                 
757                         } else if ( SF_TOP() != (void *)'/' ) {
758                                 SF_ERROR( syntax );
759
760                         } else {
761                                 struct berval           fb2;
762                                 AttributeDescription    *ad = NULL;
763                                 const char              *text = NULL;
764
765                                 SF_POP();
766                                 fb2.bv_val = filter;
767                                 fb2.bv_len = len;
768
769                                 if ( slap_bv2ad( &fb2, &ad, &text ) != LDAP_SUCCESS ) {
770                                         SF_ERROR( syntax );
771                                 }
772
773                                 /* NOTE: ad must have distinguishedName syntax
774                                  * or expand in an LDAP URI if c == '*'
775                                  */
776                                 
777                                 set = set_chase( gatherer,
778                                         cp, SF_POP(), ad, c == '*' );
779                                 if ( set == NULL ) {
780                                         SF_ERROR( memory );
781                                 }
782                                 if ( c == '*' ) {
783                                         len++;
784                                 }
785                         }
786                         filter += len;
787                         SF_PUSH( set );
788                         set = NULL;
789                         break;
790                 }
791         }
792
793         set = SF_POP();
794         if ( IS_OP( set ) ) {
795                 SF_ERROR( syntax );
796         }
797         if ( SF_TOP() == 0 ) {
798                 /* FIXME: ok ? */ ;
799
800         } else if ( IS_OP( SF_TOP() ) ) {
801                 op = (unsigned long)SF_POP();
802                 lset = SF_POP();
803                 set = slap_set_join( cp, lset, op, set );
804                 if ( set == NULL ) {
805                         SF_ERROR( memory );
806                 }
807                 
808         } else {
809                 SF_ERROR( syntax );
810         }
811
812         rc = slap_set_isempty( set ) ? 0 : 1;
813         if ( results ) {
814                 *results = set;
815                 set = NULL;
816         }
817
818 _error:
819         if ( IS_SET( set ) ) {
820                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
821         }
822         while ( ( set = SF_POP() ) ) {
823                 if ( IS_SET( set ) ) {
824                         ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
825                 }
826         }
827         return rc;
828 }