1 /*******************************************************************/
2
3 /* The following sort functions are trivial rewrites of merge-sort
4 * implementation by Simon Tatham
5 * copyright 2001 Simon Tatham.
6 *
7 * Permission is hereby granted, free of charge, to any person
8 * obtaining a copy of this software and associated documentation
9 * files (the "Software"), to deal in the Software without
10 * restriction, including without limitation the rights to use,
11 * copy, modify, merge, publish, distribute, sublicense, and/or
12 * sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following
14 * conditions:
15 *
16 * The above copyright notice and this permission notice shall be
17 * included in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NONINFRINGEMENT. IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
24 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
29 #include <cf3.defs.h>
30
31 #include <rlist.h>
32 #include <item_lib.h>
33 #include <ip_address.h>
34
35 typedef bool (*LessFn)(void *lhs, void *rhs, void *ctx);
36 typedef void * (*GetNextElementFn)(void *element);
37 typedef void (*PutNextElementFn)(void *element, void *next);
38
Sort(void * list,LessFn less,GetNextElementFn next,PutNextElementFn putnext,void * ctx)39 static void *Sort(void *list, LessFn less, GetNextElementFn next, PutNextElementFn putnext, void *ctx)
40 {
41 void *p, *q, *e, *tail;
42 int insize, nmerges, psize, qsize, i;
43
44 if (list == NULL)
45 {
46 return NULL;
47 }
48
49 insize = 1;
50
51 while (true)
52 {
53 p = list;
54 list = NULL;
55 tail = NULL;
56
57 nmerges = 0; /* count number of merges we do in this pass */
58
59 while (p)
60 {
61 nmerges++; /* there exists a merge to be done */
62 /* step `insize' places along from p */
63 q = p;
64 psize = 0;
65
66 for (i = 0; i < insize; i++)
67 {
68 psize++;
69
70 q = next(q);
71
72 if (!q)
73 {
74 break;
75 }
76 }
77
78 /* if q hasn't fallen off end, we have two lists to merge */
79 qsize = insize;
80
81 /* now we have two lists; merge them */
82 while ((psize > 0) || ((qsize > 0) && q))
83 {
84 /* decide whether next element of merge comes from p or q */
85 if (psize == 0)
86 {
87 /* p is empty; e must come from q. */
88 e = q;
89 q = next(q);
90 qsize--;
91 }
92 else if ((qsize == 0) || (!q))
93 {
94 /* q is empty; e must come from p. */
95 e = p;
96 p = next(p);
97 psize--;
98 }
99 else if (less(p, q, ctx))
100 {
101 /* First element of p is lower (or same);
102 * e must come from p. */
103 e = p;
104 p = next(p);
105 psize--;
106 }
107 else
108 {
109 /* First element of q is lower; e must come from q. */
110 e = q;
111 q = next(q);
112 qsize--;
113 }
114
115 /* add the next element to the merged list */
116 if (tail)
117 {
118 putnext(tail, e);
119 }
120 else
121 {
122 list = e;
123 }
124
125 tail = e;
126 }
127
128 /* now p has stepped `insize' places along, and q has too */
129 p = q;
130 }
131
132 putnext(tail, NULL);
133
134 /* If we have done only one merge, we're finished. */
135
136 if (nmerges <= 1) /* allow for nmerges==0, the empty list case */
137 {
138 return list;
139 }
140
141 /* Otherwise repeat, merging lists twice the size */
142 insize *= 2;
143 }
144 }
145
146 /* Item* callbacks */
147
ItemNameLess(void * lhs,void * rhs,ARG_UNUSED void * ctx)148 static bool ItemNameLess(void *lhs, void *rhs, ARG_UNUSED void *ctx)
149 {
150 return strcmp(((Item*)lhs)->name, ((Item*)rhs)->name) < 0;
151 }
152
ItemClassesLess(void * lhs,void * rhs,ARG_UNUSED void * ctx)153 static bool ItemClassesLess(void *lhs, void *rhs, ARG_UNUSED void *ctx)
154 {
155 return strcmp(((Item*)lhs)->classes, ((Item*)rhs)->classes) < 0;
156 }
157
ItemCounterMore(void * lhs,void * rhs,ARG_UNUSED void * ctx)158 static bool ItemCounterMore(void *lhs, void *rhs, ARG_UNUSED void *ctx)
159 {
160 return ((Item*)lhs)->counter > ((Item*)rhs)->counter;
161 }
162
ItemTimeMore(void * lhs,void * rhs,ARG_UNUSED void * ctx)163 static bool ItemTimeMore(void *lhs, void *rhs, ARG_UNUSED void *ctx)
164 {
165 return ((Item*)lhs)->time > ((Item*)rhs)->time;
166 }
167
ItemGetNext(void * element)168 static void *ItemGetNext(void *element)
169 {
170 return ((Item*)element)->next;
171 }
172
ItemPutNext(void * element,void * next)173 static void ItemPutNext(void *element, void *next)
174 {
175 ((Item*)element)->next = (Item *)next;
176 }
177
178 /* Item* sorting */
179
SortItemListNames(Item * list)180 Item *SortItemListNames(Item *list)
181 {
182 return Sort(list, &ItemNameLess, &ItemGetNext, &ItemPutNext, NULL);
183 }
184
SortItemListClasses(Item * list)185 Item *SortItemListClasses(Item *list)
186 {
187 return Sort(list, &ItemClassesLess, &ItemGetNext, &ItemPutNext, NULL);
188 }
189
SortItemListCounters(Item * list)190 Item *SortItemListCounters(Item *list)
191 {
192 return Sort(list, &ItemCounterMore, &ItemGetNext, &ItemPutNext, NULL);
193 }
194
SortItemListTimes(Item * list)195 Item *SortItemListTimes(Item *list)
196 {
197 return Sort(list, &ItemTimeMore, &ItemGetNext, &ItemPutNext, NULL);
198 }
199
200 /* Rlist* and String* callbacks */
201
RlistCustomItemLess(void * lhs_,void * rhs_,void * ctx)202 static bool RlistCustomItemLess(void *lhs_, void *rhs_, void *ctx)
203 {
204 Rlist *lhs = lhs_;
205 Rlist *rhs = rhs_;
206 bool (*cmp)() = ctx;
207
208 return (*cmp)(lhs->val.item, rhs->val.item);
209 }
210
RlistItemLess(void * lhs,void * rhs,ARG_UNUSED void * ctx)211 static bool RlistItemLess(void *lhs, void *rhs, ARG_UNUSED void *ctx)
212 {
213 return strcmp(((Rlist*)lhs)->val.item, ((Rlist*)rhs)->val.item) < 0;
214 }
215
StringItemLess(const char * lhs,const char * rhs,ARG_UNUSED void * ctx)216 static bool StringItemLess(const char *lhs, const char *rhs, ARG_UNUSED void *ctx)
217 {
218 return strcmp(lhs, rhs) < 0;
219 }
220
StringItemNumberLess(const char * lhs,const char * rhs,ARG_UNUSED void * ctx,bool int_mode)221 static bool StringItemNumberLess(const char *lhs, const char *rhs, ARG_UNUSED void *ctx, bool int_mode)
222 {
223 char remainder[4096];
224 double left;
225 double right;
226
227 bool matched_left = sscanf(lhs, "%lf", &left) > 0;
228 bool matched_right = sscanf(rhs, "%lf", &right) > 0;
229
230 if (!matched_left)
231 {
232 matched_left = sscanf(lhs, "%lf%4095s", &left, remainder) > 0;
233 }
234
235 if (!matched_right)
236 {
237 matched_right = sscanf(rhs, "%lf%4095s", &right, remainder) > 0;
238 }
239
240 if (matched_left && matched_right)
241 {
242 if (int_mode)
243 {
244 return ((long int)left) - ((long int)right) < 0;
245 }
246 else
247 {
248 return left - right < 0;
249 }
250 }
251
252 if (matched_left)
253 {
254 return false;
255 }
256
257 if (matched_right)
258 {
259 return true;
260 }
261
262 // neither item matched
263 return StringItemLess(lhs, rhs, ctx);
264 }
265
RlistItemNumberLess(void * lhs,void * rhs,ARG_UNUSED void * ctx,bool int_mode)266 static bool RlistItemNumberLess(void *lhs, void *rhs, ARG_UNUSED void *ctx, bool int_mode)
267 {
268 return StringItemNumberLess(RlistScalarValue((Rlist*)lhs), RlistScalarValue((Rlist*)rhs), ctx, int_mode);
269 }
270
RlistItemIntLess(void * lhs,void * rhs,ARG_UNUSED void * ctx)271 static bool RlistItemIntLess(void *lhs, void *rhs, ARG_UNUSED void *ctx)
272 {
273 return RlistItemNumberLess(lhs, rhs, ctx, true);
274 }
275
RlistItemRealLess(void * lhs,void * rhs,ARG_UNUSED void * ctx)276 static bool RlistItemRealLess(void *lhs, void *rhs, ARG_UNUSED void *ctx)
277 {
278 return RlistItemNumberLess(lhs, rhs, ctx, false);
279 }
280
StringItemIPLess(const char * left_item,const char * right_item,ARG_UNUSED void * ctx)281 static bool StringItemIPLess(const char *left_item, const char *right_item, ARG_UNUSED void *ctx)
282 {
283 Buffer *left_buffer = BufferNewFrom(left_item, strlen(left_item));
284 Buffer *right_buffer = BufferNewFrom(right_item, strlen(right_item));
285
286 IPAddress *left = IPAddressNew(left_buffer);
287 IPAddress *right = IPAddressNew(right_buffer);
288
289 bool matched_left = (left != NULL);
290 bool matched_right = (right != NULL);
291
292 BufferDestroy(left_buffer);
293 BufferDestroy(right_buffer);
294
295 if (matched_left && matched_right)
296 {
297 bool less = IPAddressCompareLess(left, right);
298 IPAddressDestroy(&left);
299 IPAddressDestroy(&right);
300 return less;
301 }
302
303 IPAddressDestroy(&left);
304 IPAddressDestroy(&right);
305
306 if (matched_left)
307 {
308 return false;
309 }
310
311 if (matched_right)
312 {
313 return true;
314 }
315
316 // neither item matched
317 return StringItemLess(left_item, right_item, ctx);
318 }
319
RlistItemIPLess(void * lhs,void * rhs,ARG_UNUSED void * ctx)320 static bool RlistItemIPLess(void *lhs, void *rhs, ARG_UNUSED void *ctx)
321 {
322 return StringItemIPLess(RlistScalarValue((Rlist*)lhs), RlistScalarValue((Rlist*)rhs), ctx);
323 }
324
ParseEtherAddress(const char * input,unsigned char * addr)325 static long ParseEtherAddress(const char* input, unsigned char *addr)
326 {
327 if (strlen(input) > 12)
328 {
329 return sscanf(input, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
330 &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]);
331 }
332
333 return sscanf(input, "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
334 &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]);
335 }
336
StringItemMACLess(const char * lhs,const char * rhs,ARG_UNUSED void * ctx)337 static bool StringItemMACLess(const char *lhs, const char *rhs, ARG_UNUSED void *ctx)
338 {
339 int bytes = 6;
340 unsigned char left[bytes], right[bytes];
341 int matched_left = (ParseEtherAddress(lhs, left) == 6);
342 int matched_right = (ParseEtherAddress(rhs, right) == 6);;
343
344 if (matched_left && matched_right)
345 {
346 int difference = memcmp(left, right, bytes);
347 if (difference != 0) return difference < 0;
348 }
349
350 if (matched_left)
351 {
352 return false;
353 }
354
355 if (matched_right)
356 {
357 return true;
358 }
359
360 // neither item matched
361 return StringItemLess(lhs, rhs, ctx);
362 }
363
RlistItemMACLess(void * lhs,void * rhs,ARG_UNUSED void * ctx)364 static bool RlistItemMACLess(void *lhs, void *rhs, ARG_UNUSED void *ctx)
365 {
366 return StringItemMACLess(RlistScalarValue((Rlist*)lhs), RlistScalarValue((Rlist*)rhs), ctx);
367 }
368
RlistGetNext(void * element)369 static void *RlistGetNext(void *element)
370 {
371 return ((Rlist*)element)->next;
372 }
373
RlistPutNext(void * element,void * next)374 static void RlistPutNext(void *element, void *next)
375 {
376 ((Rlist*)element)->next = (Rlist *)next;
377 }
378
379 /* Rlist* sorting */
380
SortRlist(Rlist * list,bool (* CompareItems)())381 Rlist *SortRlist(Rlist *list, bool (*CompareItems) ())
382 {
383 return Sort(list, &RlistCustomItemLess, &RlistGetNext, &RlistPutNext, CompareItems);
384 }
385
AlphaSortRListNames(Rlist * list)386 Rlist *AlphaSortRListNames(Rlist *list)
387 {
388 return Sort(list, &RlistItemLess, &RlistGetNext, &RlistPutNext, NULL);
389 }
390
IntSortRListNames(Rlist * list)391 Rlist *IntSortRListNames(Rlist *list)
392 {
393 return Sort(list, &RlistItemIntLess, &RlistGetNext, &RlistPutNext, NULL);
394 }
395
RealSortRListNames(Rlist * list)396 Rlist *RealSortRListNames(Rlist *list)
397 {
398 return Sort(list, &RlistItemRealLess, &RlistGetNext, &RlistPutNext, NULL);
399 }
400
IPSortRListNames(Rlist * list)401 Rlist *IPSortRListNames(Rlist *list)
402 {
403 return Sort(list, &RlistItemIPLess, &RlistGetNext, &RlistPutNext, NULL);
404 }
405
MACSortRListNames(Rlist * list)406 Rlist *MACSortRListNames(Rlist *list)
407 {
408 return Sort(list, &RlistItemMACLess, &RlistGetNext, &RlistPutNext, NULL);
409 }
410
GenericItemLess(const char * sort_type,void * lhs,void * rhs)411 bool GenericItemLess(const char *sort_type, void *lhs, void *rhs)
412 {
413 if (strcmp(sort_type, "int") == 0)
414 {
415 return RlistItemNumberLess(lhs, rhs, NULL, true);
416 }
417 else if (strcmp(sort_type, "real") == 0)
418 {
419 return RlistItemNumberLess(lhs, rhs, NULL, false);
420 }
421 else if (strcasecmp(sort_type, "IP") == 0)
422 {
423 return RlistItemIPLess(lhs, rhs, NULL);
424 }
425 else if (strcasecmp(sort_type, "MAC") == 0)
426 {
427 return RlistItemMACLess(lhs, rhs, NULL);
428 }
429
430 // "lex"
431 return RlistItemLess(lhs, rhs, NULL);
432 }
433
GenericStringItemLess(const char * sort_type,const char * lhs,const char * rhs)434 bool GenericStringItemLess(const char *sort_type, const char *lhs, const char *rhs)
435 {
436 if (strcmp(sort_type, "int") == 0)
437 {
438 return StringItemNumberLess(lhs, rhs, NULL, true);
439 }
440 else if (strcmp(sort_type, "real") == 0)
441 {
442 return StringItemNumberLess(lhs, rhs, NULL, false);
443 }
444 else if (strcasecmp(sort_type, "IP") == 0)
445 {
446 return StringItemIPLess(lhs, rhs, NULL);
447 }
448 else if (strcasecmp(sort_type, "MAC") == 0)
449 {
450 return StringItemMACLess(lhs, rhs, NULL);
451 }
452
453 // "lex"
454 return StringItemLess(lhs, rhs, NULL);
455 }
456