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