]>
git.cameronkatri.com Git - apple_cmds.git/blob - text_cmds/sort/coll.c
2 * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
3 * Copyright (C) 2012 Oleg Moskalenko <mom040267@gmail.com>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/types.h>
49 struct key_specs
*keys
;
52 wint_t symbol_decimal_point
= L
'.';
53 /* there is no default thousands separator in collate rules: */
54 wint_t symbol_thousands_sep
= 0;
55 wint_t symbol_negative_sign
= L
'-';
56 wint_t symbol_positive_sign
= L
'+';
58 static int wstrcoll(struct key_value
*kv1
, struct key_value
*kv2
, size_t offset
);
59 static int gnumcoll(struct key_value
*, struct key_value
*, size_t offset
);
60 static int monthcoll(struct key_value
*, struct key_value
*, size_t offset
);
61 static int numcoll(struct key_value
*, struct key_value
*, size_t offset
);
62 static int hnumcoll(struct key_value
*, struct key_value
*, size_t offset
);
63 static int randomcoll(struct key_value
*, struct key_value
*, size_t offset
);
64 static int versioncoll(struct key_value
*, struct key_value
*, size_t offset
);
70 keys_array_alloc(void)
72 struct keys_array
*ka
;
75 sz
= keys_array_size();
83 * Calculate whether we need key hint space
89 return (need_hint
? sizeof(struct key_hint
) : 0);
93 * Calculate keys array size
99 return (keys_num
* (sizeof(struct key_value
) + key_hint_size()));
103 * Clean data of keys array
106 clean_keys_array(const struct bwstring
*s
, struct keys_array
*ka
)
110 for (size_t i
= 0; i
< keys_num
; ++i
) {
111 const struct key_value
*kv
;
113 kv
= get_key_from_keys_array(ka
, i
);
114 if (kv
->k
&& kv
->k
!= s
)
117 memset(ka
, 0, keys_array_size());
122 * Get pointer to a key value in the keys set
125 get_key_from_keys_array(struct keys_array
*ka
, size_t ind
)
128 return ((struct key_value
*)((caddr_t
)ka
->key
+
129 ind
* (sizeof(struct key_value
) + key_hint_size())));
133 * Set value of a key in the keys set
136 set_key_on_keys_array(struct keys_array
*ka
, struct bwstring
*s
, size_t ind
)
139 if (ka
&& keys_num
> ind
) {
140 struct key_value
*kv
;
142 kv
= get_key_from_keys_array(ka
, ind
);
144 if (kv
->k
&& kv
->k
!= s
)
151 * Initialize a sort list item
153 struct sort_list_item
*
154 sort_list_item_alloc(void)
156 struct sort_list_item
*si
;
159 sz
= sizeof(struct sort_list_item
) + keys_array_size();
160 si
= sort_malloc(sz
);
167 sort_list_item_size(struct sort_list_item
*si
)
172 ret
= sizeof(struct sort_list_item
) + keys_array_size();
174 ret
+= bws_memsize(si
->str
);
175 for (size_t i
= 0; i
< keys_num
; ++i
) {
176 const struct key_value
*kv
;
178 kv
= get_key_from_keys_array(&si
->ka
, i
);
180 if (kv
->k
!= si
->str
)
181 ret
+= bws_memsize(kv
->k
);
188 * Calculate key for a sort list item
191 sort_list_item_make_key(struct sort_list_item
*si
)
194 preproc(si
->str
, &(si
->ka
));
198 * Set value of a sort list item.
199 * Return combined string and keys memory size.
202 sort_list_item_set(struct sort_list_item
*si
, struct bwstring
*str
)
206 clean_keys_array(si
->str
, &(si
->ka
));
208 if (si
->str
== str
) {
209 /* we are trying to reset the same string */
217 sort_list_item_make_key(si
);
222 * De-allocate a sort list item object memory
225 sort_list_item_clean(struct sort_list_item
*si
)
229 clean_keys_array(si
->str
, &(si
->ka
));
238 * Skip columns according to specs
241 skip_cols_to_start(const struct bwstring
*s
, size_t cols
, size_t start
,
242 bool skip_blanks
, bool *empty_key
)
245 return (BWSLEN(s
) + 1);
248 while (start
< BWSLEN(s
) && iswblank_f(BWS_GET(s
,start
)))
251 while (start
< BWSLEN(s
) && cols
> 1) {
256 if (start
>= BWSLEN(s
))
263 * Skip fields according to specs
266 skip_fields_to_start(const struct bwstring
*s
, size_t fields
, bool *empty_field
)
273 } else if (!(sort_opts_vals
.tflag
)) {
277 while (cpos
< BWSLEN(s
)) {
280 isblank
= iswblank_f(BWS_GET(s
, cpos
));
282 if (isblank
&& !pb
) {
296 while (cpos
< BWSLEN(s
)) {
297 if (BWS_GET(s
,cpos
) == (wchar_t)sort_opts_vals
.field_sep
) {
314 find_field_start(const struct bwstring
*s
, struct key_specs
*ks
,
315 size_t *field_start
, size_t *key_start
, bool *empty_field
, bool *empty_key
)
318 *field_start
= skip_fields_to_start(s
, ks
->f1
, empty_field
);
320 *key_start
= skip_cols_to_start(s
, ks
->c1
, *field_start
,
321 ks
->pos1b
, empty_key
);
327 * Find end key position
330 find_field_end(const struct bwstring
*s
, struct key_specs
*ks
)
332 size_t f2
, next_field_start
, pos_end
;
333 bool empty_field
, empty_key
;
340 return (BWSLEN(s
) + 1);
343 next_field_start
= skip_fields_to_start(s
, f2
+ 1,
345 if ((next_field_start
> 0) && sort_opts_vals
.tflag
&&
346 ((wchar_t)sort_opts_vals
.field_sep
== BWS_GET(s
,
347 next_field_start
- 1)))
350 next_field_start
= skip_fields_to_start(s
, f2
,
354 if (empty_field
|| (next_field_start
>= BWSLEN(s
)))
355 return (BWSLEN(s
) + 1);
358 pos_end
= skip_cols_to_start(s
, ks
->c2
, next_field_start
,
359 ks
->pos2b
, &empty_key
);
360 if (pos_end
< BWSLEN(s
))
363 pos_end
= next_field_start
;
369 * Cut a field according to the key specs
371 static struct bwstring
*
372 cut_field(const struct bwstring
*s
, struct key_specs
*ks
)
374 struct bwstring
*ret
= NULL
;
377 size_t field_start
, key_end
, key_start
, sz
;
378 bool empty_field
, empty_key
;
385 find_field_start(s
, ks
, &field_start
, &key_start
,
386 &empty_field
, &empty_key
);
391 key_end
= find_field_end(s
, ks
);
392 sz
= (key_end
< key_start
) ? 0 : (key_end
- key_start
);
397 bwsnocpy(ret
, s
, key_start
, sz
);
405 * Preprocesses a line applying the necessary transformations
406 * specified by command line options and returns the preprocessed
407 * string, which can be used to compare.
410 preproc(struct bwstring
*s
, struct keys_array
*ka
)
413 if (sort_opts_vals
.kflag
)
414 for (size_t i
= 0; i
< keys_num
; i
++) {
415 struct bwstring
*key
;
416 struct key_specs
*kspecs
;
417 struct sort_mods
*sm
;
420 key
= cut_field(s
, kspecs
);
424 key
= dictionary_order(key
);
426 key
= ignore_nonprinting(key
);
427 if (sm
->fflag
|| sm
->Mflag
)
428 key
= ignore_case(key
);
430 set_key_on_keys_array(ka
, key
, i
);
433 struct bwstring
*ret
= NULL
;
434 struct sort_mods
*sm
= default_sort_mods
;
439 ret
= ignore_leading_blanks(ret
);
444 ret
= dictionary_order(ret
);
445 } else if (sm
->iflag
) {
448 ret
= ignore_nonprinting(ret
);
450 if (sm
->fflag
|| sm
->Mflag
) {
453 ret
= ignore_case(ret
);
456 set_key_on_keys_array(ka
, s
, 0);
458 set_key_on_keys_array(ka
, ret
, 0);
465 get_sort_func(struct sort_mods
*sm
)
479 return (versioncoll
);
485 * Compares the given strings. Returns a positive number if
486 * the first precedes the second, a negative number if the second is
487 * the preceding one, and zero if they are equal. This function calls
488 * the underlying collate functions, which done the actual comparison.
491 key_coll(struct keys_array
*ps1
, struct keys_array
*ps2
, size_t offset
)
493 struct key_value
*kv1
, *kv2
;
494 struct sort_mods
*sm
;
497 for (size_t i
= 0; i
< keys_num
; ++i
) {
498 kv1
= get_key_from_keys_array(ps1
, i
);
499 kv2
= get_key_from_keys_array(ps2
, i
);
503 res
= sm
->func(kv2
, kv1
, offset
);
505 res
= sm
->func(kv1
, kv2
, offset
);
510 /* offset applies to only the first key */
517 * Compare two strings.
518 * Plain symbol-by-symbol comparison.
521 top_level_str_coll(const struct bwstring
*s1
, const struct bwstring
*s2
)
524 if (default_sort_mods
->rflag
) {
525 const struct bwstring
*tmp
;
532 return (bwscoll(s1
, s2
, 0));
536 * Compare a string and a sort list item, according to the sort specs.
539 str_list_coll(struct bwstring
*str1
, struct sort_list_item
**ss2
)
541 struct keys_array
*ka1
;
544 ka1
= keys_array_alloc();
548 sort_list_item_make_key(*ss2
);
551 bwsprintf(stdout
, str1
, "; s1=<", ">");
552 bwsprintf(stdout
, (*ss2
)->str
, ", s2=<", ">");
555 ret
= key_coll(ka1
, &((*ss2
)->ka
), 0);
558 printf("; cmp1=%d", ret
);
560 clean_keys_array(str1
, ka1
);
563 if ((ret
== 0) && !(sort_opts_vals
.sflag
) && sort_opts_vals
.complex_sort
) {
564 ret
= top_level_str_coll(str1
, ((*ss2
)->str
));
566 printf("; cmp2=%d", ret
);
576 * Compare two sort list items, according to the sort specs.
579 list_coll_offset(struct sort_list_item
**ss1
, struct sort_list_item
**ss2
,
584 ret
= key_coll(&((*ss1
)->ka
), &((*ss2
)->ka
), offset
);
588 printf("; offset=%d", (int) offset
);
589 bwsprintf(stdout
, ((*ss1
)->str
), "; s1=<", ">");
590 bwsprintf(stdout
, ((*ss2
)->str
), ", s2=<", ">");
591 printf("; cmp1=%d\n", ret
);
597 if (!(sort_opts_vals
.sflag
) && sort_opts_vals
.complex_sort
) {
598 ret
= top_level_str_coll(((*ss1
)->str
), ((*ss2
)->str
));
600 printf("; cmp2=%d\n", ret
);
607 * Compare two sort list items, according to the sort specs.
610 list_coll(struct sort_list_item
**ss1
, struct sort_list_item
**ss2
)
613 return (list_coll_offset(ss1
, ss2
, 0));
618 list_coll_##N(struct sort_list_item **ss1, struct sort_list_item **ss2) \
621 return (list_coll_offset(ss1, ss2, N)); \
646 get_list_call_func(size_t offset
)
648 static const listcoll_t lsarray
[] = { list_coll
, list_coll_1
,
649 list_coll_2
, list_coll_3
, list_coll_4
, list_coll_5
,
650 list_coll_6
, list_coll_7
, list_coll_8
, list_coll_9
,
651 list_coll_10
, list_coll_11
, list_coll_12
, list_coll_13
,
652 list_coll_14
, list_coll_15
, list_coll_16
, list_coll_17
,
653 list_coll_18
, list_coll_19
, list_coll_20
};
656 return (lsarray
[offset
]);
662 * Compare two sort list items, only by their original string.
665 list_coll_by_str_only(struct sort_list_item
**ss1
, struct sort_list_item
**ss2
)
668 return (top_level_str_coll(((*ss1
)->str
), ((*ss2
)->str
)));
672 * Maximum size of a number in the string (before or after decimal point)
674 #define MAX_NUM_SIZE (128)
679 static void setsuffix(wchar_t c
, unsigned char *si
)
713 * Read string s and parse the string into a fixed-decimal-point number.
714 * sign equals -1 if the number is negative (explicit plus is not allowed,
715 * according to GNU sort's "info sort".
716 * The number part before decimal point is in the smain, after the decimal
717 * point is in sfrac, tail is the pointer to the remainder of the string.
720 read_number(struct bwstring
*s0
, int *sign
, wchar_t *smain
, size_t *main_len
, wchar_t *sfrac
, size_t *frac_len
, unsigned char *si
)
723 bool prev_thousand_sep
= false;
727 /* always end the fraction with zero, even if we have no fraction */
730 while (iswblank_f(bws_get_iter_value(s
)))
731 s
= bws_iterator_inc(s
, 1);
733 if (bws_get_iter_value(s
) == (wchar_t)symbol_negative_sign
) {
735 s
= bws_iterator_inc(s
, 1);
738 // This is '0', not '\0', do not change this
739 while (iswdigit(bws_get_iter_value(s
)) &&
740 (bws_get_iter_value(s
) == L
'0'))
741 s
= bws_iterator_inc(s
, 1);
743 while (bws_get_iter_value(s
) && *main_len
< MAX_NUM_SIZE
) {
744 if (iswdigit(bws_get_iter_value(s
))) {
745 smain
[*main_len
] = bws_get_iter_value(s
);
746 s
= bws_iterator_inc(s
, 1);
748 prev_thousand_sep
= false;
749 } else if (symbol_thousands_sep
750 && (bws_get_iter_value(s
) == (wchar_t)symbol_thousands_sep
)
751 && (!prev_thousand_sep
)
753 s
= bws_iterator_inc(s
, 1);
754 prev_thousand_sep
= true;
759 smain
[*main_len
] = 0;
761 if (bws_get_iter_value(s
) == (wchar_t)symbol_decimal_point
) {
762 s
= bws_iterator_inc(s
, 1);
763 while (iswdigit(bws_get_iter_value(s
)) &&
764 *frac_len
< MAX_NUM_SIZE
) {
765 sfrac
[*frac_len
] = bws_get_iter_value(s
);
766 s
= bws_iterator_inc(s
, 1);
769 sfrac
[*frac_len
] = 0;
771 while (*frac_len
> 0 && sfrac
[*frac_len
- 1] == L
'0') {
773 sfrac
[*frac_len
] = L
'\0';
777 setsuffix(bws_get_iter_value(s
),si
);
779 if ((*main_len
+ *frac_len
) == 0)
786 * Implements string sort.
789 wstrcoll(struct key_value
*kv1
, struct key_value
*kv2
, size_t offset
)
794 printf("; offset=%d\n", (int) offset
);
795 bwsprintf(stdout
, kv1
->k
, "; k1=<", ">");
796 printf("(%zu)", BWSLEN(kv1
->k
));
797 bwsprintf(stdout
, kv2
->k
, ", k2=<", ">");
798 printf("(%zu)", BWSLEN(kv2
->k
));
801 return (bwscoll(kv1
->k
, kv2
->k
, offset
));
805 * Compare two suffixes
808 cmpsuffix(unsigned char si1
, unsigned char si2
)
811 return ((char)si1
- (char)si2
);
815 * Implements numeric sort for -n and -h.
818 numcoll_impl(struct key_value
*kv1
, struct key_value
*kv2
,
819 size_t offset __unused
, bool use_suffix
)
821 struct bwstring
*s1
, *s2
;
822 wchar_t sfrac1
[MAX_NUM_SIZE
+ 1], sfrac2
[MAX_NUM_SIZE
+ 1];
823 wchar_t smain1
[MAX_NUM_SIZE
+ 1], smain2
[MAX_NUM_SIZE
+ 1];
824 int cmp_res
, sign1
, sign2
;
825 size_t frac1
, frac2
, main1
, main2
;
826 unsigned char SI1
, SI2
;
827 bool e1
, e2
, key1_read
, key2_read
;
835 key1_read
= key2_read
= false;
838 bwsprintf(stdout
, s1
, "; k1=<", ">");
839 bwsprintf(stdout
, s2
, ", k2=<", ">");
845 if (kv1
->hint
->status
== HS_UNINITIALIZED
) {
846 /* read the number from the string */
847 read_number(s1
, &sign1
, smain1
, &main1
, sfrac1
, &frac1
, &SI1
);
849 kv1
->hint
->v
.nh
.n1
= wcstoull(smain1
, NULL
, 10);
850 if(main1
< 1 && frac1
< 1)
851 kv1
->hint
->v
.nh
.empty
=true;
852 kv1
->hint
->v
.nh
.si
= SI1
;
853 kv1
->hint
->status
= (kv1
->hint
->v
.nh
.n1
!= ULLONG_MAX
) ?
854 HS_INITIALIZED
: HS_ERROR
;
855 kv1
->hint
->v
.nh
.neg
= (sign1
< 0) ? true : false;
858 if (kv2
->hint
->status
== HS_UNINITIALIZED
) {
859 /* read the number from the string */
860 read_number(s2
, &sign2
, smain2
, &main2
, sfrac2
, &frac2
,&SI2
);
862 kv2
->hint
->v
.nh
.n1
= wcstoull(smain2
, NULL
, 10);
863 if(main2
< 1 && frac2
< 1)
864 kv2
->hint
->v
.nh
.empty
=true;
865 kv2
->hint
->v
.nh
.si
= SI2
;
866 kv2
->hint
->status
= (kv2
->hint
->v
.nh
.n1
!= ULLONG_MAX
) ?
867 HS_INITIALIZED
: HS_ERROR
;
868 kv2
->hint
->v
.nh
.neg
= (sign2
< 0) ? true : false;
871 if (kv1
->hint
->status
== HS_INITIALIZED
&& kv2
->hint
->status
==
873 unsigned long long n1
, n2
;
876 e1
= kv1
->hint
->v
.nh
.empty
;
877 e2
= kv2
->hint
->v
.nh
.empty
;
882 neg1
= kv1
->hint
->v
.nh
.neg
;
883 neg2
= kv2
->hint
->v
.nh
.neg
;
891 return (neg2
? +1 : -1);
893 return (neg1
? -1 : +1);
897 cmp_res
= cmpsuffix(kv1
->hint
->v
.nh
.si
, kv2
->hint
->v
.nh
.si
);
899 return (neg1
? -cmp_res
: cmp_res
);
902 n1
= kv1
->hint
->v
.nh
.n1
;
903 n2
= kv2
->hint
->v
.nh
.n1
;
905 return (neg1
? +1 : -1);
907 return (neg1
? -1 : +1);
910 /* read the numbers from the strings */
912 read_number(s1
, &sign1
, smain1
, &main1
, sfrac1
, &frac1
, &SI1
);
914 read_number(s2
, &sign2
, smain2
, &main2
, sfrac2
, &frac2
, &SI2
);
916 e1
= ((main1
+ frac1
) == 0);
917 e2
= ((main2
+ frac2
) == 0);
922 /* we know the result if the signs are different */
923 if (sign1
< 0 && sign2
>= 0)
925 if (sign1
>= 0 && sign2
< 0)
929 return ((sign2
< 0) ? +1 : -1);
931 return ((sign1
< 0) ? -1 : +1);
934 cmp_res
= cmpsuffix(SI1
, SI2
);
936 return ((sign1
< 0) ? -cmp_res
: cmp_res
);
939 /* if both numbers are empty assume that the strings are equal */
940 if (main1
< 1 && main2
< 1 && frac1
< 1 && frac2
< 1)
944 * if the main part is of different size, we know the result
945 * (because the leading zeros are removed)
949 else if (main1
> main2
)
951 /* if the sizes are equal then simple non-collate string compare gives the correct result */
953 cmp_res
= wcscmp(smain1
, smain2
);
957 cmp_res
= wcscmp(sfrac1
, sfrac2
);
962 /* reverse result if the signs are negative */
963 if (sign1
< 0 && sign2
< 0)
970 * Implements numeric sort (-n).
973 numcoll(struct key_value
*kv1
, struct key_value
*kv2
, size_t offset
)
976 return (numcoll_impl(kv1
, kv2
, offset
, false));
980 * Implements 'human' numeric sort (-h).
983 hnumcoll(struct key_value
*kv1
, struct key_value
*kv2
, size_t offset
)
986 return (numcoll_impl(kv1
, kv2
, offset
, true));
990 * Implements random sort (-R).
993 randomcoll(struct key_value
*kv1
, struct key_value
*kv2
,
994 size_t offset __unused
)
996 struct bwstring
*s1
, *s2
;
1004 bwsprintf(stdout
, s1
, "; k1=<", ">");
1005 bwsprintf(stdout
, s2
, ", k2=<", ">");
1011 memcpy(&ctx1
,&md5_ctx
,sizeof(MD5_CTX
));
1012 memcpy(&ctx2
,&md5_ctx
,sizeof(MD5_CTX
));
1014 MD5Update(&ctx1
, bwsrawdata(s1
), bwsrawlen(s1
));
1015 MD5Update(&ctx2
, bwsrawdata(s2
), bwsrawlen(s2
));
1016 b1
= MD5End(&ctx1
, NULL
);
1017 b2
= MD5End(&ctx2
, NULL
);
1025 } else if (b2
== NULL
) {
1031 cmp_res
= strcmp(b1
,b2
);
1036 cmp_res
= bwscoll(s1
, s2
, 0);
1043 * Implements version sort (-V).
1046 versioncoll(struct key_value
*kv1
, struct key_value
*kv2
,
1047 size_t offset __unused
)
1049 struct bwstring
*s1
, *s2
;
1055 bwsprintf(stdout
, s1
, "; k1=<", ">");
1056 bwsprintf(stdout
, s2
, ", k2=<", ">");
1062 return (vcmp(s1
, s2
));
1066 * Check for minus infinity
1069 huge_minus(double d
, int err1
)
1073 if (d
== -HUGE_VAL
|| d
== -HUGE_VALF
|| d
== -HUGE_VALL
)
1080 * Check for plus infinity
1083 huge_plus(double d
, int err1
)
1087 if (d
== HUGE_VAL
|| d
== HUGE_VALF
|| d
== HUGE_VALL
)
1094 * Check whether a function is a NAN
1100 return ((d
== NAN
) || (isnan(d
)));
1107 cmp_nans(double d1
, double d2
)
1118 * Implements general numeric sort (-g).
1121 gnumcoll(struct key_value
*kv1
, struct key_value
*kv2
,
1122 size_t offset __unused
)
1126 bool empty1
, empty2
, key1_read
, key2_read
;
1130 key1_read
= key2_read
= false;
1133 bwsprintf(stdout
, kv1
->k
, "; k1=<", ">");
1134 bwsprintf(stdout
, kv2
->k
, "; k2=<", ">");
1137 if (kv1
->hint
->status
== HS_UNINITIALIZED
) {
1139 d1
= bwstod(kv1
->k
, &empty1
);
1143 kv1
->hint
->v
.gh
.notnum
= true;
1144 else if (err1
== 0) {
1145 kv1
->hint
->v
.gh
.d
= d1
;
1146 kv1
->hint
->v
.gh
.nan
= is_nan(d1
);
1147 kv1
->hint
->status
= HS_INITIALIZED
;
1149 kv1
->hint
->status
= HS_ERROR
;
1154 if (kv2
->hint
->status
== HS_UNINITIALIZED
) {
1156 d2
= bwstod(kv2
->k
, &empty2
);
1160 kv2
->hint
->v
.gh
.notnum
= true;
1161 else if (err2
== 0) {
1162 kv2
->hint
->v
.gh
.d
= d2
;
1163 kv2
->hint
->v
.gh
.nan
= is_nan(d2
);
1164 kv2
->hint
->status
= HS_INITIALIZED
;
1166 kv2
->hint
->status
= HS_ERROR
;
1171 if (kv1
->hint
->status
== HS_INITIALIZED
&&
1172 kv2
->hint
->status
== HS_INITIALIZED
) {
1173 if (kv1
->hint
->v
.gh
.notnum
)
1174 return ((kv2
->hint
->v
.gh
.notnum
) ? 0 : -1);
1175 else if (kv2
->hint
->v
.gh
.notnum
)
1178 if (kv1
->hint
->v
.gh
.nan
)
1179 return ((kv2
->hint
->v
.gh
.nan
) ?
1180 cmp_nans(kv1
->hint
->v
.gh
.d
, kv2
->hint
->v
.gh
.d
) :
1182 else if (kv2
->hint
->v
.gh
.nan
)
1185 d1
= kv1
->hint
->v
.gh
.d
;
1186 d2
= kv2
->hint
->v
.gh
.d
;
1198 d1
= bwstod(kv1
->k
, &empty1
);
1204 d2
= bwstod(kv2
->k
, &empty2
);
1208 /* Non-value case: */
1210 return (empty2
? 0 : -1);
1216 return (is_nan(d2
) ? cmp_nans(d1
, d2
) : -1);
1217 else if (is_nan(d2
))
1221 if (err1
== ERANGE
|| err2
== ERANGE
) {
1222 /* Minus infinity case */
1223 if (huge_minus(d1
, err1
)) {
1224 if (huge_minus(d2
, err2
)) {
1233 } else if (huge_minus(d2
, err2
)) {
1234 if (huge_minus(d1
, err1
)) {
1244 /* Plus infinity case */
1245 if (huge_plus(d1
, err1
)) {
1246 if (huge_plus(d2
, err2
)) {
1254 } else if (huge_plus(d2
, err2
)) {
1255 if (huge_plus(d1
, err1
)) {
1275 * Implements month sort (-M).
1278 monthcoll(struct key_value
*kv1
, struct key_value
*kv2
, size_t offset __unused
)
1281 bool key1_read
, key2_read
;
1284 key1_read
= key2_read
= false;
1287 bwsprintf(stdout
, kv1
->k
, "; k1=<", ">");
1288 bwsprintf(stdout
, kv2
->k
, "; k2=<", ">");
1291 if (kv1
->hint
->status
== HS_UNINITIALIZED
) {
1292 kv1
->hint
->v
.Mh
.m
= bws_month_score(kv1
->k
);
1294 kv1
->hint
->status
= HS_INITIALIZED
;
1297 if (kv2
->hint
->status
== HS_UNINITIALIZED
) {
1298 kv2
->hint
->v
.Mh
.m
= bws_month_score(kv2
->k
);
1300 kv2
->hint
->status
= HS_INITIALIZED
;
1303 if (kv1
->hint
->status
== HS_INITIALIZED
) {
1304 val1
= kv1
->hint
->v
.Mh
.m
;
1308 if (kv2
->hint
->status
== HS_INITIALIZED
) {
1309 val2
= kv2
->hint
->v
.Mh
.m
;
1314 val1
= bws_month_score(kv1
->k
);
1316 val2
= bws_month_score(kv2
->k
);