]> git.sur5r.net Git - openldap/blob - libraries/libldap/sort.c
Sync with HEAD
[openldap] / libraries / libldap / sort.c
1 /* sort.c -- LDAP library entry and value sort routines */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2003 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* Portions Copyright (c) 1994 Regents of the University of Michigan.
17  * All rights reserved.
18  *
19  * Redistribution and use in source and binary forms are permitted
20  * provided that this notice is preserved and that due credit is given
21  * to the University of Michigan at Ann Arbor. The name of the University
22  * may not be used to endorse or promote products derived from this
23  * software without specific prior written permission. This software
24  * is provided ``as is'' without express or implied warranty.
25  */
26
27 #include "portable.h"
28
29 #include <stdio.h>
30 #include <ac/stdlib.h>
31
32 #include <ac/ctype.h>
33 #include <ac/string.h>
34 #include <ac/time.h>
35
36
37 #include "ldap-int.h"
38
39 struct entrything {
40         char            **et_vals;
41         LDAPMessage     *et_msg;
42         int             (*et_cmp_fn) LDAP_P((const char *a, const char *b));
43 };
44
45 static int      et_cmp LDAP_P(( const void *aa, const void *bb));
46
47
48 int
49 ldap_sort_strcasecmp(
50         LDAP_CONST void *a,
51         LDAP_CONST void *b
52 )
53 {
54         return( strcasecmp( *(char *const *)a, *(char *const *)b ) );
55 }
56
57 static int
58 et_cmp(
59         const void      *aa,
60         const void      *bb
61 )
62 {
63         int                     i, rc;
64         const struct entrything *a = (const struct entrything *)aa;
65         const struct entrything *b = (const struct entrything *)bb;
66
67         if ( a->et_vals == NULL && b->et_vals == NULL )
68                 return( 0 );
69         if ( a->et_vals == NULL )
70                 return( -1 );
71         if ( b->et_vals == NULL )
72                 return( 1 );
73
74         for ( i = 0; a->et_vals[i] && b->et_vals[i]; i++ ) {
75                 if ( (rc = a->et_cmp_fn( a->et_vals[i], b->et_vals[i] )) != 0 ) {
76                         return( rc );
77                 }
78         }
79
80         if ( a->et_vals[i] == NULL && b->et_vals[i] == NULL )
81                 return( 0 );
82         if ( a->et_vals[i] == NULL )
83                 return( -1 );
84         return( 1 );
85 }
86
87 int
88 ldap_sort_entries(
89     LDAP        *ld,
90     LDAPMessage **chain,
91     LDAP_CONST char     *attr,          /* NULL => sort by DN */
92     int         (*cmp) (LDAP_CONST  char *, LDAP_CONST char *)
93 )
94 {
95         int                     i, count;
96         struct entrything       *et;
97         LDAPMessage             *e, *last;
98         LDAPMessage             **ep;
99
100         assert( ld != NULL );
101
102         count = ldap_count_entries( ld, *chain );
103
104         if ( count < 0 ) {
105                 return -1;
106
107         } else if ( count < 2 ) {
108                 /* zero or one entries -- already sorted! */
109                 return 0;
110         }
111
112         if ( (et = (struct entrything *) LDAP_MALLOC( count *
113             sizeof(struct entrything) )) == NULL ) {
114                 ld->ld_errno = LDAP_NO_MEMORY;
115                 return( -1 );
116         }
117
118         e = *chain;
119         for ( i = 0; i < count; i++ ) {
120                 et[i].et_cmp_fn = cmp;
121                 et[i].et_msg = e;
122                 if ( attr == NULL ) {
123                         char    *dn;
124
125                         dn = ldap_get_dn( ld, e );
126                         et[i].et_vals = ldap_explode_dn( dn, 1 );
127                         LDAP_FREE( dn );
128                 } else {
129                         et[i].et_vals = ldap_get_values( ld, e, attr );
130                 }
131
132                 e = e->lm_chain;
133         }
134         last = e;
135
136         qsort( et, count, sizeof(struct entrything), et_cmp );
137
138         ep = chain;
139         for ( i = 0; i < count; i++ ) {
140                 *ep = et[i].et_msg;
141                 ep = &(*ep)->lm_chain;
142
143                 LDAP_VFREE( et[i].et_vals );
144         }
145         *ep = last;
146         LDAP_FREE( (char *) et );
147
148         return( 0 );
149 }
150
151 int
152 ldap_sort_values(
153     LDAP        *ld,
154     char        **vals,
155     int         (*cmp) (LDAP_CONST void *, LDAP_CONST void *)
156 )
157 {
158         int     nel;
159
160         for ( nel = 0; vals[nel] != NULL; nel++ )
161                 ;       /* NULL */
162
163         qsort( vals, nel, sizeof(char *), cmp );
164
165         return( 0 );
166 }