r574: - another attempt at const cleanliness in ldb
[kamenim/samba.git] / source4 / lib / ldb / common / ldb_msg.c
1 /* 
2    ldb database library
3
4    Copyright (C) Andrew Tridgell  2004
5
6      ** NOTE! The following LGPL license applies to the ldb
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9    
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Lesser General Public
12    License as published by the Free Software Foundation; either
13    version 2 of the License, or (at your option) any later version.
14
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Lesser General Public License for more details.
19
20    You should have received a copy of the GNU Lesser General Public
21    License along with this library; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25 /*
26  *  Name: ldb
27  *
28  *  Component: ldb message component utility functions
29  *
30  *  Description: functions for manipulating ldb_message structures
31  *
32  *  Author: Andrew Tridgell
33  */
34
35 #include "includes.h"
36
37
38 /*
39   find an element in a message by attribute name
40 */
41 struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg, 
42                                                  const char *attr_name)
43 {
44         int i;
45         for (i=0;i<msg->num_elements;i++) {
46                 if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
47                         return &msg->elements[i];
48                 }
49         }
50         return NULL;
51 }
52
53 /*
54   see if two ldb_val structures contain exactly the same data
55   return 1 for a match, 0 for a mis-match
56 */
57 int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
58 {
59         if (v1->length != v2->length) return 0;
60
61         if (v1->length == 0) return 1;
62
63         if (memcmp(v1->data, v2->data, v1->length) == 0) {
64                 return 1;
65         }
66
67         return 0;
68 }
69
70 /*
71   find a value in an element
72   assumes case sensitive comparison
73 */
74 struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el, 
75                                  struct ldb_val *val)
76 {
77         int i;
78         for (i=0;i<el->num_values;i++) {
79                 if (ldb_val_equal_exact(val, &el->values[i])) {
80                         return &el->values[i];
81                 }
82         }
83         return NULL;
84 }
85
86
87 /*
88   add an empty element to a message
89 */
90 int ldb_msg_add_empty(struct ldb_context *ldb,
91                       struct ldb_message *msg, const char *attr_name, int flags)
92 {
93         struct ldb_message_element *els;
94
95         els = ldb_realloc_p(ldb, msg->elements, 
96                             struct ldb_message_element, msg->num_elements+1);
97         if (!els) {
98                 errno = ENOMEM;
99                 return -1;
100         }
101
102         els[msg->num_elements].values = NULL;
103         els[msg->num_elements].num_values = 0;
104         els[msg->num_elements].flags = flags;
105         els[msg->num_elements].name = ldb_strdup(ldb, attr_name);
106         if (!els[msg->num_elements].name) {
107                 return -1;
108         }
109
110         msg->elements = els;
111         msg->num_elements++;
112
113         return 0;
114 }
115
116 /*
117   add an empty element to a message
118 */
119 int ldb_msg_add(struct ldb_context *ldb,
120                 struct ldb_message *msg, 
121                 const struct ldb_message_element *el, 
122                 int flags)
123 {
124         if (ldb_msg_add_empty(ldb, msg, el->name, flags) != 0) {
125                 return -1;
126         }
127
128         msg->elements[msg->num_elements-1] = *el;
129         msg->elements[msg->num_elements-1].flags = flags;
130
131         return 0;
132 }
133
134 /*
135   add a value to a message
136 */
137 int ldb_msg_add_value(struct ldb_context *ldb,
138                       struct ldb_message *msg, 
139                       char *attr_name,
140                       struct ldb_val *val)
141 {
142         struct ldb_message_element *el;
143         struct ldb_val *vals;
144
145         el = ldb_msg_find_element(msg, attr_name);
146         if (!el) {
147                 ldb_msg_add_empty(ldb, msg, attr_name, 0);
148                 el = ldb_msg_find_element(msg, attr_name);
149         }
150         if (!el) {
151                 return -1;
152         }
153
154         vals = ldb_realloc_p(ldb, el->values, struct ldb_val, el->num_values+1);
155         if (!vals) {
156                 errno = ENOMEM;
157                 return -1;
158         }
159         el->values = vals;
160         el->values[el->num_values] = *val;
161         el->num_values++;
162
163         return 0;
164 }
165
166
167 /*
168   add a string element to a message
169 */
170 int ldb_msg_add_string(struct ldb_context *ldb, struct ldb_message *msg, 
171                        char *attr_name, char *str)
172 {
173         struct ldb_val val;
174
175         val.data = str;
176         val.length = strlen(str);
177
178         return ldb_msg_add_value(ldb, msg, attr_name, &val);
179 }
180
181 /*
182   compare two ldb_message_element structures
183   assumes case senistive comparison
184 */
185 int ldb_msg_element_compare(struct ldb_message_element *el1, 
186                             struct ldb_message_element *el2)
187 {
188         int i;
189
190         if (el1->num_values != el2->num_values) {
191                 return el1->num_values - el2->num_values;
192         }
193
194         for (i=0;i<el1->num_values;i++) {
195                 if (!ldb_msg_find_val(el2, &el1->values[i])) {
196                         return -1;
197                 }
198         }
199
200         return 0;
201 }
202
203
204 /*
205   convenience functions to return common types from a message
206   these return the first value if the attribute is multi-valued
207 */
208 int ldb_msg_find_int(const struct ldb_message *msg, 
209                      const char *attr_name,
210                      int default_value)
211 {
212         struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
213         if (!el || el->num_values == 0) {
214                 return default_value;
215         }
216         return strtol(el->values[0].data, NULL, 0);
217 }
218
219 unsigned int ldb_msg_find_uint(const struct ldb_message *msg, 
220                                const char *attr_name,
221                                int default_value)
222 {
223         struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
224         if (!el || el->num_values == 0) {
225                 return default_value;
226         }
227         return strtoul(el->values[0].data, NULL, 0);
228 }
229
230 double ldb_msg_find_double(const struct ldb_message *msg, 
231                            const char *attr_name,
232                            double default_value)
233 {
234         struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
235         if (!el || el->num_values == 0) {
236                 return default_value;
237         }
238         return strtod(el->values[0].data, NULL);
239 }
240
241 const char *ldb_msg_find_string(const struct ldb_message *msg, 
242                                 const char *attr_name,
243                                 const char *default_value)
244 {
245         struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
246         if (!el || el->num_values == 0) {
247                 return default_value;
248         }
249         return el->values[0].data;
250 }