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