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