1 /**
2 * sort.c -- functions related to sort functionality
3 * ______ ___
4 * / ____/___ / | _____________ __________
5 * / / __/ __ \/ /| |/ ___/ ___/ _ \/ ___/ ___/
6 * / /_/ / /_/ / ___ / /__/ /__/ __(__ |__ )
7 * \____/\____/_/ |_\___/\___/\___/____/____/
8 *
9 * The MIT License (MIT)
10 * Copyright (c) 2009-2020 Gerardo Orellana <hello @ goaccess.io>
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a copy
13 * of this software and associated documentation files (the "Software"), to deal
14 * in the Software without restriction, including without limitation the rights
15 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 * copies of the Software, and to permit persons to whom the Software is
17 * furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included in all
20 * copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 * SOFTWARE.
29 */
30
31 #if HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <getopt.h>
39 #include <errno.h>
40
41 #include "error.h"
42 #include "settings.h"
43 #include "util.h"
44
45 #include "sort.h"
46
47 /* *INDENT-OFF* */
48 const int sort_choices[][SORT_MAX_OPTS] = {
49 /* VISITORS */
50 {SORT_BY_HITS, SORT_BY_VISITORS, SORT_BY_DATA, SORT_BY_BW, SORT_BY_AVGTS, SORT_BY_CUMTS, SORT_BY_MAXTS, -1},
51 /* REQUESTS */
52 {SORT_BY_HITS, SORT_BY_VISITORS, SORT_BY_DATA, SORT_BY_BW, SORT_BY_AVGTS, SORT_BY_CUMTS, SORT_BY_MAXTS, SORT_BY_PROT, SORT_BY_MTHD, -1},
53 /* REQUESTS_STATIC */
54 {SORT_BY_HITS, SORT_BY_VISITORS, SORT_BY_DATA, SORT_BY_BW, SORT_BY_AVGTS, SORT_BY_CUMTS, SORT_BY_MAXTS, SORT_BY_PROT, SORT_BY_MTHD, -1},
55 /* NOT_FOUND */
56 {SORT_BY_HITS, SORT_BY_VISITORS, SORT_BY_DATA, SORT_BY_BW, SORT_BY_AVGTS, SORT_BY_CUMTS, SORT_BY_MAXTS, SORT_BY_PROT, SORT_BY_MTHD, -1},
57 /* HOSTS */
58 {SORT_BY_HITS, SORT_BY_VISITORS, SORT_BY_DATA, SORT_BY_BW, SORT_BY_AVGTS, SORT_BY_CUMTS, SORT_BY_MAXTS, -1},
59 /* OS */
60 {SORT_BY_HITS, SORT_BY_VISITORS, SORT_BY_DATA, SORT_BY_BW, SORT_BY_AVGTS, SORT_BY_CUMTS, SORT_BY_MAXTS, -1},
61 /* BROWSERS */
62 {SORT_BY_HITS, SORT_BY_VISITORS, SORT_BY_DATA, SORT_BY_BW, SORT_BY_AVGTS, SORT_BY_CUMTS, SORT_BY_MAXTS, -1},
63 /* VISIT_TIMES */
64 {SORT_BY_HITS, SORT_BY_VISITORS, SORT_BY_DATA, SORT_BY_BW, SORT_BY_AVGTS, SORT_BY_CUMTS, SORT_BY_MAXTS, -1},
65 /* VIRTUAL_HOSTS */
66 {SORT_BY_HITS, SORT_BY_VISITORS, SORT_BY_DATA, SORT_BY_BW, SORT_BY_AVGTS, SORT_BY_CUMTS, SORT_BY_MAXTS, -1},
67 /* REFERRERS */
68 {SORT_BY_HITS, SORT_BY_VISITORS, SORT_BY_DATA, SORT_BY_BW, SORT_BY_AVGTS, SORT_BY_CUMTS, SORT_BY_MAXTS, -1},
69 /* REFERRING_SITES */
70 {SORT_BY_HITS, SORT_BY_VISITORS, SORT_BY_DATA, SORT_BY_BW, SORT_BY_AVGTS, SORT_BY_CUMTS, SORT_BY_MAXTS, -1},
71 /* KEYPHRASES */
72 {SORT_BY_HITS, SORT_BY_VISITORS, SORT_BY_DATA, SORT_BY_BW, SORT_BY_AVGTS, SORT_BY_CUMTS, SORT_BY_MAXTS, -1},
73 /* STATUS_CODES */
74 {SORT_BY_HITS, SORT_BY_VISITORS, SORT_BY_DATA, SORT_BY_BW, SORT_BY_AVGTS, SORT_BY_CUMTS, SORT_BY_MAXTS, -1},
75 /* REMOTE_USER */
76 {SORT_BY_HITS, SORT_BY_VISITORS, SORT_BY_DATA, SORT_BY_BW, SORT_BY_AVGTS, SORT_BY_CUMTS, SORT_BY_MAXTS, -1},
77 /* CACHE_STATUS */
78 {SORT_BY_HITS, SORT_BY_VISITORS, SORT_BY_DATA, SORT_BY_BW, SORT_BY_AVGTS, SORT_BY_CUMTS, SORT_BY_MAXTS, -1},
79 #ifdef HAVE_GEOLOCATION
80 /* GEO_LOCATION */
81 {SORT_BY_HITS, SORT_BY_VISITORS, SORT_BY_DATA, SORT_BY_BW, SORT_BY_AVGTS, SORT_BY_CUMTS, SORT_BY_MAXTS, -1},
82 #endif
83 /* MIME_TYPE */
84 {SORT_BY_HITS, SORT_BY_DATA, SORT_BY_BW, SORT_BY_AVGTS, SORT_BY_CUMTS, SORT_BY_MAXTS, -1},
85 /* TLS_TYPE */
86 {SORT_BY_HITS, SORT_BY_DATA, SORT_BY_VISITORS, SORT_BY_BW, -1},
87 };
88
89 static GEnum FIELD[] = {
90 {"BY_HITS" , SORT_BY_HITS } ,
91 {"BY_VISITORS" , SORT_BY_VISITORS } ,
92 {"BY_DATA" , SORT_BY_DATA } ,
93 {"BY_BW" , SORT_BY_BW } ,
94 {"BY_AVGTS" , SORT_BY_AVGTS } ,
95 {"BY_CUMTS" , SORT_BY_CUMTS } ,
96 {"BY_MAXTS" , SORT_BY_MAXTS } ,
97 {"BY_PROT" , SORT_BY_PROT } ,
98 {"BY_MTHD" , SORT_BY_MTHD } ,
99 };
100
101 static GEnum ORDER[] = {
102 {"ASC" , SORT_ASC } ,
103 {"DESC" , SORT_DESC } ,
104 };
105
106 GSort module_sort[TOTAL_MODULES] = {
107 {VISITORS , SORT_BY_DATA , SORT_DESC } ,
108 {REQUESTS , SORT_BY_HITS , SORT_DESC } ,
109 {REQUESTS_STATIC , SORT_BY_HITS , SORT_DESC } ,
110 {NOT_FOUND , SORT_BY_HITS , SORT_DESC } ,
111 {HOSTS , SORT_BY_HITS , SORT_DESC } ,
112 {OS , SORT_BY_HITS , SORT_DESC } ,
113 {BROWSERS , SORT_BY_HITS , SORT_DESC } ,
114 {VISIT_TIMES , SORT_BY_DATA , SORT_ASC } ,
115 {VIRTUAL_HOSTS , SORT_BY_HITS , SORT_DESC } ,
116 {REFERRERS , SORT_BY_HITS , SORT_DESC } ,
117 {REFERRING_SITES , SORT_BY_HITS , SORT_DESC } ,
118 {KEYPHRASES , SORT_BY_HITS , SORT_DESC } ,
119 {STATUS_CODES , SORT_BY_HITS , SORT_DESC } ,
120 {REMOTE_USER , SORT_BY_HITS , SORT_DESC } ,
121 {CACHE_STATUS , SORT_BY_HITS , SORT_DESC } ,
122 #ifdef HAVE_GEOLOCATION
123 {GEO_LOCATION , SORT_BY_HITS , SORT_DESC } ,
124 #endif
125 {MIME_TYPE , SORT_BY_HITS , SORT_DESC } ,
126 {TLS_TYPE , SORT_BY_VISITORS , SORT_DESC } ,
127 };
128 /* *INDENT-ON* */
129
130 /* Sort an array of strings ascending */
131 int
strcmp_asc(const void * a,const void * b)132 strcmp_asc (const void *a, const void *b) {
133 return strcmp (*((char *const *) a), *((char *const *) b));
134 }
135
136 /* Sort 'data' metric ascending */
137 static int
cmp_data_asc(const void * a,const void * b)138 cmp_data_asc (const void *a, const void *b) {
139 const GHolderItem *ia = a;
140 const GHolderItem *ib = b;
141 return strcmp (ia->metrics->data, ib->metrics->data);
142 }
143
144 /* Sort 'data' metric descending */
145 static int
cmp_data_desc(const void * a,const void * b)146 cmp_data_desc (const void *a, const void *b) {
147 const GHolderItem *ia = a;
148 const GHolderItem *ib = b;
149 return strcmp (ib->metrics->data, ia->metrics->data);
150 }
151
152 /* Sort 'hits' metric descending */
153 static int
cmp_num_desc(const void * a,const void * b)154 cmp_num_desc (const void *a, const void *b) {
155 const GHolderItem *ia = a;
156 const GHolderItem *ib = b;
157
158 uint64_t va = ia->metrics->hits;
159 uint64_t vb = ib->metrics->hits;
160
161 return (va < vb) - (va > vb);
162 }
163
164 /* Sort 'hits' metric ascending */
165 static int
cmp_num_asc(const void * a,const void * b)166 cmp_num_asc (const void *a, const void *b) {
167 const GHolderItem *ia = a;
168 const GHolderItem *ib = b;
169
170 uint64_t va = ia->metrics->hits;
171 uint64_t vb = ib->metrics->hits;
172
173 return (va > vb) - (va < vb);
174 }
175
176 /* Sort 'visitors' metric descending */
177 static int
cmp_vis_desc(const void * a,const void * b)178 cmp_vis_desc (const void *a, const void *b) {
179 const GHolderItem *ia = a;
180 const GHolderItem *ib = b;
181
182 uint64_t va = ia->metrics->visitors;
183 uint64_t vb = ib->metrics->visitors;
184
185 return (va < vb) - (va > vb);
186 }
187
188 /* Sort 'visitors' metric ascending */
189 static int
cmp_vis_asc(const void * a,const void * b)190 cmp_vis_asc (const void *a, const void *b) {
191 const GHolderItem *ia = a;
192 const GHolderItem *ib = b;
193
194 uint64_t va = ia->metrics->visitors;
195 uint64_t vb = ib->metrics->visitors;
196
197 return (va > vb) - (va < vb);
198 }
199
200 /* Sort GRawDataItem value descending */
201 static int
cmp_raw_num_desc(const void * a,const void * b)202 cmp_raw_num_desc (const void *a, const void *b) {
203 const GRawDataItem *ia = a;
204 const GRawDataItem *ib = b;
205
206 uint64_t va = ia->hits;
207 uint64_t vb = ib->hits;
208
209 return (va < vb) - (va > vb);
210 }
211
212 /* Sort GRawDataItem value descending */
213 static int
cmp_raw_str_desc(const void * a,const void * b)214 cmp_raw_str_desc (const void *a, const void *b) {
215 const GRawDataItem *ia = a;
216 const GRawDataItem *ib = b;
217
218 return strcmp (ib->data, ia->data);
219 }
220
221 /* Sort 'bandwidth' metric descending */
222 static int
cmp_bw_desc(const void * a,const void * b)223 cmp_bw_desc (const void *a, const void *b) {
224 const GHolderItem *ia = a;
225 const GHolderItem *ib = b;
226
227 uint64_t va = ia->metrics->bw.nbw;
228 uint64_t vb = ib->metrics->bw.nbw;
229
230 return (va < vb) - (va > vb);
231 }
232
233 /* Sort 'bandwidth' metric ascending */
234 static int
cmp_bw_asc(const void * a,const void * b)235 cmp_bw_asc (const void *a, const void *b) {
236 const GHolderItem *ia = a;
237 const GHolderItem *ib = b;
238
239 uint64_t va = ia->metrics->bw.nbw;
240 uint64_t vb = ib->metrics->bw.nbw;
241
242 return (va > vb) - (va < vb);
243 }
244
245 /* Sort 'avgts' metric descending */
246 static int
cmp_avgts_desc(const void * a,const void * b)247 cmp_avgts_desc (const void *a, const void *b) {
248 const GHolderItem *ia = a;
249 const GHolderItem *ib = b;
250
251 uint64_t va = ia->metrics->avgts.nts;
252 uint64_t vb = ib->metrics->avgts.nts;
253
254 return (va < vb) - (va > vb);
255 }
256
257 /* Sort 'avgts' metric ascending */
258 static int
cmp_avgts_asc(const void * a,const void * b)259 cmp_avgts_asc (const void *a, const void *b) {
260 const GHolderItem *ia = a;
261 const GHolderItem *ib = b;
262
263 uint64_t va = ia->metrics->avgts.nts;
264 uint64_t vb = ib->metrics->avgts.nts;
265
266 return (va > vb) - (va < vb);
267 }
268
269 /* Sort 'cumts' metric descending */
270 static int
cmp_cumts_desc(const void * a,const void * b)271 cmp_cumts_desc (const void *a, const void *b) {
272 const GHolderItem *ia = a;
273 const GHolderItem *ib = b;
274
275 uint64_t va = ia->metrics->cumts.nts;
276 uint64_t vb = ib->metrics->cumts.nts;
277
278 return (va < vb) - (va > vb);
279 }
280
281 /* Sort 'cumts' metric ascending */
282 static int
cmp_cumts_asc(const void * a,const void * b)283 cmp_cumts_asc (const void *a, const void *b) {
284 const GHolderItem *ia = a;
285 const GHolderItem *ib = b;
286
287 uint64_t va = ia->metrics->cumts.nts;
288 uint64_t vb = ib->metrics->cumts.nts;
289
290 return (va > vb) - (va < vb);
291 }
292
293 /* Sort 'maxts' metric descending */
294 static int
cmp_maxts_desc(const void * a,const void * b)295 cmp_maxts_desc (const void *a, const void *b) {
296 const GHolderItem *ia = a;
297 const GHolderItem *ib = b;
298
299 uint64_t va = ia->metrics->maxts.nts;
300 uint64_t vb = ib->metrics->maxts.nts;
301
302 return (va < vb) - (va > vb);
303 }
304
305 /* Sort 'maxts' metric ascending */
306 static int
cmp_maxts_asc(const void * a,const void * b)307 cmp_maxts_asc (const void *a, const void *b) {
308 const GHolderItem *ia = a;
309 const GHolderItem *ib = b;
310
311 uint64_t va = ia->metrics->maxts.nts;
312 uint64_t vb = ib->metrics->maxts.nts;
313
314 return (va > vb) - (va < vb);
315 }
316
317 /* Sort 'protocol' metric ascending */
318 static int
cmp_proto_asc(const void * a,const void * b)319 cmp_proto_asc (const void *a, const void *b) {
320 const GHolderItem *ia = a;
321 const GHolderItem *ib = b;
322 return strcmp (ia->metrics->protocol, ib->metrics->protocol);
323 }
324
325 /* Sort 'protocol' metric descending */
326 static int
cmp_proto_desc(const void * a,const void * b)327 cmp_proto_desc (const void *a, const void *b) {
328 const GHolderItem *ia = a;
329 const GHolderItem *ib = b;
330 return strcmp (ib->metrics->protocol, ia->metrics->protocol);
331 }
332
333 /* Sort 'method' metric ascending */
334 static int
cmp_mthd_asc(const void * a,const void * b)335 cmp_mthd_asc (const void *a, const void *b) {
336 const GHolderItem *ia = a;
337 const GHolderItem *ib = b;
338 return strcmp (ia->metrics->method, ib->metrics->method);
339 }
340
341 /* Sort 'method' metric descending */
342 static int
cmp_mthd_desc(const void * a,const void * b)343 cmp_mthd_desc (const void *a, const void *b) {
344 const GHolderItem *ia = a;
345 const GHolderItem *ib = b;
346 return strcmp (ib->metrics->method, ia->metrics->method);
347 }
348
349 /* Sort ascending */
350 #if defined(__clang__) && defined(__clang_major__) && (__clang_major__ >= 4)
351 __attribute__((no_sanitize ("implicit-conversion", "unsigned-integer-overflow")))
352 #endif
cmp_ui32_asc(const void * a,const void * b)353 int cmp_ui32_asc (const void *a, const void *b) {
354 const uint32_t *ia = (const uint32_t *) a; // casting pointer types
355 const uint32_t *ib = (const uint32_t *) b;
356 return *ia - *ib;
357 }
358
359 int
cmp_ui32_desc(const void * a,const void * b)360 cmp_ui32_desc (const void *a, const void *b) {
361 const uint32_t *ia = (const uint32_t *) a; // casting pointer types
362 const uint32_t *ib = (const uint32_t *) b;
363 return *ib - *ia;
364 }
365
366 /* Given a string sort field, get the enum field value.
367 *
368 * On error, -1 is returned.
369 * On success, the enumerated field value is returned. */
370 int
get_sort_field_enum(const char * str)371 get_sort_field_enum (const char *str) {
372 return str2enum (FIELD, ARRAY_SIZE (FIELD), str);
373 }
374
375 /* Given a string sort order, get the enum order value.
376 *
377 * On error, -1 is returned.
378 * On success, the enumerated order value is returned. */
379 int
get_sort_order_enum(const char * str)380 get_sort_order_enum (const char *str) {
381 return str2enum (ORDER, ARRAY_SIZE (ORDER), str);
382 }
383
384 /* Given a GSortOrder enum value, return the corresponding string.
385 *
386 * The string corresponding to the enumerated order value is returned. */
387 const char *
get_sort_order_str(GSortOrder order)388 get_sort_order_str (GSortOrder order) {
389 return ORDER[order].str;
390 }
391
392 /* Given a GSortField enum value, return the corresponding string.
393 *
394 * The string corresponding to the enumerated field value is returned. */
395 const char *
get_sort_field_str(GSortField field)396 get_sort_field_str (GSortField field) {
397 return FIELD[field].str;
398 }
399
400 /* Given a GSortField enum value, return the corresponding key.
401 *
402 * The key corresponding to the enumerated field value is returned. */
403 const char *
get_sort_field_key(GSortField field)404 get_sort_field_key (GSortField field) {
405 static const char *field2key[][2] = {
406 {"BY_HITS", "hits"},
407 {"BY_VISITORS", "visitors"},
408 {"BY_DATA", "data"},
409 {"BY_BW", "bytes"},
410 {"BY_AVGTS", "avgts"},
411 {"BY_CUMTS", "cumts"},
412 {"BY_MAXTS", "maxts"},
413 {"BY_PROT", "protocol"},
414 {"BY_MTHD", "method"},
415 };
416
417 return field2key[field][1];
418 }
419
420 /* Set the initial metric sort per module/panel.
421 *
422 * On error, function returns.
423 * On success, panel metrics are sorted. */
424 void
set_initial_sort(const char * smod,const char * sfield,const char * ssort)425 set_initial_sort (const char *smod, const char *sfield, const char *ssort) {
426 int module, field, order;
427 if ((module = get_module_enum (smod)) == -1)
428 return;
429
430 if ((field = get_sort_field_enum (sfield)) == -1)
431 return;
432 if ((order = get_sort_order_enum (ssort)) == -1)
433 return;
434 if (!can_sort_module (module, field))
435 return;
436
437 module_sort[module].field = field;
438 module_sort[module].sort = order;
439 }
440
441 /* Determine if module/panel metric can be sorted.
442 *
443 * On error or if metric can't be sorted, 0 is returned.
444 * On success, 1 is returned. */
445 int
can_sort_module(GModule module,int field)446 can_sort_module (GModule module, int field) {
447 int i, can_sort = 0;
448 for (i = 0; -1 != sort_choices[module][i]; i++) {
449 if (sort_choices[module][i] != field)
450 continue;
451 if (SORT_BY_AVGTS == field && !conf.serve_usecs)
452 continue;
453 if (SORT_BY_CUMTS == field && !conf.serve_usecs)
454 continue;
455 if (SORT_BY_MAXTS == field && !conf.serve_usecs)
456 continue;
457 else if (SORT_BY_BW == field && !conf.bandwidth)
458 continue;
459 else if (SORT_BY_PROT == field && !conf.append_protocol)
460 continue;
461 else if (SORT_BY_MTHD == field && !conf.append_method)
462 continue;
463
464 can_sort = 1;
465 break;
466 }
467
468 return can_sort;
469 }
470
471 /* Parse all initial sort options from the config file.
472 *
473 * On error, function returns.
474 * On success, panel metrics are sorted. */
475 void
parse_initial_sort(void)476 parse_initial_sort (void) {
477 int i;
478 char module[SORT_MODULE_LEN], field[SORT_FIELD_LEN], order[SORT_ORDER_LEN];
479 for (i = 0; i < conf.sort_panel_idx; ++i) {
480 if (sscanf (conf.sort_panels[i], "%15[^','],%11[^','],%4s", module, field, order) != 3)
481 continue;
482 set_initial_sort (module, field, order);
483 }
484 }
485
486 /* Apply user defined sort */
487 void
sort_holder_items(GHolderItem * items,int size,GSort sort)488 sort_holder_items (GHolderItem * items, int size, GSort sort) {
489 switch (sort.field) {
490 case SORT_BY_HITS:
491 if (sort.sort == SORT_DESC)
492 qsort (items, size, sizeof (GHolderItem), cmp_num_desc);
493 else
494 qsort (items, size, sizeof (GHolderItem), cmp_num_asc);
495 break;
496 case SORT_BY_VISITORS:
497 if (sort.sort == SORT_DESC)
498 qsort (items, size, sizeof (GHolderItem), cmp_vis_desc);
499 else
500 qsort (items, size, sizeof (GHolderItem), cmp_vis_asc);
501 break;
502 case SORT_BY_DATA:
503 if (sort.sort == SORT_DESC)
504 qsort (items, size, sizeof (GHolderItem), cmp_data_desc);
505 else
506 qsort (items, size, sizeof (GHolderItem), cmp_data_asc);
507 break;
508 case SORT_BY_BW:
509 if (sort.sort == SORT_DESC)
510 qsort (items, size, sizeof (GHolderItem), cmp_bw_desc);
511 else
512 qsort (items, size, sizeof (GHolderItem), cmp_bw_asc);
513 break;
514 case SORT_BY_AVGTS:
515 if (sort.sort == SORT_DESC)
516 qsort (items, size, sizeof (GHolderItem), cmp_avgts_desc);
517 else
518 qsort (items, size, sizeof (GHolderItem), cmp_avgts_asc);
519 break;
520 case SORT_BY_CUMTS:
521 if (sort.sort == SORT_DESC)
522 qsort (items, size, sizeof (GHolderItem), cmp_cumts_desc);
523 else
524 qsort (items, size, sizeof (GHolderItem), cmp_cumts_asc);
525 break;
526 case SORT_BY_MAXTS:
527 if (sort.sort == SORT_DESC)
528 qsort (items, size, sizeof (GHolderItem), cmp_maxts_desc);
529 else
530 qsort (items, size, sizeof (GHolderItem), cmp_maxts_asc);
531 break;
532 case SORT_BY_PROT:
533 if (sort.sort == SORT_DESC)
534 qsort (items, size, sizeof (GHolderItem), cmp_proto_desc);
535 else
536 qsort (items, size, sizeof (GHolderItem), cmp_proto_asc);
537 break;
538 case SORT_BY_MTHD:
539 if (sort.sort == SORT_DESC)
540 qsort (items, size, sizeof (GHolderItem), cmp_mthd_desc);
541 else
542 qsort (items, size, sizeof (GHolderItem), cmp_mthd_asc);
543 break;
544 }
545 }
546
547 /* Sort raw numeric data in a descending order for the first run
548 * (default sort)
549 *
550 * On success, raw data sorted in a descending order. */
551 GRawData *
sort_raw_num_data(GRawData * raw_data,int ht_size)552 sort_raw_num_data (GRawData * raw_data, int ht_size) {
553 qsort (raw_data->items, ht_size, sizeof *(raw_data->items), cmp_raw_num_desc);
554 return raw_data;
555 }
556
557 /* Sort raw string data in a descending order for the first run.
558 *
559 * On success, raw data sorted in a descending order. */
560 GRawData *
sort_raw_str_data(GRawData * raw_data,int ht_size)561 sort_raw_str_data (GRawData * raw_data, int ht_size) {
562 qsort (raw_data->items, ht_size, sizeof *(raw_data->items), cmp_raw_str_desc);
563 return raw_data;
564 }
565