wined3d: Set SFLAG_INSYSMEM when WINED3DLOCK_DISCARD is passed to IWineD3DSurfaceImpl...
[wine] / dlls / wldap32 / search.c
1 /*
2  * WLDAP32 - LDAP support for Wine
3  *
4  * Copyright 2005 Hans Leidekker
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22
23 #include "wine/port.h"
24 #include "wine/debug.h"
25
26 #include <stdarg.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winnls.h"
31
32 #ifdef HAVE_LDAP_H
33 #include <ldap.h>
34 #else
35 #define LDAP_SUCCESS        0x00
36 #define LDAP_NOT_SUPPORTED  0x5c
37 #endif
38
39 #include "winldap_private.h"
40 #include "wldap32.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(wldap32);
43
44 /***********************************************************************
45  *      ldap_searchA     (WLDAP32.@)
46  *
47  * See ldap_searchW.
48  */
49 ULONG CDECL ldap_searchA( WLDAP32_LDAP *ld, PCHAR base, ULONG scope, PCHAR filter,
50     PCHAR attrs[], ULONG attrsonly )
51 {
52     ULONG ret = LDAP_NOT_SUPPORTED;
53 #ifdef HAVE_LDAP
54     WCHAR *baseW = NULL, *filterW = NULL, **attrsW = NULL;
55
56     ret = WLDAP32_LDAP_NO_MEMORY;
57
58     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x)\n", ld, debugstr_a(base),
59            scope, debugstr_a(filter), attrs, attrsonly );
60
61     if (!ld) return ~0UL;
62
63     if (base) {
64         baseW = strAtoW( base );
65         if (!baseW) goto exit;
66     }
67     if (filter) {
68         filterW = strAtoW( filter );
69         if (!filterW) goto exit;
70     }
71     if (attrs) {
72         attrsW = strarrayAtoW( attrs );
73         if (!attrsW) goto exit;
74     }
75
76     ret = ldap_searchW( ld, baseW, scope, filterW, attrsW, attrsonly );
77
78 exit:
79     strfreeW( baseW );
80     strfreeW( filterW );
81     strarrayfreeW( attrsW );
82
83 #endif
84     return ret;
85 }
86
87 /***********************************************************************
88  *      ldap_searchW     (WLDAP32.@)
89  *
90  * Search a directory tree (asynchronous operation).
91  *
92  * PARAMS
93  *  ld        [I] Pointer to an LDAP context.
94  *  base      [I] Starting point for the search.
95  *  scope     [I] Search scope. One of LDAP_SCOPE_BASE,
96  *                LDAP_SCOPE_ONELEVEL and LDAP_SCOPE_SUBTREE.
97  *  filter    [I] Search filter.
98  *  attrs     [I] Attributes to return.
99  *  attrsonly [I] Return no values, only attributes.
100  *
101  * RETURNS
102  *  Success: Message ID of the search operation.
103  *  Failure: ~0UL
104  *
105  * NOTES
106  *  Call ldap_result with the message ID to get the result of
107  *  the operation. Cancel the operation by calling ldap_abandon
108  *  with the message ID.
109  */
110 ULONG CDECL ldap_searchW( WLDAP32_LDAP *ld, PWCHAR base, ULONG scope, PWCHAR filter,
111     PWCHAR attrs[], ULONG attrsonly )
112 {
113     ULONG ret = LDAP_NOT_SUPPORTED;
114 #ifdef HAVE_LDAP
115     char *baseU = NULL, *filterU = NULL, **attrsU = NULL;
116     int msg;
117
118     ret = WLDAP32_LDAP_NO_MEMORY;
119
120     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x)\n", ld, debugstr_w(base),
121            scope, debugstr_w(filter), attrs, attrsonly );
122
123     if (!ld) return ~0UL;
124
125     if (base) {
126         baseU = strWtoU( base );
127         if (!baseU) goto exit;
128     }
129     if (filter) {
130         filterU = strWtoU( filter );
131         if (!filterU) goto exit;
132     }
133     if (attrs) {
134         attrsU = strarrayWtoU( attrs );
135         if (!attrsU) goto exit;
136     }
137
138     ret = ldap_search_ext( ld, baseU, scope, filterU, attrsU, attrsonly,
139                            NULL, NULL, NULL, 0, &msg );
140
141     if (ret == LDAP_SUCCESS)
142         ret = msg;
143     else
144         ret = ~0UL;
145
146 exit:
147     strfreeU( baseU );
148     strfreeU( filterU );
149     strarrayfreeU( attrsU );
150
151 #endif
152     return ret;
153 }
154
155 /***********************************************************************
156  *      ldap_search_extA     (WLDAP32.@)
157  *
158  * See ldap_search_extW.
159  */
160 ULONG CDECL ldap_search_extA( WLDAP32_LDAP *ld, PCHAR base, ULONG scope,
161     PCHAR filter, PCHAR attrs[], ULONG attrsonly, PLDAPControlA *serverctrls,
162     PLDAPControlA *clientctrls, ULONG timelimit, ULONG sizelimit, ULONG *message )
163 {
164     ULONG ret = LDAP_NOT_SUPPORTED;
165 #ifdef HAVE_LDAP
166     WCHAR *baseW = NULL, *filterW = NULL, **attrsW = NULL;
167     LDAPControlW **serverctrlsW = NULL, **clientctrlsW = NULL;
168
169     ret = WLDAP32_LDAP_NO_MEMORY;
170
171     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x, %p, %p, 0x%08x, 0x%08x, %p)\n",
172            ld, debugstr_a(base), scope, debugstr_a(filter), attrs, attrsonly,
173            serverctrls, clientctrls, timelimit, sizelimit, message );
174
175     if (!ld) return WLDAP32_LDAP_PARAM_ERROR;
176
177     if (base) {
178         baseW = strAtoW( base );
179         if (!baseW) goto exit;
180     }
181     if (filter)
182     {
183         filterW = strAtoW( filter );
184         if (!filterW) goto exit;
185     }
186     if (attrs) {
187         attrsW = strarrayAtoW( attrs );
188         if (!attrsW) goto exit;
189     }
190     if (serverctrls) {
191         serverctrlsW = controlarrayAtoW( serverctrls );
192         if (!serverctrlsW) goto exit;
193     }
194     if (clientctrls) {
195         clientctrlsW = controlarrayAtoW( clientctrls );
196         if (!clientctrlsW) goto exit;
197     }
198
199     ret = ldap_search_extW( ld, baseW, scope, filterW, attrsW, attrsonly,
200                             serverctrlsW, clientctrlsW, timelimit, sizelimit, message );
201
202 exit:
203     strfreeW( baseW );
204     strfreeW( filterW );
205     strarrayfreeW( attrsW );
206     controlarrayfreeW( serverctrlsW );
207     controlarrayfreeW( clientctrlsW );
208
209 #endif
210     return ret;
211 }
212
213 /***********************************************************************
214  *      ldap_search_extW     (WLDAP32.@)
215  *
216  * Search a directory tree (asynchronous operation).
217  *
218  * PARAMS
219  *  ld          [I] Pointer to an LDAP context.
220  *  base        [I] Starting point for the search.
221  *  scope       [I] Search scope. One of LDAP_SCOPE_BASE,
222  *                  LDAP_SCOPE_ONELEVEL and LDAP_SCOPE_SUBTREE.
223  *  filter      [I] Search filter.
224  *  attrs       [I] Attributes to return.
225  *  attrsonly   [I] Return no values, only attributes.
226  *  serverctrls [I] Array of LDAP server controls.
227  *  clientctrls [I] Array of LDAP client controls.
228  *  timelimit   [I] Timeout in seconds.
229  *  sizelimit   [I] Maximum number of entries to return. Zero means unlimited.
230  *  message     [O] Message ID of the search operation.
231  *
232  * RETURNS
233  *  Success: LDAP_SUCCESS
234  *  Failure: An LDAP error code.
235  *
236  * NOTES
237  *  Call ldap_result with the message ID to get the result of
238  *  the operation. Cancel the operation by calling ldap_abandon
239  *  with the message ID.
240  */
241 ULONG CDECL ldap_search_extW( WLDAP32_LDAP *ld, PWCHAR base, ULONG scope,
242     PWCHAR filter, PWCHAR attrs[], ULONG attrsonly, PLDAPControlW *serverctrls,
243     PLDAPControlW *clientctrls, ULONG timelimit, ULONG sizelimit, ULONG *message )
244 {
245     ULONG ret = LDAP_NOT_SUPPORTED;
246 #ifdef HAVE_LDAP
247     char *baseU = NULL, *filterU = NULL, **attrsU = NULL;
248     LDAPControl **serverctrlsU = NULL, **clientctrlsU = NULL;
249     struct timeval tv;
250
251     ret = WLDAP32_LDAP_NO_MEMORY;
252
253     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x, %p, %p, 0x%08x, 0x%08x, %p)\n",
254            ld, debugstr_w(base), scope, debugstr_w(filter), attrs, attrsonly,
255            serverctrls, clientctrls, timelimit, sizelimit, message );
256
257     if (!ld) return ~0UL;
258
259     if (base) {
260         baseU = strWtoU( base );
261         if (!baseU) goto exit;
262     }
263     if (filter) {
264         filterU = strWtoU( filter );
265         if (!filterU) goto exit;
266     }
267     if (attrs) {
268         attrsU = strarrayWtoU( attrs );
269         if (!attrsU) goto exit;
270     }
271     if (serverctrls) {
272         serverctrlsU = controlarrayWtoU( serverctrls );
273         if (!serverctrlsU) goto exit;
274     }
275     if (clientctrls) {
276         clientctrlsU = controlarrayWtoU( clientctrls );
277         if (!clientctrlsU) goto exit;
278     }
279
280     tv.tv_sec = timelimit;
281     tv.tv_usec = 0;
282
283     ret = ldap_search_ext( ld, baseU, scope, filterU, attrsU, attrsonly,
284                            serverctrlsU, clientctrlsU, &tv, sizelimit, (int *)message );
285
286 exit:
287     strfreeU( baseU );
288     strfreeU( filterU );
289     strarrayfreeU( attrsU );
290     controlarrayfreeU( serverctrlsU );
291     controlarrayfreeU( clientctrlsU );
292
293 #endif
294     return ret;
295 }
296
297 /***********************************************************************
298  *      ldap_search_ext_sA     (WLDAP32.@)
299  *
300  * See ldap_search_ext_sW.
301  */
302 ULONG CDECL ldap_search_ext_sA( WLDAP32_LDAP *ld, PCHAR base, ULONG scope,
303     PCHAR filter, PCHAR attrs[], ULONG attrsonly, PLDAPControlA *serverctrls,
304     PLDAPControlA *clientctrls, struct l_timeval* timeout, ULONG sizelimit, WLDAP32_LDAPMessage **res )
305 {
306     ULONG ret = LDAP_NOT_SUPPORTED;
307 #ifdef HAVE_LDAP
308     WCHAR *baseW = NULL, *filterW = NULL, **attrsW = NULL;
309     LDAPControlW **serverctrlsW = NULL, **clientctrlsW = NULL;
310
311     ret = WLDAP32_LDAP_NO_MEMORY;
312
313     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x, %p, %p, %p, 0x%08x, %p)\n",
314            ld, debugstr_a(base), scope, debugstr_a(filter), attrs, attrsonly,
315            serverctrls, clientctrls, timeout, sizelimit, res );
316
317     if (!ld || !res) return WLDAP32_LDAP_PARAM_ERROR;
318
319     if (base) {
320         baseW = strAtoW( base );
321         if (!baseW) goto exit;
322     }
323     if (filter) {
324         filterW = strAtoW( filter );
325         if (!filterW) goto exit;
326     }
327     if (attrs) {
328         attrsW = strarrayAtoW( attrs );
329         if (!attrsW) goto exit;
330     }
331     if (serverctrls) {
332         serverctrlsW = controlarrayAtoW( serverctrls );
333         if (!serverctrlsW) goto exit;
334     }
335     if (clientctrls) {
336         clientctrlsW = controlarrayAtoW( clientctrls );
337         if (!clientctrlsW) goto exit;
338     }
339
340     ret = ldap_search_ext_sW( ld, baseW, scope, filterW, attrsW, attrsonly,
341                               serverctrlsW, clientctrlsW, timeout, sizelimit, res );
342
343 exit:
344     strfreeW( baseW );
345     strfreeW( filterW );
346     strarrayfreeW( attrsW );
347     controlarrayfreeW( serverctrlsW );
348     controlarrayfreeW( clientctrlsW );
349
350 #endif
351     return ret;
352 }
353
354 /***********************************************************************
355  *      ldap_search_ext_sW     (WLDAP32.@)
356  *
357  * Search a directory tree (synchronous operation).
358  *
359  * PARAMS
360  *  ld          [I] Pointer to an LDAP context.
361  *  base        [I] Starting point for the search.
362  *  scope       [I] Search scope. One of LDAP_SCOPE_BASE,
363  *                  LDAP_SCOPE_ONELEVEL and LDAP_SCOPE_SUBTREE.
364  *  filter      [I] Search filter.
365  *  attrs       [I] Attributes to return.
366  *  attrsonly   [I] Return no values, only attributes.
367  *  serverctrls [I] Array of LDAP server controls.
368  *  clientctrls [I] Array of LDAP client controls.
369  *  timeout     [I] Timeout in seconds.
370  *  sizelimit   [I] Maximum number of entries to return. Zero means unlimited.
371  *  res         [O] Results of the search operation.
372  *
373  * RETURNS
374  *  Success: LDAP_SUCCESS
375  *  Failure: An LDAP error code.
376  *
377  * NOTES
378  *  Call ldap_msgfree to free the results.
379  */
380 ULONG CDECL ldap_search_ext_sW( WLDAP32_LDAP *ld, PWCHAR base, ULONG scope,
381     PWCHAR filter, PWCHAR attrs[], ULONG attrsonly, PLDAPControlW *serverctrls,
382     PLDAPControlW *clientctrls, struct l_timeval* timeout, ULONG sizelimit, WLDAP32_LDAPMessage **res )
383 {
384     ULONG ret = LDAP_NOT_SUPPORTED;
385 #ifdef HAVE_LDAP
386     char *baseU = NULL, *filterU = NULL, **attrsU = NULL;
387     LDAPControl **serverctrlsU = NULL, **clientctrlsU = NULL;
388
389     ret = WLDAP32_LDAP_NO_MEMORY;
390
391     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x, %p, %p, %p, 0x%08x, %p)\n",
392            ld, debugstr_w(base), scope, debugstr_w(filter), attrs, attrsonly,
393            serverctrls, clientctrls, timeout, sizelimit, res );
394
395     if (!ld || !res) return WLDAP32_LDAP_PARAM_ERROR;
396
397     if (base) {
398         baseU = strWtoU( base );
399         if (!baseU) goto exit;
400     }
401     if (filter) {
402         filterU = strWtoU( filter );
403         if (!filterU) goto exit;
404     }
405     if (attrs) {
406         attrsU = strarrayWtoU( attrs );
407         if (!attrsU) goto exit;
408     }
409     if (serverctrls) {
410         serverctrlsU = controlarrayWtoU( serverctrls );
411         if (!serverctrlsU) goto exit;
412     }
413     if (clientctrls) {
414         clientctrlsU = controlarrayWtoU( clientctrls );
415         if (!clientctrlsU) goto exit;
416     }
417
418     ret = ldap_search_ext_s( ld, baseU, scope, filterU, attrsU, attrsonly,
419                              serverctrlsU, clientctrlsU, (struct timeval *)timeout, sizelimit, res );
420
421 exit:
422     strfreeU( baseU );
423     strfreeU( filterU );
424     strarrayfreeU( attrsU );
425     controlarrayfreeU( serverctrlsU );
426     controlarrayfreeU( clientctrlsU );
427
428 #endif
429     return ret;
430 }
431
432 /***********************************************************************
433  *      ldap_search_sA     (WLDAP32.@)
434  *
435  * See ldap_search_sW.
436  */
437 ULONG CDECL ldap_search_sA( WLDAP32_LDAP *ld, PCHAR base, ULONG scope, PCHAR filter,
438     PCHAR attrs[], ULONG attrsonly, WLDAP32_LDAPMessage **res )
439 {
440     ULONG ret = LDAP_NOT_SUPPORTED;
441 #ifdef HAVE_LDAP
442     WCHAR *baseW = NULL, *filterW = NULL, **attrsW = NULL;
443
444     ret = WLDAP32_LDAP_NO_MEMORY;
445
446     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x, %p)\n", ld, debugstr_a(base),
447            scope, debugstr_a(filter), attrs, attrsonly, res );
448
449     if (!ld || !res) return WLDAP32_LDAP_PARAM_ERROR;
450
451     if (base) {
452         baseW = strAtoW( base );
453         if (!baseW) goto exit;
454     }
455     if (filter) {
456         filterW = strAtoW( filter );
457         if (!filterW) goto exit;
458     }
459     if (attrs) {
460         attrsW = strarrayAtoW( attrs );
461         if (!attrsW) goto exit;
462     }
463
464     ret = ldap_search_sW( ld, baseW, scope, filterW, attrsW, attrsonly, res );
465
466 exit:
467     strfreeW( baseW );
468     strfreeW( filterW );
469     strarrayfreeW( attrsW );
470
471 #endif
472     return ret;
473 }
474
475 /***********************************************************************
476  *      ldap_search_sW     (WLDAP32.@)
477  *
478  * Search a directory tree (synchronous operation).
479  *
480  * PARAMS
481  *  ld        [I] Pointer to an LDAP context.
482  *  base      [I] Starting point for the search.
483  *  scope     [I] Search scope. One of LDAP_SCOPE_BASE,
484  *                LDAP_SCOPE_ONELEVEL and LDAP_SCOPE_SUBTREE.
485  *  filter    [I] Search filter.
486  *  attrs     [I] Attributes to return.
487  *  attrsonly [I] Return no values, only attributes.
488  *  res       [O] Results of the search operation.
489  *
490  * RETURNS
491  *  Success: LDAP_SUCCESS
492  *  Failure: An LDAP error code.
493  *
494  * NOTES
495  *  Call ldap_msgfree to free the results.
496  */
497 ULONG CDECL ldap_search_sW( WLDAP32_LDAP *ld, PWCHAR base, ULONG scope, PWCHAR filter,
498     PWCHAR attrs[], ULONG attrsonly, WLDAP32_LDAPMessage **res )
499 {
500     ULONG ret = LDAP_NOT_SUPPORTED;
501 #ifdef HAVE_LDAP
502     char *baseU = NULL, *filterU = NULL, **attrsU = NULL;
503
504     ret = WLDAP32_LDAP_NO_MEMORY;
505
506     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x, %p)\n", ld, debugstr_w(base),
507            scope, debugstr_w(filter), attrs, attrsonly, res );
508
509     if (!ld || !res) return WLDAP32_LDAP_PARAM_ERROR;
510
511     if (base) {
512         baseU = strWtoU( base );
513         if (!baseU) goto exit;
514     }
515     if (filter) {
516         filterU = strWtoU( filter );
517         if (!filterU) goto exit;
518     }
519     if (attrs) {
520         attrsU = strarrayWtoU( attrs );
521         if (!attrsU) goto exit;
522     }
523
524     ret = ldap_search_ext_s( ld, baseU, scope, filterU, attrsU, attrsonly,
525                              NULL, NULL, NULL, 0, res );
526
527 exit:
528     strfreeU( baseU );
529     strfreeU( filterU );
530     strarrayfreeU( attrsU );
531
532 #endif
533     return ret;
534 }
535
536 /***********************************************************************
537  *      ldap_search_stA     (WLDAP32.@)
538  *
539  * See ldap_search_stW.
540  */
541 ULONG CDECL ldap_search_stA( WLDAP32_LDAP *ld, const PCHAR base, ULONG scope,
542     const PCHAR filter, PCHAR attrs[], ULONG attrsonly,
543     struct l_timeval *timeout, WLDAP32_LDAPMessage **res )
544 {
545     ULONG ret = LDAP_NOT_SUPPORTED;
546 #ifdef HAVE_LDAP
547     WCHAR *baseW = NULL, *filterW = NULL, **attrsW = NULL;
548
549     ret = WLDAP32_LDAP_NO_MEMORY;
550
551     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x, %p, %p)\n", ld,
552            debugstr_a(base), scope, debugstr_a(filter), attrs,
553            attrsonly, timeout, res );
554
555     if (!ld || !res) return WLDAP32_LDAP_PARAM_ERROR;
556
557     if (base) {
558         baseW = strAtoW( base );
559         if (!baseW) goto exit;
560     }
561     if (filter) {
562         filterW = strAtoW( filter );
563         if (!filterW) goto exit;
564     }
565     if (attrs) {
566         attrsW = strarrayAtoW( attrs );
567         if (!attrsW) goto exit;
568     }
569
570     ret = ldap_search_stW( ld, baseW, scope, filterW, attrsW, attrsonly,
571                            timeout, res );
572
573 exit:
574     strfreeW( baseW );
575     strfreeW( filterW );
576     strarrayfreeW( attrsW );
577
578 #endif
579     return ret;
580 }
581
582 /***********************************************************************
583  *      ldap_search_stW     (WLDAP32.@)
584  *
585  * Search a directory tree (synchronous operation).
586  *
587  * PARAMS
588  *  ld        [I] Pointer to an LDAP context.
589  *  base      [I] Starting point for the search.
590  *  scope     [I] Search scope. One of LDAP_SCOPE_BASE,
591  *                LDAP_SCOPE_ONELEVEL and LDAP_SCOPE_SUBTREE.
592  *  filter    [I] Search filter.
593  *  attrs     [I] Attributes to return.
594  *  attrsonly [I] Return no values, only attributes.
595  *  timeout   [I] Timeout in seconds.
596  *  res       [O] Results of the search operation.
597  *
598  * RETURNS
599  *  Success: LDAP_SUCCESS
600  *  Failure: An LDAP error code.
601  *
602  * NOTES
603  *  Call ldap_msgfree to free the results.
604  */
605 ULONG CDECL ldap_search_stW( WLDAP32_LDAP *ld, const PWCHAR base, ULONG scope,
606     const PWCHAR filter, PWCHAR attrs[], ULONG attrsonly,
607     struct l_timeval *timeout, WLDAP32_LDAPMessage **res )
608 {
609     ULONG ret = LDAP_NOT_SUPPORTED;
610 #ifdef HAVE_LDAP
611     char *baseU = NULL, *filterU = NULL, **attrsU = NULL;
612
613     ret = WLDAP32_LDAP_NO_MEMORY;
614
615     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x, %p, %p)\n", ld,
616            debugstr_w(base), scope, debugstr_w(filter), attrs,
617            attrsonly, timeout, res );
618
619     if (!ld || !res) return WLDAP32_LDAP_PARAM_ERROR;
620
621     if (base) {
622         baseU = strWtoU( base );
623         if (!baseU) goto exit;
624     }
625     if (filter) {
626         filterU = strWtoU( filter );
627         if (!filterU) goto exit;
628     }
629     if (attrs) {
630         attrsU = strarrayWtoU( attrs );
631         if (!attrsU) goto exit;
632     }
633
634     ret = ldap_search_ext_s( ld, baseU, scope, filterU, attrsU, attrsonly,
635                              NULL, NULL, (struct timeval *)timeout, 0, res );
636
637 exit:
638     strfreeU( baseU );
639     strfreeU( filterU );
640     strarrayfreeU( attrsU );
641
642 #endif
643     return ret;
644 }