1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the Netscape Public
3*7c478bd9Sstevel@tonic-gate  * License Version 1.1 (the "License"); you may not use this file
4*7c478bd9Sstevel@tonic-gate  * except in compliance with the License. You may obtain a copy of
5*7c478bd9Sstevel@tonic-gate  * the License at http://www.mozilla.org/NPL/
6*7c478bd9Sstevel@tonic-gate  *
7*7c478bd9Sstevel@tonic-gate  * Software distributed under the License is distributed on an "AS
8*7c478bd9Sstevel@tonic-gate  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9*7c478bd9Sstevel@tonic-gate  * implied. See the License for the specific language governing
10*7c478bd9Sstevel@tonic-gate  * rights and limitations under the License.
11*7c478bd9Sstevel@tonic-gate  *
12*7c478bd9Sstevel@tonic-gate  * The Original Code is Mozilla Communicator client code, released
13*7c478bd9Sstevel@tonic-gate  * March 31, 1998.
14*7c478bd9Sstevel@tonic-gate  *
15*7c478bd9Sstevel@tonic-gate  * The Initial Developer of the Original Code is Netscape
16*7c478bd9Sstevel@tonic-gate  * Communications Corporation. Portions created by Netscape are
17*7c478bd9Sstevel@tonic-gate  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
18*7c478bd9Sstevel@tonic-gate  * Rights Reserved.
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * Contributor(s):
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1994 Regents of the University of Michigan.
24*7c478bd9Sstevel@tonic-gate  * All rights reserved.
25*7c478bd9Sstevel@tonic-gate  *
26*7c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted
27*7c478bd9Sstevel@tonic-gate  * provided that this notice is preserved and that due credit is given
28*7c478bd9Sstevel@tonic-gate  * to the University of Michigan at Ann Arbor. The name of the University
29*7c478bd9Sstevel@tonic-gate  * may not be used to endorse or promote products derived from this
30*7c478bd9Sstevel@tonic-gate  * software without specific prior written permission. This software
31*7c478bd9Sstevel@tonic-gate  * is provided ``as is'' without express or implied warranty.
32*7c478bd9Sstevel@tonic-gate  */
33*7c478bd9Sstevel@tonic-gate /*
34*7c478bd9Sstevel@tonic-gate  * sort.c:  LDAP library entry and value sort routines
35*7c478bd9Sstevel@tonic-gate  */
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #include "ldap-int.h"
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate /* This xp_qsort fixes a memory problem (ABR) on Solaris for the client.
40*7c478bd9Sstevel@tonic-gate  * Server is welcome to use it too, but I wasn't sure if it
41*7c478bd9Sstevel@tonic-gate  * would be ok to use XP code here.  -slamm
42*7c478bd9Sstevel@tonic-gate  *
43*7c478bd9Sstevel@tonic-gate  * We don't want to require use of libxp when linking with libldap, so
44*7c478bd9Sstevel@tonic-gate  * I'll leave use of xp_qsort as a MOZILLA_CLIENT-only thing for now. --mcs
45*7c478bd9Sstevel@tonic-gate  */
46*7c478bd9Sstevel@tonic-gate #if defined(MOZILLA_CLIENT) && defined(SOLARIS)
47*7c478bd9Sstevel@tonic-gate #include "xp_qsort.h"
48*7c478bd9Sstevel@tonic-gate #else
49*7c478bd9Sstevel@tonic-gate #define XP_QSORT qsort
50*7c478bd9Sstevel@tonic-gate #endif
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate typedef struct keycmp {
53*7c478bd9Sstevel@tonic-gate     void                 *kc_arg;
54*7c478bd9Sstevel@tonic-gate     LDAP_KEYCMP_CALLBACK *kc_cmp;
55*7c478bd9Sstevel@tonic-gate } keycmp_t;
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate typedef struct keything {
58*7c478bd9Sstevel@tonic-gate     keycmp_t            *kt_cmp;
59*7c478bd9Sstevel@tonic-gate     const struct berval *kt_key;
60*7c478bd9Sstevel@tonic-gate     LDAPMessage         *kt_msg;
61*7c478bd9Sstevel@tonic-gate } keything_t;
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate static int LDAP_C LDAP_CALLBACK
ldapi_keycmp(const void * Lv,const void * Rv)64*7c478bd9Sstevel@tonic-gate ldapi_keycmp( const void *Lv, const void *Rv )
65*7c478bd9Sstevel@tonic-gate {
66*7c478bd9Sstevel@tonic-gate     auto keything_t **L = (keything_t**)Lv;
67*7c478bd9Sstevel@tonic-gate     auto keything_t **R = (keything_t**)Rv;
68*7c478bd9Sstevel@tonic-gate     auto keycmp_t *cmp = (*L)->kt_cmp;
69*7c478bd9Sstevel@tonic-gate     return cmp->kc_cmp( cmp->kc_arg, (*L)->kt_key, (*R)->kt_key );
70*7c478bd9Sstevel@tonic-gate }
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate int
73*7c478bd9Sstevel@tonic-gate LDAP_CALL
ldap_keysort_entries(LDAP * ld,LDAPMessage ** chain,void * arg,LDAP_KEYGEN_CALLBACK * gen,LDAP_KEYCMP_CALLBACK * cmp,LDAP_KEYFREE_CALLBACK * fre)74*7c478bd9Sstevel@tonic-gate ldap_keysort_entries(
75*7c478bd9Sstevel@tonic-gate     LDAP        *ld,
76*7c478bd9Sstevel@tonic-gate     LDAPMessage **chain,
77*7c478bd9Sstevel@tonic-gate     void                  *arg,
78*7c478bd9Sstevel@tonic-gate     LDAP_KEYGEN_CALLBACK  *gen,
79*7c478bd9Sstevel@tonic-gate     LDAP_KEYCMP_CALLBACK  *cmp,
80*7c478bd9Sstevel@tonic-gate     LDAP_KEYFREE_CALLBACK *fre)
81*7c478bd9Sstevel@tonic-gate {
82*7c478bd9Sstevel@tonic-gate 	size_t		count, i;
83*7c478bd9Sstevel@tonic-gate 	keycmp_t	kc = {0};
84*7c478bd9Sstevel@tonic-gate 	keything_t	**kt;
85*7c478bd9Sstevel@tonic-gate 	LDAPMessage	*e, *last;
86*7c478bd9Sstevel@tonic-gate 	LDAPMessage	**ep;
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )
89*7c478bd9Sstevel@tonic-gate 	    || chain == NULL || cmp == NULL ) {
90*7c478bd9Sstevel@tonic-gate 		return( LDAP_PARAM_ERROR );
91*7c478bd9Sstevel@tonic-gate 	}
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 	count = ldap_count_entries( ld, *chain );
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate 	kt = (keything_t**)NSLDAPI_MALLOC( count * (sizeof(keything_t*) + sizeof(keything_t)) );
96*7c478bd9Sstevel@tonic-gate 	if ( kt == NULL ) {
97*7c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
98*7c478bd9Sstevel@tonic-gate 		return( -1 );
99*7c478bd9Sstevel@tonic-gate 	}
100*7c478bd9Sstevel@tonic-gate 	for ( i = 0; i < count; i++ ) {
101*7c478bd9Sstevel@tonic-gate 		kt[i] = i + (keything_t*)(kt + count);
102*7c478bd9Sstevel@tonic-gate 	}
103*7c478bd9Sstevel@tonic-gate 	kc.kc_arg = arg;
104*7c478bd9Sstevel@tonic-gate 	kc.kc_cmp = cmp;
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate 	for ( e = *chain, i = 0; i < count; i++, e = e->lm_chain ) {
107*7c478bd9Sstevel@tonic-gate 		kt[i]->kt_msg = e;
108*7c478bd9Sstevel@tonic-gate 		kt[i]->kt_cmp = &kc;
109*7c478bd9Sstevel@tonic-gate 		kt[i]->kt_key = gen( arg, ld, e );
110*7c478bd9Sstevel@tonic-gate 		if ( kt[i]->kt_key == NULL ) {
111*7c478bd9Sstevel@tonic-gate 			if ( fre ) while ( i-- > 0 ) fre( arg, kt[i]->kt_key );
112*7c478bd9Sstevel@tonic-gate 			NSLDAPI_FREE( (char*)kt );
113*7c478bd9Sstevel@tonic-gate 			LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
114*7c478bd9Sstevel@tonic-gate 			return( -1 );
115*7c478bd9Sstevel@tonic-gate 		}
116*7c478bd9Sstevel@tonic-gate 	}
117*7c478bd9Sstevel@tonic-gate 	last = e;
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate 	XP_QSORT( (void*)kt, count, (size_t)sizeof(keything_t*), ldapi_keycmp );
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate 	ep = chain;
122*7c478bd9Sstevel@tonic-gate 	for ( i = 0; i < count; i++ ) {
123*7c478bd9Sstevel@tonic-gate 		*ep = kt[i]->kt_msg;
124*7c478bd9Sstevel@tonic-gate 		ep = &(*ep)->lm_chain;
125*7c478bd9Sstevel@tonic-gate 		if ( fre ) fre( arg, kt[i]->kt_key );
126*7c478bd9Sstevel@tonic-gate 	}
127*7c478bd9Sstevel@tonic-gate 	*ep = last;
128*7c478bd9Sstevel@tonic-gate 	NSLDAPI_FREE( (char*)kt );
129*7c478bd9Sstevel@tonic-gate 	return( 0 );
130*7c478bd9Sstevel@tonic-gate }
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate struct entrything {
134*7c478bd9Sstevel@tonic-gate 	char		**et_vals;
135*7c478bd9Sstevel@tonic-gate 	LDAPMessage	*et_msg;
136*7c478bd9Sstevel@tonic-gate };
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate typedef int (LDAP_C LDAP_CALLBACK LDAP_CHARCMP_CALLBACK)(char*, char*);
139*7c478bd9Sstevel@tonic-gate typedef int (LDAP_C LDAP_CALLBACK LDAP_VOIDCMP_CALLBACK)(const void*,
140*7c478bd9Sstevel@tonic-gate 	const void*);
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate static LDAP_CHARCMP_CALLBACK *et_cmp_fn;
143*7c478bd9Sstevel@tonic-gate static LDAP_VOIDCMP_CALLBACK et_cmp;
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate int
146*7c478bd9Sstevel@tonic-gate LDAP_C
147*7c478bd9Sstevel@tonic-gate LDAP_CALLBACK
ldap_sort_strcasecmp(const char ** a,const char ** b)148*7c478bd9Sstevel@tonic-gate ldap_sort_strcasecmp(
149*7c478bd9Sstevel@tonic-gate     const char	**a,
150*7c478bd9Sstevel@tonic-gate     const char	**b
151*7c478bd9Sstevel@tonic-gate )
152*7c478bd9Sstevel@tonic-gate {
153*7c478bd9Sstevel@tonic-gate     /* XXXceb
154*7c478bd9Sstevel@tonic-gate      * I am not 100% sure this is the way this should be handled.
155*7c478bd9Sstevel@tonic-gate      * For now we will return a 0 on invalid.
156*7c478bd9Sstevel@tonic-gate      */
157*7c478bd9Sstevel@tonic-gate 	if (NULL == a || NULL == b)
158*7c478bd9Sstevel@tonic-gate 		return (0);
159*7c478bd9Sstevel@tonic-gate 	return( strcasecmp( (char *)*a, (char *)*b ) );
160*7c478bd9Sstevel@tonic-gate }
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate static int
163*7c478bd9Sstevel@tonic-gate LDAP_C
164*7c478bd9Sstevel@tonic-gate LDAP_CALLBACK
et_cmp(const void * aa,const void * bb)165*7c478bd9Sstevel@tonic-gate et_cmp(
166*7c478bd9Sstevel@tonic-gate     const void	*aa,
167*7c478bd9Sstevel@tonic-gate     const void	*bb
168*7c478bd9Sstevel@tonic-gate )
169*7c478bd9Sstevel@tonic-gate {
170*7c478bd9Sstevel@tonic-gate 	int			i, rc;
171*7c478bd9Sstevel@tonic-gate 	struct entrything	*a = (struct entrything *)aa;
172*7c478bd9Sstevel@tonic-gate 	struct entrything	*b = (struct entrything *)bb;
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	if ( a->et_vals == NULL && b->et_vals == NULL )
175*7c478bd9Sstevel@tonic-gate 		return( 0 );
176*7c478bd9Sstevel@tonic-gate 	if ( a->et_vals == NULL )
177*7c478bd9Sstevel@tonic-gate 		return( -1 );
178*7c478bd9Sstevel@tonic-gate 	if ( b->et_vals == NULL )
179*7c478bd9Sstevel@tonic-gate 		return( 1 );
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	for ( i = 0; a->et_vals[i] && b->et_vals[i]; i++ ) {
182*7c478bd9Sstevel@tonic-gate 		if ( (rc = (*et_cmp_fn)( a->et_vals[i], b->et_vals[i] ))
183*7c478bd9Sstevel@tonic-gate 		    != 0 ) {
184*7c478bd9Sstevel@tonic-gate 			return( rc );
185*7c478bd9Sstevel@tonic-gate 		}
186*7c478bd9Sstevel@tonic-gate 	}
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 	if ( a->et_vals[i] == NULL && b->et_vals[i] == NULL )
189*7c478bd9Sstevel@tonic-gate 		return( 0 );
190*7c478bd9Sstevel@tonic-gate 	if ( a->et_vals[i] == NULL )
191*7c478bd9Sstevel@tonic-gate 		return( -1 );
192*7c478bd9Sstevel@tonic-gate 	return( 1 );
193*7c478bd9Sstevel@tonic-gate }
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate int
196*7c478bd9Sstevel@tonic-gate LDAP_CALL
ldap_multisort_entries(LDAP * ld,LDAPMessage ** chain,char ** attr,LDAP_CMP_CALLBACK * cmp)197*7c478bd9Sstevel@tonic-gate ldap_multisort_entries(
198*7c478bd9Sstevel@tonic-gate     LDAP	*ld,
199*7c478bd9Sstevel@tonic-gate     LDAPMessage	**chain,
200*7c478bd9Sstevel@tonic-gate     char	**attr,		/* NULL => sort by DN */
201*7c478bd9Sstevel@tonic-gate     LDAP_CMP_CALLBACK *cmp
202*7c478bd9Sstevel@tonic-gate )
203*7c478bd9Sstevel@tonic-gate {
204*7c478bd9Sstevel@tonic-gate 	int			i, count;
205*7c478bd9Sstevel@tonic-gate 	struct entrything	*et;
206*7c478bd9Sstevel@tonic-gate 	LDAPMessage		*e, *last;
207*7c478bd9Sstevel@tonic-gate 	LDAPMessage		**ep;
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )
210*7c478bd9Sstevel@tonic-gate 	    || chain == NULL || cmp == NULL ) {
211*7c478bd9Sstevel@tonic-gate 		return( LDAP_PARAM_ERROR );
212*7c478bd9Sstevel@tonic-gate 	}
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate 	count = ldap_count_entries( ld, *chain );
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 	if ( (et = (struct entrything *)NSLDAPI_MALLOC( count *
217*7c478bd9Sstevel@tonic-gate 	    sizeof(struct entrything) )) == NULL ) {
218*7c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
219*7c478bd9Sstevel@tonic-gate 		return( -1 );
220*7c478bd9Sstevel@tonic-gate 	}
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 	e = *chain;
223*7c478bd9Sstevel@tonic-gate 	for ( i = 0; i < count; i++ ) {
224*7c478bd9Sstevel@tonic-gate 		et[i].et_msg = e;
225*7c478bd9Sstevel@tonic-gate 		et[i].et_vals = NULL;
226*7c478bd9Sstevel@tonic-gate 		if ( attr == NULL ) {
227*7c478bd9Sstevel@tonic-gate 			char	*dn;
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 			dn = ldap_get_dn( ld, e );
230*7c478bd9Sstevel@tonic-gate 			et[i].et_vals = ldap_explode_dn( dn, 1 );
231*7c478bd9Sstevel@tonic-gate 			NSLDAPI_FREE( dn );
232*7c478bd9Sstevel@tonic-gate 		} else {
233*7c478bd9Sstevel@tonic-gate 			int	attrcnt;
234*7c478bd9Sstevel@tonic-gate 			char	**vals;
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 			for ( attrcnt = 0; attr[attrcnt] != NULL; attrcnt++ ) {
237*7c478bd9Sstevel@tonic-gate 			    vals = ldap_get_values( ld, e, attr[attrcnt] );
238*7c478bd9Sstevel@tonic-gate 			    if ( ldap_charray_merge( &(et[i].et_vals), vals )
239*7c478bd9Sstevel@tonic-gate 				!= 0 ) {
240*7c478bd9Sstevel@tonic-gate 				int	j;
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 				/* XXX risky: ldap_value_free( vals ); */
243*7c478bd9Sstevel@tonic-gate 				for ( j = 0; j <= i; j++ )
244*7c478bd9Sstevel@tonic-gate 				    ldap_value_free( et[j].et_vals );
245*7c478bd9Sstevel@tonic-gate 				NSLDAPI_FREE( (char *) et );
246*7c478bd9Sstevel@tonic-gate 				LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL,
247*7c478bd9Sstevel@tonic-gate 				    NULL );
248*7c478bd9Sstevel@tonic-gate 				return( -1 );
249*7c478bd9Sstevel@tonic-gate 			    }
250*7c478bd9Sstevel@tonic-gate 			    if ( vals != NULL ) {
251*7c478bd9Sstevel@tonic-gate 				NSLDAPI_FREE( (char *)vals );
252*7c478bd9Sstevel@tonic-gate 			    }
253*7c478bd9Sstevel@tonic-gate 			}
254*7c478bd9Sstevel@tonic-gate 		}
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 		e = e->lm_chain;
257*7c478bd9Sstevel@tonic-gate 	}
258*7c478bd9Sstevel@tonic-gate 	last = e;
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate 	et_cmp_fn = (LDAP_CHARCMP_CALLBACK *)cmp;
261*7c478bd9Sstevel@tonic-gate 	XP_QSORT( (void *) et, (size_t) count,
262*7c478bd9Sstevel@tonic-gate 		(size_t) sizeof(struct entrything), et_cmp );
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate 	ep = chain;
265*7c478bd9Sstevel@tonic-gate 	for ( i = 0; i < count; i++ ) {
266*7c478bd9Sstevel@tonic-gate 		*ep = et[i].et_msg;
267*7c478bd9Sstevel@tonic-gate 		ep = &(*ep)->lm_chain;
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 		ldap_value_free( et[i].et_vals );
270*7c478bd9Sstevel@tonic-gate 	}
271*7c478bd9Sstevel@tonic-gate 	*ep = last;
272*7c478bd9Sstevel@tonic-gate 	NSLDAPI_FREE( (char *) et );
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 	return( 0 );
275*7c478bd9Sstevel@tonic-gate }
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate int
278*7c478bd9Sstevel@tonic-gate LDAP_CALL
ldap_sort_entries(LDAP * ld,LDAPMessage ** chain,char * attr,LDAP_CMP_CALLBACK * cmp)279*7c478bd9Sstevel@tonic-gate ldap_sort_entries(
280*7c478bd9Sstevel@tonic-gate     LDAP	*ld,
281*7c478bd9Sstevel@tonic-gate     LDAPMessage	**chain,
282*7c478bd9Sstevel@tonic-gate     char	*attr,		/* NULL => sort by DN */
283*7c478bd9Sstevel@tonic-gate     LDAP_CMP_CALLBACK *cmp
284*7c478bd9Sstevel@tonic-gate )
285*7c478bd9Sstevel@tonic-gate {
286*7c478bd9Sstevel@tonic-gate 	char	*attrs[2];
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 	attrs[0] = attr;
289*7c478bd9Sstevel@tonic-gate 	attrs[1] = NULL;
290*7c478bd9Sstevel@tonic-gate 	return( ldap_multisort_entries( ld, chain, attr ? attrs : NULL, cmp ) );
291*7c478bd9Sstevel@tonic-gate }
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate int
294*7c478bd9Sstevel@tonic-gate LDAP_CALL
ldap_sort_values(LDAP * ld,char ** vals,LDAP_VALCMP_CALLBACK * cmp)295*7c478bd9Sstevel@tonic-gate ldap_sort_values(
296*7c478bd9Sstevel@tonic-gate     LDAP	*ld,
297*7c478bd9Sstevel@tonic-gate     char	**vals,
298*7c478bd9Sstevel@tonic-gate     LDAP_VALCMP_CALLBACK *cmp
299*7c478bd9Sstevel@tonic-gate )
300*7c478bd9Sstevel@tonic-gate {
301*7c478bd9Sstevel@tonic-gate 	int	nel;
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || cmp == NULL ) {
304*7c478bd9Sstevel@tonic-gate 		return( LDAP_PARAM_ERROR );
305*7c478bd9Sstevel@tonic-gate 	}
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate     if ( NULL == vals)
308*7c478bd9Sstevel@tonic-gate     {
309*7c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
310*7c478bd9Sstevel@tonic-gate 		return( LDAP_PARAM_ERROR );
311*7c478bd9Sstevel@tonic-gate 	}
312*7c478bd9Sstevel@tonic-gate 	for ( nel = 0; vals[nel] != NULL; nel++ )
313*7c478bd9Sstevel@tonic-gate 		;	/* NULL */
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	XP_QSORT( vals, nel, sizeof(char *), (LDAP_VOIDCMP_CALLBACK *)cmp );
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate 	return( LDAP_SUCCESS );
318*7c478bd9Sstevel@tonic-gate }
319