SDDSlib
Loading...
Searching...
No Matches
sortfunctions.c
Go to the documentation of this file.
1/**
2 * @file sortfunctions.c
3 * @brief Useful routines for sorting, compatible with qsort()
4 *
5 * @copyright
6 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
7 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
8 *
9 * @license
10 * This file is distributed under the terms of the Software License Agreement
11 * found in the file LICENSE included with this distribution.
12 *
13 * @author M. Borland, C. Saunders, R. Soliday, H. Shang
14 */
15#include "mdb.h"
16#include "SDDS.h"
17
18/**
19 * @brief Compare two doubles in ascending order.
20 *
21 * This function compares two double values pointed to by `a` and `b`.
22 *
23 * @param a Pointer to the first double.
24 * @param b Pointer to the second double.
25 * @return int Returns -1 if *a < *b, 1 if *a > *b, and 0 if equal.
26 */
27int double_cmpasc(const void *a, const void *b) {
28 double diff;
29
30 diff = *((double *)b) - *((double *)a);
31 return (diff < 0 ? 1 : (diff > 0 ? -1 : 0));
32}
33
34/**
35 * @brief Compare the absolute values of two doubles in ascending order.
36 *
37 * This function compares the absolute values of two double values pointed to by `a` and `b`.
38 *
39 * @param a Pointer to the first double.
40 * @param b Pointer to the second double.
41 * @return int Returns -1 if |*a| < |*b|, 1 if |*a| > |*b|, and 0 if equal.
42 */
43int double_abs_cmpasc(const void *a, const void *b) {
44 double diff;
45
46 diff = fabs(*((double *)b)) - fabs(*((double *)a));
47 return (diff < 0 ? 1 : (diff > 0 ? -1 : 0));
48}
49
50/**
51 * @brief Compare two doubles in descending order.
52 *
53 * This function compares two double values pointed to by `a` and `b` in descending order.
54 *
55 * @param a Pointer to the first double.
56 * @param b Pointer to the second double.
57 * @return int Returns 1 if *a < *b, -1 if *a > *b, and 0 if equal.
58 */
59int double_cmpdes(const void *a, const void *b) {
60 double diff;
61
62 diff = *((double *)b) - *((double *)a);
63 return (diff > 0 ? 1 : (diff < 0 ? -1 : 0));
64}
65
66/**
67 * @brief Compare the absolute values of two doubles in descending order.
68 *
69 * This function compares the absolute values of two double values pointed to by `a` and `b` in descending order.
70 *
71 * @param a Pointer to the first double.
72 * @param b Pointer to the second double.
73 * @return int Returns 1 if |*a| < |*b|, -1 if |*a| > |*b|, and 0 if equal.
74 */
75int double_abs_cmpdes(const void *a, const void *b) {
76 double diff;
77
78 diff = fabs(*((double *)b)) - fabs(*((double *)a));
79 return (diff > 0 ? 1 : (diff < 0 ? -1 : 0));
80}
81
82void double_copy(void *a, void *b) {
83
84 *((double *)a) = *((double *)b);
85}
86
87int float_cmpasc(const void *a, const void *b) {
88 float diff;
89
90 diff = *((float *)b) - *((float *)a);
91 return (diff < 0 ? 1 : (diff > 0 ? -1 : 0));
92}
93
94int float_abs_cmpasc(const void *a, const void *b) {
95 float diff;
96
97 diff = fabsf(*((float *)b)) - fabsf(*((float *)a));
98 return (diff < 0 ? 1 : (diff > 0 ? -1 : 0));
99}
100
101int float_cmpdes(const void *a, const void *b) {
102 float diff;
103
104 diff = *((float *)b) - *((float *)a);
105 return (diff > 0 ? 1 : (diff < 0 ? -1 : 0));
106}
107
108int float_abs_cmpdes(const void *a, const void *b) {
109 float diff;
110
111 diff = fabsf(*((float *)b)) - fabsf(*((float *)a));
112 return (diff > 0 ? 1 : (diff < 0 ? -1 : 0));
113}
114
115void float_copy(void *a, void *b) {
116 *((float *)a) = *((float *)b);
117}
118
119/**
120 * @brief Compare two long integers in ascending order.
121 *
122 * This function compares two `int32_t` values pointed to by `a` and `b`.
123 *
124 * @param a Pointer to the first long integer.
125 * @param b Pointer to the second long integer.
126 * @return int Returns -1 if *a < *b, 1 if *a > *b, and 0 if equal.
127 */
128int long_cmpasc(const void *a, const void *b) {
129 int32_t diff;
130 diff = *((int32_t *)b) - *((int32_t *)a);
131 return (diff < 0 ? 1 : (diff > 0 ? -1 : 0));
132}
133
134/**
135 * @brief Compare the absolute values of two long integers in ascending order.
136 *
137 * This function compares the absolute values of two `int32_t` values pointed to by `a` and `b`.
138 *
139 * @param a Pointer to the first long integer.
140 * @param b Pointer to the second long integer.
141 * @return int Returns -1 if |*a| < |*b|, 1 if |*a| > |*b|, and 0 if equal.
142 */
143int long_abs_cmpasc(const void *a, const void *b) {
144 int32_t diff;
145 diff = labs(*((int32_t *)b)) - labs(*((int32_t *)a));
146 return (diff < 0 ? 1 : (diff > 0 ? -1 : 0));
147}
148
149int long_cmpdes(const void *a, const void *b) {
150 long diff;
151 diff = *((long *)a) - *((long *)b);
152 return (diff < 0 ? 1 : (diff > 0 ? -1 : 0));
153}
154
155int long_abs_cmpdes(const void *a, const void *b) {
156 long diff;
157 diff = labs(*((long *)a)) - labs(*((long *)b));
158 return (diff < 0 ? 1 : (diff > 0 ? -1 : 0));
159}
160
161void long_copy(void *a, void *b) {
162 *((long *)a) = *((long *)b);
163}
164
165/**
166 * @brief Compare two strings in ascending order.
167 *
168 * This function compares two null-terminated strings pointed to by `a` and `b` using `strcmp`.
169 *
170 * @param a Pointer to the first string.
171 * @param b Pointer to the second string.
172 * @return int Returns a negative value if *a < *b, a positive value if *a > *b, and 0 if equal.
173 */
174int string_cmpasc(const void *a, const void *b) {
175 return (strcmp(*((char **)a), *((char **)b)));
176}
177
178int string_cmpdes(const void *a, const void *b) {
179 return (strcmp(*((char **)b), *((char **)a)));
180}
181
182/**
183 * @brief Copy a string value.
184 *
185 * This function copies the string from the source pointed to by `b` to the destination pointed to by `a`.
186 * If the destination buffer is large enough, it uses `strcpy_ss`; otherwise, it allocates memory using `cp_str`.
187 *
188 * @param a Destination pointer where the string will be copied.
189 * @param b Source pointer from where the string will be copied.
190 */
191void string_copy(void *a, void *b) {
192 if ((long)strlen(*((char **)a)) >= (long)strlen(*((char **)b)))
193 strcpy_ss(*((char **)a), *((char **)b));
194 else
195 cp_str(((char **)a), *((char **)b));
196}
197
198/**
199 * @brief Remove duplicate elements from a sorted array.
200 *
201 * This function iterates through a sorted array and removes duplicate items based on the provided comparison function.
202 *
203 * @param base Pointer to the first element of the array.
204 * @param n_items Number of items in the array.
205 * @param size Size of each element in the array.
206 * @param compare Function pointer to the comparison function.
207 * @param copy Function pointer to the copy function.
208 * @return int Returns the new number of unique items in the array.
209 */
210int unique(void *base, size_t n_items, size_t size,
211 int (*compare)(const void *a, const void *b),
212 void (*copy)(void *a, void *b)) {
213 long i, j;
214
215 for (i = 0; i < n_items - 1; i++) {
216 if ((*compare)((char *)base + i * size, (char *)base + (i + 1) * size) == 0) {
217 for (j = i + 1; j < n_items - 1; j++)
218 (*copy)((char *)base + j * size, (char *)base + (j + 1) * size);
219 n_items--;
220 i--;
221 }
222 }
223 return (n_items);
224}
225
226static int (*item_compare)(const void *a, const void *b);
227static int column_to_compare;
228static int size_of_element;
229static int number_of_columns;
230
231/**
232 * @brief Set up parameters for row-based sorting.
233 *
234 * This function initializes the sorting parameters for sorting 2D data by rows based on a specified column.
235 *
236 * @param sort_by_column The column index to sort by.
237 * @param n_columns Total number of columns.
238 * @param element_size Size of each element in a row.
239 * @param compare Function pointer to the comparison function.
240 */
242 int sort_by_column,
243 size_t n_columns,
244 size_t element_size,
245 int (*compare)(const void *a, const void *b)) {
246 if ((column_to_compare = sort_by_column) >= (number_of_columns = n_columns))
247 bomb("column out of range in set_up_row_sort()", NULL);
248 size_of_element = element_size;
249 if (!(item_compare = compare))
250 bomb("null function pointer in set_up_row_sort()", NULL);
251}
252
253/**
254 * @brief Compare two rows based on the previously set sorting parameters.
255 *
256 * This static function is used internally to compare two rows during sorting.
257 *
258 * @param av Pointer to the first row.
259 * @param bv Pointer to the second row.
260 * @return int Result of the comparison.
261 */
262int row_compare(const void *av, const void *bv) {
263 char **a, **b;
264 a = (char **)av;
265 b = (char **)bv;
266 return ((*item_compare)(*a + size_of_element * column_to_compare,
267 *b + size_of_element * column_to_compare));
268}
269
270void row_copy(void *av, void *bv) {
271 void **a, **b;
272 void *ptr;
273 a = (void **)av;
274 b = (void **)bv;
275 ptr = *a;
276 *a = *b;
277 *b = ptr;
278}
279
280static long orderIndices; /* compare source indices if keys are identical? */
281
282/**
283 * @brief Compare two KEYED_INDEX structures based on string keys.
284 *
285 * This function compares two `KEYED_INDEX` structures using their `stringKey` fields.
286 * If the string keys are identical and `orderIndices` is set, it compares based on `rowIndex`.
287 *
288 * @param ki1 Pointer to the first KEYED_INDEX.
289 * @param ki2 Pointer to the second KEYED_INDEX.
290 * @return int Returns a negative value if ki1 < ki2, positive if ki1 > ki2, or based on `rowIndex` if keys are equal.
291 */
292int CompareStringKeyedIndex(const void *ki1, const void *ki2) {
293 int value;
294 if ((value = strcmp((*(const KEYED_INDEX *)ki1).stringKey, (*(const KEYED_INDEX *)ki2).stringKey)))
295 return value;
296 if (orderIndices)
297 return (*(const KEYED_INDEX *)ki1).rowIndex - (*(const KEYED_INDEX *)ki2).rowIndex;
298 return value;
299}
300
301/**
302 * @brief Compare two KEYED_INDEX structures based on double keys.
303 *
304 * This function compares two `KEYED_INDEX` structures using their `doubleKey` fields.
305 * If the double keys are identical and `orderIndices` is set, it compares based on `rowIndex`.
306 *
307 * @param ki1 Pointer to the first KEYED_INDEX.
308 * @param ki2 Pointer to the second KEYED_INDEX.
309 * @return int Returns -1 if ki1 < ki2, 1 if ki1 > ki2, or based on `rowIndex` if keys are equal.
310 */
311int CompareDoubleKeyedIndex(const void *ki1, const void *ki2) {
312 double diff;
313 if ((diff = (*(const KEYED_INDEX *)ki1).doubleKey - (*(const KEYED_INDEX *)ki2).doubleKey)) {
314 if (diff < 0)
315 return -1;
316 return 1;
317 }
318 if (orderIndices)
319 return (*(const KEYED_INDEX *)ki1).rowIndex - (*(const KEYED_INDEX *)ki2).rowIndex;
320 return 0;
321}
322
323/**
324 * @brief Compare two KEYED_EQUIVALENT groups based on string keys.
325 *
326 * This function compares the first string key of two `KEYED_EQUIVALENT` groups.
327 *
328 * @param kg1 Pointer to the first KEYED_EQUIVALENT group.
329 * @param kg2 Pointer to the second KEYED_EQUIVALENT group.
330 * @return int Returns the result of `strcmp` on the first string keys.
331 */
332int CompareStringKeyedGroup(const void *kg1, const void *kg2) {
333 return strcmp((*(KEYED_EQUIVALENT *)kg1).equivalent[0]->stringKey, (*(KEYED_EQUIVALENT *)kg2).equivalent[0]->stringKey);
334}
335
336/**
337 * @brief Compare two KEYED_EQUIVALENT groups based on double keys.
338 *
339 * This function compares the first double key of two `KEYED_EQUIVALENT` groups.
340 *
341 * @param kg1 Pointer to the first KEYED_EQUIVALENT group.
342 * @param kg2 Pointer to the second KEYED_EQUIVALENT group.
343 * @return int Returns -1 if kg1 < kg2, 1 if kg1 > kg2, or 0 if equal.
344 */
345int CompareDoubleKeyedGroup(const void *kg1, const void *kg2) {
346 double diff;
347 if ((diff = (*(KEYED_EQUIVALENT *)kg1).equivalent[0]->doubleKey - (*(KEYED_EQUIVALENT *)kg2).equivalent[0]->doubleKey)) {
348 if (diff < 0)
349 return -1;
350 return 1;
351 }
352 return 0;
353}
354
355/**
356 * @brief Create sorted key groups from data.
357 *
358 * This function generates sorted groups of keys from the provided data based on the specified key type.
359 *
360 * @param keyGroups Pointer to store the number of key groups created.
361 * @param keyType The type of key (e.g., SDDS_STRING or SDDS_DOUBLE).
362 * @param data Pointer to the data to be grouped.
363 * @param points Number of data points.
364 * @return KEYED_EQUIVALENT** Returns an array of pointers to `KEYED_EQUIVALENT` structures.
365 */
366KEYED_EQUIVALENT **MakeSortedKeyGroups(long *keyGroups, long keyType, void *data, long points) {
367 KEYED_EQUIVALENT **keyedEquiv = NULL;
368 static KEYED_INDEX *keyedIndex = NULL;
369 long iEquiv, i2, j;
370 long i1;
371
372 if (!points)
373 return 0;
374 if (keyedIndex)
375 free(keyedIndex);
376 if (!(keyedIndex = (KEYED_INDEX *)malloc(sizeof(*keyedIndex) * points)) ||
377 !(keyedEquiv = (KEYED_EQUIVALENT **)malloc(sizeof(*keyedEquiv) * points))) {
378 fprintf(stderr, "memory allocation failure");
379 exit(1);
380 }
381 if (keyType == SDDS_STRING) {
382 char **string;
383 string = data;
384 for (i1 = 0; i1 < points; i1++) {
385 keyedIndex[i1].stringKey = string[i1];
386 keyedIndex[i1].rowIndex = i1;
387 }
388 orderIndices = 1; /* subsort by source row index */
389 qsort((void *)keyedIndex, points, sizeof(*keyedIndex), CompareStringKeyedIndex);
390 orderIndices = 0; /* ignore index in comparisons */
391 for (iEquiv = i1 = 0; i1 < points; iEquiv++) {
392 for (i2 = i1 + 1; i2 < points; i2++) {
393 if (CompareStringKeyedIndex(keyedIndex + i1, keyedIndex + i2))
394 break;
395 }
396 if (!(keyedEquiv[iEquiv] = (KEYED_EQUIVALENT *)malloc(sizeof(KEYED_EQUIVALENT))) ||
397 !(keyedEquiv[iEquiv]->equivalent = (KEYED_INDEX **)malloc(sizeof(KEYED_INDEX *) * (i2 - i1)))) {
398 fprintf(stderr, "memory allocation failure");
399 exit(1);
400 }
401 keyedEquiv[iEquiv]->equivalents = i2 - i1;
402 keyedEquiv[iEquiv]->nextIndex = 0;
403 for (j = 0; i1 < i2; i1++, j++)
404 keyedEquiv[iEquiv]->equivalent[j] = keyedIndex + i1;
405 }
406 } else {
407 double *value;
408 value = data;
409 for (i1 = 0; i1 < points; i1++) {
410 keyedIndex[i1].doubleKey = value[i1];
411 keyedIndex[i1].rowIndex = i1;
412 }
413 orderIndices = 1; /* subsort by source row index */
414 qsort((void *)keyedIndex, points, sizeof(*keyedIndex), CompareDoubleKeyedIndex);
415 orderIndices = 0; /* ignore index in comparisons */
416 for (iEquiv = i1 = 0; i1 < points; iEquiv++) {
417 for (i2 = i1 + 1; i2 < points; i2++) {
418 if (CompareDoubleKeyedIndex(keyedIndex + i1, keyedIndex + i2))
419 break;
420 }
421 if (!(keyedEquiv[iEquiv] = (KEYED_EQUIVALENT *)malloc(sizeof(KEYED_EQUIVALENT))) ||
422 !(keyedEquiv[iEquiv]->equivalent = (KEYED_INDEX **)malloc(sizeof(KEYED_INDEX *) * (i2 - i1)))) {
423 fprintf(stderr, "memory allocation failure");
424 exit(1);
425 }
426 keyedEquiv[iEquiv]->equivalents = i2 - i1;
427 keyedEquiv[iEquiv]->nextIndex = 0;
428 for (j = 0; i1 < i2; i1++, j++)
429 keyedEquiv[iEquiv]->equivalent[j] = keyedIndex + i1;
430 }
431 }
432 *keyGroups = iEquiv;
433 return keyedEquiv;
434}
435
436/**
437 * @brief Find a matching key group for a search key.
438 *
439 * This function searches for a key group that matches the provided search key.
440 *
441 * @param keyGroup Array of key groups.
442 * @param keyGroups Number of key groups.
443 * @param keyType The type of key (e.g., SDDS_STRING or SDDS_DOUBLE).
444 * @param searchKeyData Pointer to the search key data.
445 * @param reuse Flag indicating whether to allow reuse of key groups.
446 * @return long Returns the row index of the matching key group or -1 if not found.
447 */
448long FindMatchingKeyGroup(KEYED_EQUIVALENT **keyGroup, long keyGroups, long keyType,
449 void *searchKeyData, long reuse) {
450 static KEYED_EQUIVALENT *searchKey = NULL;
451 static KEYED_INDEX keyedIndex;
452 long rowIndex, i;
453
454 if (!searchKey) {
455 searchKey = (KEYED_EQUIVALENT *)malloc(sizeof(*searchKey));
456 searchKey->equivalent = (KEYED_INDEX **)malloc(sizeof(*(searchKey->equivalent)));
457 searchKey->equivalent[0] = &keyedIndex;
458 searchKey->equivalents = 1;
459 }
460 if (keyType == SDDS_STRING) {
461 keyedIndex.stringKey = *(char **)searchKeyData;
462 i = binaryIndexSearch((void **)keyGroup, keyGroups, (void *)searchKey, CompareStringKeyedGroup, 0);
463 } else {
464 keyedIndex.doubleKey = *(double *)searchKeyData;
465 i = binaryIndexSearch((void **)keyGroup, keyGroups, (void *)searchKey, CompareDoubleKeyedGroup, 0);
466 }
467 if (i < 0 || keyGroup[i]->nextIndex >= keyGroup[i]->equivalents)
468 return -1;
469 rowIndex = keyGroup[i]->equivalent[keyGroup[i]->nextIndex]->rowIndex;
470 if (!reuse)
471 keyGroup[i]->nextIndex += 1;
472 return rowIndex;
473}
474
475/**
476 * @brief Sort data and return the sorted index.
477 *
478 * This function sorts the provided data based on the specified type and order, and returns an array of indices representing the sorted order.
479 *
480 * @param data Pointer to the data to be sorted.
481 * @param type The data type (e.g., SDDS_STRING, SDDS_DOUBLE).
482 * @param rows Number of rows in the data.
483 * @param increaseOrder If non-zero, sort in increasing order; otherwise, sort in decreasing order.
484 * @return long* Returns an array of indices representing the sorted order, or NULL on failure.
485 */
486long *sort_and_return_index(void *data, long type, long rows, long increaseOrder) {
487 long *index = NULL;
488 long i, keyGroups, i1, j, istart, jstart, i2, j2;
489 KEYED_EQUIVALENT **keyGroup;
490 char **tmpstring = NULL;
491 double *tmpdata = NULL;
492
493 if (!rows || !data)
494 return 0;
495 index = (long *)malloc(sizeof(*index) * rows);
496 switch (type) {
497 case SDDS_STRING:
498 tmpstring = (char **)data;
499 keyGroup = MakeSortedKeyGroups(&keyGroups, SDDS_STRING, tmpstring, rows);
500 break;
501 default:
502 if (type == SDDS_DOUBLE)
503 tmpdata = (double *)data;
504 else {
505 tmpdata = calloc(sizeof(*tmpdata), rows);
506 for (i = 0; i < rows; i++) {
507 switch (type) {
508 case SDDS_SHORT:
509 tmpdata[i] = *((short *)data + i);
510 break;
511 case SDDS_USHORT:
512 tmpdata[i] = *((unsigned short *)data + i);
513 break;
514 case SDDS_LONG:
515 tmpdata[i] = *((int32_t *)data + i);
516 break;
517 case SDDS_ULONG:
518 tmpdata[i] = *((uint32_t *)data + i);
519 break;
520 case SDDS_CHARACTER:
521 tmpdata[i] = *((unsigned char *)data + i);
522 break;
523 case SDDS_FLOAT:
524 tmpdata[i] = *((float *)data + i);
525 break;
526 default:
527 fprintf(stderr, "Invalid data type given!\n");
528 exit(1);
529 break;
530 }
531 }
532 }
533 keyGroup = MakeSortedKeyGroups(&keyGroups, SDDS_DOUBLE, tmpdata, rows);
534 if (type != SDDS_DOUBLE)
535 free(tmpdata);
536 break;
537 }
538 i1 = 0;
539 if (increaseOrder) {
540 istart = 0;
541 } else {
542 istart = keyGroups - 1;
543 }
544 for (i = istart, i2 = 0; i2 < keyGroups; i2++) {
545 if (increaseOrder) {
546 jstart = 0;
547 } else {
548 jstart = keyGroup[i]->equivalents - 1;
549 }
550 for (j = jstart, j2 = 0; j2 < keyGroup[i]->equivalents; j2++) {
551 switch (type) {
552 case SDDS_STRING:
553 ((char **)data)[i1] = keyGroup[i]->equivalent[j]->stringKey;
554 break;
555 case SDDS_DOUBLE:
556 ((double *)data)[i1] = keyGroup[i]->equivalent[j]->doubleKey;
557 break;
558 case SDDS_FLOAT:
559 ((float *)data)[i1] = (float)keyGroup[i]->equivalent[j]->doubleKey;
560 break;
561 case SDDS_LONG:
562 ((int32_t *)data)[i1] = (int32_t)keyGroup[i]->equivalent[j]->doubleKey;
563 break;
564 case SDDS_ULONG:
565 ((uint32_t *)data)[i1] = (uint32_t)keyGroup[i]->equivalent[j]->doubleKey;
566 break;
567 case SDDS_SHORT:
568 ((short *)data)[i1] = (short)keyGroup[i]->equivalent[j]->doubleKey;
569 break;
570 case SDDS_USHORT:
571 ((unsigned short *)data)[i1] = (unsigned short)keyGroup[i]->equivalent[j]->doubleKey;
572 break;
573 case SDDS_CHARACTER:
574 ((char *)data)[i1] = (unsigned char)keyGroup[i]->equivalent[j]->doubleKey;
575 break;
576 default:
577 fprintf(stderr, "Invalid data type given!\n");
578 exit(1);
579 break;
580 }
581 index[i1] = keyGroup[i]->equivalent[j]->rowIndex;
582 i1++;
583 if (increaseOrder)
584 j++;
585 else
586 j--;
587 }
588 if (increaseOrder)
589 i++;
590 else
591 i--;
592 }
593 for (i = 0; i < keyGroups; i++) {
594 free(keyGroup[i]->equivalent);
595 free(keyGroup[i]);
596 }
597 free(keyGroup);
598 return index;
599}
600
601/**
602 * @brief Compare two strings while skipping specified characters.
603 *
604 * This function compares two null-terminated strings `s1` and `s2`, ignoring any characters found in the `skip` string.
605 *
606 * @param s1 Pointer to the first string.
607 * @param s2 Pointer to the second string.
608 * @param skip String containing characters to be skipped during comparison.
609 * @return int Returns a negative value if `s1` < `s2`, a positive value if `s1` > `s2`, and 0 if equal.
610 */
611int strcmp_skip(const char *s1, const char *s2, const char *skip) {
612 do {
613 if (*s1 != *s2) {
614 while (*s1 && strchr(skip, *s1))
615 s1++;
616 while (*s2 && strchr(skip, *s2))
617 s2++;
618 if (*s1 != *s2)
619 return *s1 - *s2;
620 }
621 s1++;
622 s2++;
623 } while (*s1 && *s2);
624 return *s1 - *s2;
625}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
#define SDDS_ULONG
Identifier for the unsigned 32-bit integer data type.
Definition SDDStypes.h:67
#define SDDS_FLOAT
Identifier for the float data type.
Definition SDDStypes.h:43
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
Definition SDDStypes.h:61
#define SDDS_SHORT
Identifier for the signed short integer data type.
Definition SDDStypes.h:73
#define SDDS_CHARACTER
Identifier for the character data type.
Definition SDDStypes.h:91
#define SDDS_USHORT
Identifier for the unsigned short integer data type.
Definition SDDStypes.h:79
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
long binaryIndexSearch(void **array, long members, void *key, int(*compare)(const void *c1, const void *c2), long bracket)
Searches for a key in a sorted array of pointers using binary search.
Definition binsert.c:98
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
Definition bomb.c:26
char * cp_str(char **s, char *t)
Copies a string, allocating memory for storage.
Definition cp_str.c:28
int unique(void *base, size_t n_items, size_t size, int(*compare)(const void *a, const void *b), void(*copy)(void *a, void *b))
Remove duplicate elements from a sorted array.
int CompareDoubleKeyedIndex(const void *ki1, const void *ki2)
Compare two KEYED_INDEX structures based on double keys.
void set_up_row_sort(int sort_by_column, size_t n_columns, size_t element_size, int(*compare)(const void *a, const void *b))
Set up parameters for row-based sorting.
int double_abs_cmpasc(const void *a, const void *b)
Compare the absolute values of two doubles in ascending order.
KEYED_EQUIVALENT ** MakeSortedKeyGroups(long *keyGroups, long keyType, void *data, long points)
Create sorted key groups from data.
int double_cmpdes(const void *a, const void *b)
Compare two doubles in descending order.
int CompareStringKeyedIndex(const void *ki1, const void *ki2)
Compare two KEYED_INDEX structures based on string keys.
int long_cmpasc(const void *a, const void *b)
Compare two long integers in ascending order.
int double_cmpasc(const void *a, const void *b)
Compare two doubles in ascending order.
int CompareDoubleKeyedGroup(const void *kg1, const void *kg2)
Compare two KEYED_EQUIVALENT groups based on double keys.
long * sort_and_return_index(void *data, long type, long rows, long increaseOrder)
Sort data and return the sorted index.
int long_abs_cmpasc(const void *a, const void *b)
Compare the absolute values of two long integers in ascending order.
int CompareStringKeyedGroup(const void *kg1, const void *kg2)
Compare two KEYED_EQUIVALENT groups based on string keys.
int string_cmpasc(const void *a, const void *b)
Compare two strings in ascending order.
int row_compare(const void *av, const void *bv)
Compare two rows based on the previously set sorting parameters.
long FindMatchingKeyGroup(KEYED_EQUIVALENT **keyGroup, long keyGroups, long keyType, void *searchKeyData, long reuse)
Find a matching key group for a search key.
int double_abs_cmpdes(const void *a, const void *b)
Compare the absolute values of two doubles in descending order.
void string_copy(void *a, void *b)
Copy a string value.
int strcmp_skip(const char *s1, const char *s2, const char *skip)
Compare two strings while skipping specified characters.
char * strcpy_ss(char *dest, const char *src)
Safely copies a string, handling memory overlap.
Definition str_copy.c:34