]> git.sur5r.net Git - openldap/blob - servers/slapd/str2filter.c
Cleanup slapd search op deallocation.
[openldap] / servers / slapd / str2filter.c
1 /* str2filter.c - parse an rfc 1588 string filter */
2
3 #include "portable.h"
4
5 #include <stdio.h>
6
7 #include <ac/string.h>
8 #include <ac/ctype.h>
9 #include <ac/socket.h>
10
11 #include "slap.h"
12
13 static char     *find_matching_paren(char *s);
14 static Filter   *str2list(char *str, long unsigned int ftype);
15 static Filter   *str2simple(char *str);
16 static int      str2subvals(char *val, Filter *f);
17
18 Filter *
19 str2filter( char *str )
20 {
21         Filter  *f = NULL;
22         char    *end;
23
24         Debug( LDAP_DEBUG_FILTER, "str2filter \"%s\"\n", str, 0, 0 );
25
26         if ( str == NULL || *str == '\0' ) {
27                 return( NULL );
28         }
29
30         switch ( *str ) {
31         case '(':
32                 if ( (end = find_matching_paren( str )) == NULL ) {
33                         filter_free( f );
34                         return( NULL );
35                 }
36                 *end = '\0';
37
38                 str++;
39                 switch ( *str ) {
40                 case '&':
41                         Debug( LDAP_DEBUG_FILTER, "str2filter: AND\n",
42                             0, 0, 0 );
43
44                         str++;
45                         f = str2list( str, LDAP_FILTER_AND );
46                         break;
47
48                 case '|':
49                         Debug( LDAP_DEBUG_FILTER, "put_filter: OR\n",
50                             0, 0, 0 );
51
52                         str++;
53                         f = str2list( str, LDAP_FILTER_OR );
54                         break;
55
56                 case '!':
57                         Debug( LDAP_DEBUG_FILTER, "put_filter: NOT\n",
58                             0, 0, 0 );
59
60                         str++;
61                         f = str2list( str, LDAP_FILTER_NOT );
62                         break;
63
64                 default:
65                         Debug( LDAP_DEBUG_FILTER, "str2filter: simple\n",
66                             0, 0, 0 );
67
68                         f = str2simple( str );
69                         break;
70                 }
71                 *end = ')';
72                 break;
73
74         default:        /* assume it's a simple type=value filter */
75                 Debug( LDAP_DEBUG_FILTER, "str2filter: default\n", 0, 0,
76                     0 );
77
78                 f = str2simple( str );
79                 break;
80         }
81
82         return( f );
83 }
84
85 /*
86  * Put a list of filters like this "(filter1)(filter2)..."
87  */
88
89 static Filter *
90 str2list( char *str, unsigned long ftype )
91 {
92         Filter  *f;
93         Filter  **fp;
94         char    *next;
95         char    save;
96
97         Debug( LDAP_DEBUG_FILTER, "str2list \"%s\"\n", str, 0, 0 );
98
99         f = (Filter *) ch_calloc( 1, sizeof(Filter) );
100         f->f_choice = ftype;
101         fp = &f->f_list;
102
103         while ( *str ) {
104                 while ( *str && isspace( *str ) )
105                         str++;
106                 if ( *str == '\0' )
107                         break;
108
109                 if ( (next = find_matching_paren( str )) == NULL ) {
110                         filter_free( f );
111                         return( NULL );
112                 }
113                 save = *++next;
114                 *next = '\0';
115
116                 /* now we have "(filter)" with str pointing to it */
117                 if ( (*fp = str2filter( str )) == NULL ) {
118                         filter_free( f );
119                         *next = save;
120                         return( NULL );
121                 }
122                 *next = save;
123
124                 str = next;
125                 fp = &(*fp)->f_next;
126         }
127         *fp = NULL;
128
129         return( f );
130 }
131
132 static Filter *
133 str2simple( char *str )
134 {
135         Filter          *f;
136         char            *s;
137         char            *value, savechar;
138
139         Debug( LDAP_DEBUG_FILTER, "str2simple \"%s\"\n", str, 0, 0 );
140
141         if ( (s = strchr( str, '=' )) == NULL ) {
142                 return( NULL );
143         }
144         value = s + 1;
145         *s-- = '\0';
146         savechar = *s;
147
148         f = (Filter *) ch_calloc( 1, sizeof(Filter) );
149
150         switch ( *s ) {
151         case '<':
152                 f->f_choice = LDAP_FILTER_LE;
153                 *s = '\0';
154                 break;
155         case '>':
156                 f->f_choice = LDAP_FILTER_GE;
157                 *s = '\0';
158                 break;
159         case '~':
160                 f->f_choice = LDAP_FILTER_APPROX;
161                 *s = '\0';
162                 break;
163         default:
164                 if ( strchr( value, '*' ) == NULL ) {
165                         f->f_choice = LDAP_FILTER_EQUALITY;
166                 } else if ( strcmp( value, "*" ) == 0 ) {
167                         f->f_choice = LDAP_FILTER_PRESENT;
168                 } else {
169                         f->f_choice = LDAP_FILTER_SUBSTRINGS;
170                         f->f_sub_type = ch_strdup( str );
171                         if ( str2subvals( value, f ) != 0 ) {
172                                 filter_free( f );
173                                 *(value-1) = '=';
174                                 return( NULL );
175                         }
176                         *(value-1) = '=';
177                         return( f );
178                 }
179                 break;
180         }
181
182         if ( f->f_choice == LDAP_FILTER_PRESENT ) {
183                 f->f_type = ch_strdup( str );
184         } else {
185                 f->f_avtype = ch_strdup( str );
186                 f->f_avvalue.bv_val = ch_strdup( value );
187                 f->f_avvalue.bv_len = strlen( value );
188         }
189
190         *s = savechar;
191         *(value-1) = '=';
192         return( f );
193 }
194
195 static int
196 str2subvals( char *val, Filter *f )
197 {
198         char    *nextstar;
199         int     gotstar;
200
201         Debug( LDAP_DEBUG_FILTER, "str2subvals \"%s\"\n", val, 0, 0 );
202
203         gotstar = 0;
204         while ( val != NULL && *val ) {
205                 if ( (nextstar = strchr( val, '*' )) != NULL )
206                         *nextstar++ = '\0';
207
208                 if ( gotstar == 0 ) {
209                         f->f_sub_initial = ch_strdup( val );
210                 } else if ( nextstar == NULL ) {
211                         f->f_sub_final = ch_strdup( val );
212                 } else {
213                         charray_add( &f->f_sub_any, ch_strdup( val ) );
214                 }
215
216                 gotstar = 1;
217                 if ( nextstar != NULL )
218                         *(nextstar-1) = '*';
219                 val = nextstar;
220         }
221
222         return( 0 );
223 }
224
225 /*
226  * find_matching_paren - return a pointer to the right paren in s matching
227  * the left paren to which *s currently points
228  */
229
230 static char *
231 find_matching_paren( char *s )
232 {
233         int     balance, escape;
234
235         balance = 0;
236         escape = 0;
237         for ( ; *s; s++ ) {
238                 if ( escape == 0 ) {
239                         if ( *s == '(' )
240                                 balance++;
241                         else if ( *s == ')' )
242                                 balance--;
243                 }
244                 if ( balance == 0 ) {
245                         return( s );
246                 }
247                 if ( *s == '\\' && ! escape )
248                         escape = 1;
249                 else
250                         escape = 0;
251         }
252
253         return( NULL );
254 }