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
27 * $FreeBSD: head/usr.bin/sort/coll.c 281132 2015-04-06 02:35:55Z pfg $
31 #include <sys/types.h>
42 #if defined(SORT_RANDOM)
43 #include <openssl/md5.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 #if defined(SORT_RANDOM)
64 static int randomcoll(struct key_value
*, struct key_value
*, size_t offset
);
66 static int versioncoll(struct key_value
*, struct key_value
*, size_t offset
);
72 keys_array_alloc(void)
74 struct keys_array
*ka
;
77 sz
= keys_array_size();
85 * Calculate whether we need key hint space
91 return (need_hint
? sizeof(struct key_hint
) : 0);
95 * Calculate keys array size
101 return (keys_num
* (sizeof(struct key_value
) + key_hint_size()));
105 * Clean data of keys array
108 clean_keys_array(const struct bwstring
*s
, struct keys_array
*ka
)
112 for (size_t i
= 0; i
< keys_num
; ++i
)
113 if (ka
->key
[i
].k
&& ka
->key
[i
].k
!= s
)
114 bwsfree(ka
->key
[i
].k
);
115 memset(ka
, 0, keys_array_size());
120 * Set value of a key in the keys set
123 set_key_on_keys_array(struct keys_array
*ka
, struct bwstring
*s
, size_t ind
)
126 if (ka
&& keys_num
> ind
) {
127 struct key_value
*kv
;
129 kv
= &(ka
->key
[ind
]);
131 if (kv
->k
&& kv
->k
!= s
)
138 * Initialize a sort list item
140 struct sort_list_item
*
141 sort_list_item_alloc(void)
143 struct sort_list_item
*si
;
146 sz
= sizeof(struct sort_list_item
) + keys_array_size();
147 si
= sort_malloc(sz
);
154 sort_list_item_size(struct sort_list_item
*si
)
159 ret
= sizeof(struct sort_list_item
) + keys_array_size();
161 ret
+= bws_memsize(si
->str
);
162 for (size_t i
= 0; i
< keys_num
; ++i
) {
163 struct key_value
*kv
;
165 kv
= &(si
->ka
.key
[i
]);
167 if (kv
->k
!= si
->str
)
168 ret
+= bws_memsize(kv
->k
);
175 * Calculate key for a sort list item
178 sort_list_item_make_key(struct sort_list_item
*si
)
181 preproc(si
->str
, &(si
->ka
));
185 * Set value of a sort list item.
186 * Return combined string and keys memory size.
189 sort_list_item_set(struct sort_list_item
*si
, struct bwstring
*str
)
193 clean_keys_array(si
->str
, &(si
->ka
));
195 if (si
->str
== str
) {
196 /* we are trying to reset the same string */
204 sort_list_item_make_key(si
);
209 * De-allocate a sort list item object memory
212 sort_list_item_clean(struct sort_list_item
*si
)
216 clean_keys_array(si
->str
, &(si
->ka
));
225 * Skip columns according to specs
228 skip_cols_to_start(const struct bwstring
*s
, size_t cols
, size_t start
,
229 bool skip_blanks
, bool *empty_key
)
232 return (BWSLEN(s
) + 1);
235 while (start
< BWSLEN(s
) && iswblank(BWS_GET(s
,start
)))
238 while (start
< BWSLEN(s
) && cols
> 1) {
243 if (start
>= BWSLEN(s
))
250 * Skip fields according to specs
253 skip_fields_to_start(const struct bwstring
*s
, size_t fields
, bool *empty_field
)
260 } else if (!(sort_opts_vals
.tflag
)) {
264 while (cpos
< BWSLEN(s
)) {
267 isblank
= iswblank(BWS_GET(s
, cpos
));
269 if (isblank
&& !pb
) {
283 while (cpos
< BWSLEN(s
)) {
284 if (BWS_GET(s
,cpos
) == (wchar_t)sort_opts_vals
.field_sep
) {
301 find_field_start(const struct bwstring
*s
, struct key_specs
*ks
,
302 size_t *field_start
, size_t *key_start
, bool *empty_field
, bool *empty_key
)
305 *field_start
= skip_fields_to_start(s
, ks
->f1
, empty_field
);
307 *key_start
= skip_cols_to_start(s
, ks
->c1
, *field_start
,
308 ks
->pos1b
, empty_key
);
314 * Find end key position
317 find_field_end(const struct bwstring
*s
, struct key_specs
*ks
)
319 size_t f2
, next_field_start
, pos_end
;
320 bool empty_field
, empty_key
;
323 next_field_start
= 0;
329 return (BWSLEN(s
) + 1);
332 next_field_start
= skip_fields_to_start(s
, f2
+ 1,
334 if ((next_field_start
> 0) && sort_opts_vals
.tflag
&&
335 ((wchar_t)sort_opts_vals
.field_sep
== BWS_GET(s
,
336 next_field_start
- 1)))
339 next_field_start
= skip_fields_to_start(s
, f2
,
343 if (empty_field
|| (next_field_start
>= BWSLEN(s
)))
344 return (BWSLEN(s
) + 1);
347 pos_end
= skip_cols_to_start(s
, ks
->c2
, next_field_start
,
348 ks
->pos2b
, &empty_key
);
349 if (pos_end
< BWSLEN(s
))
352 pos_end
= next_field_start
;
358 * Cut a field according to the key specs
360 static struct bwstring
*
361 cut_field(const struct bwstring
*s
, struct key_specs
*ks
)
363 struct bwstring
*ret
= NULL
;
366 size_t field_start
, key_end
, key_start
, sz
;
367 bool empty_field
, empty_key
;
374 find_field_start(s
, ks
, &field_start
, &key_start
,
375 &empty_field
, &empty_key
);
380 key_end
= find_field_end(s
, ks
);
381 sz
= (key_end
< key_start
) ? 0 : (key_end
- key_start
);
386 bwsnocpy(ret
, s
, key_start
, sz
);
394 * Preprocesses a line applying the necessary transformations
395 * specified by command line options and returns the preprocessed
396 * string, which can be used to compare.
399 preproc(struct bwstring
*s
, struct keys_array
*ka
)
402 if (sort_opts_vals
.kflag
)
403 for (size_t i
= 0; i
< keys_num
; i
++) {
404 struct bwstring
*key
;
405 struct key_specs
*kspecs
;
406 struct sort_mods
*sm
;
409 key
= cut_field(s
, kspecs
);
413 key
= dictionary_order(key
);
415 key
= ignore_nonprinting(key
);
416 if (sm
->fflag
|| sm
->Mflag
)
417 key
= ignore_case(key
);
419 set_key_on_keys_array(ka
, key
, i
);
422 struct bwstring
*ret
= NULL
;
423 struct sort_mods
*sm
= default_sort_mods
;
428 ret
= ignore_leading_blanks(ret
);
433 ret
= dictionary_order(ret
);
434 } else if (sm
->iflag
) {
437 ret
= ignore_nonprinting(ret
);
439 if (sm
->fflag
|| sm
->Mflag
) {
442 ret
= ignore_case(ret
);
445 set_key_on_keys_array(ka
, s
, 0);
447 set_key_on_keys_array(ka
, ret
, 0);
454 get_sort_func(struct sort_mods
*sm
)
465 #if defined(SORT_RANDOM)
470 return (versioncoll
);
476 * Compares the given strings. Returns a positive number if
477 * the first precedes the second, a negative number if the second is
478 * the preceding one, and zero if they are equal. This function calls
479 * the underlying collate functions, which done the actual comparison.
482 key_coll(struct keys_array
*ps1
, struct keys_array
*ps2
, size_t offset
)
484 struct sort_mods
*sm
;
487 for (size_t i
= 0; i
< keys_num
; ++i
) {
491 res
= sm
->func(&(ps2
->key
[i
]), &(ps1
->key
[i
]), offset
);
493 res
= sm
->func(&(ps1
->key
[i
]), &(ps2
->key
[i
]), offset
);
498 /* offset applies to only the first key */
505 * Compare two strings.
506 * Plain symbol-by-symbol comparison.
509 top_level_str_coll(const struct bwstring
*s1
, const struct bwstring
*s2
)
512 if (default_sort_mods
->rflag
) {
513 const struct bwstring
*tmp
;
520 return (bwscoll(s1
, s2
, 0));
524 * Compare a string and a sort list item, according to the sort specs.
527 str_list_coll(struct bwstring
*str1
, struct sort_list_item
**ss2
)
529 struct keys_array
*ka1
;
532 ka1
= keys_array_alloc();
536 sort_list_item_make_key(*ss2
);
539 bwsprintf(stdout
, str1
, "; s1=<", ">");
540 bwsprintf(stdout
, (*ss2
)->str
, ", s2=<", ">");
543 ret
= key_coll(ka1
, &((*ss2
)->ka
), 0);
546 printf("; cmp1=%d", ret
);
548 clean_keys_array(str1
, ka1
);
551 if ((ret
== 0) && !(sort_opts_vals
.sflag
) && sort_opts_vals
.complex_sort
) {
552 ret
= top_level_str_coll(str1
, ((*ss2
)->str
));
554 printf("; cmp2=%d", ret
);
564 * Compare two sort list items, according to the sort specs.
567 list_coll_offset(struct sort_list_item
**ss1
, struct sort_list_item
**ss2
,
572 ret
= key_coll(&((*ss1
)->ka
), &((*ss2
)->ka
), offset
);
576 printf("; offset=%d", (int) offset
);
577 bwsprintf(stdout
, ((*ss1
)->str
), "; s1=<", ">");
578 bwsprintf(stdout
, ((*ss2
)->str
), ", s2=<", ">");
579 printf("; cmp1=%d\n", ret
);
585 if (!(sort_opts_vals
.sflag
) && sort_opts_vals
.complex_sort
) {
586 ret
= top_level_str_coll(((*ss1
)->str
), ((*ss2
)->str
));
588 printf("; cmp2=%d\n", ret
);
595 * Compare two sort list items, according to the sort specs.
598 list_coll(struct sort_list_item
**ss1
, struct sort_list_item
**ss2
)
601 return (list_coll_offset(ss1
, ss2
, 0));
606 list_coll_##N(struct sort_list_item **ss1, struct sort_list_item **ss2) \
609 return (list_coll_offset(ss1, ss2, N)); \
634 get_list_call_func(size_t offset
)
636 static const listcoll_t lsarray
[] = { list_coll
, list_coll_1
,
637 list_coll_2
, list_coll_3
, list_coll_4
, list_coll_5
,
638 list_coll_6
, list_coll_7
, list_coll_8
, list_coll_9
,
639 list_coll_10
, list_coll_11
, list_coll_12
, list_coll_13
,
640 list_coll_14
, list_coll_15
, list_coll_16
, list_coll_17
,
641 list_coll_18
, list_coll_19
, list_coll_20
};
644 return (lsarray
[offset
]);
650 * Compare two sort list items, only by their original string.
653 list_coll_by_str_only(struct sort_list_item
**ss1
, struct sort_list_item
**ss2
)
656 return (top_level_str_coll(((*ss1
)->str
), ((*ss2
)->str
)));
660 * Maximum size of a number in the string (before or after decimal point)
662 #define MAX_NUM_SIZE (128)
667 static void setsuffix(wchar_t c
, unsigned char *si
)
701 * Read string s and parse the string into a fixed-decimal-point number.
702 * sign equals -1 if the number is negative (explicit plus is not allowed,
703 * according to GNU sort's "info sort".
704 * The number part before decimal point is in the smain, after the decimal
705 * point is in sfrac, tail is the pointer to the remainder of the string.
708 read_number(struct bwstring
*s0
, int *sign
, wchar_t *smain
, size_t *main_len
, wchar_t *sfrac
, size_t *frac_len
, unsigned char *si
)
714 /* always end the fraction with zero, even if we have no fraction */
717 while (iswblank(bws_get_iter_value(s
)))
718 s
= bws_iterator_inc(s
, 1);
720 if (bws_get_iter_value(s
) == (wchar_t)symbol_negative_sign
) {
722 s
= bws_iterator_inc(s
, 1);
725 // This is '0', not '\0', do not change this
726 while (iswdigit(bws_get_iter_value(s
)) &&
727 (bws_get_iter_value(s
) == L
'0'))
728 s
= bws_iterator_inc(s
, 1);
730 while (bws_get_iter_value(s
) && *main_len
< MAX_NUM_SIZE
) {
731 if (iswdigit(bws_get_iter_value(s
))) {
732 smain
[*main_len
] = bws_get_iter_value(s
);
733 s
= bws_iterator_inc(s
, 1);
735 } else if (symbol_thousands_sep
&&
736 (bws_get_iter_value(s
) == (wchar_t)symbol_thousands_sep
))
737 s
= bws_iterator_inc(s
, 1);
742 smain
[*main_len
] = 0;
744 if (bws_get_iter_value(s
) == (wchar_t)symbol_decimal_point
) {
745 s
= bws_iterator_inc(s
, 1);
746 while (iswdigit(bws_get_iter_value(s
)) &&
747 *frac_len
< MAX_NUM_SIZE
) {
748 sfrac
[*frac_len
] = bws_get_iter_value(s
);
749 s
= bws_iterator_inc(s
, 1);
752 sfrac
[*frac_len
] = 0;
754 while (*frac_len
> 0 && sfrac
[*frac_len
- 1] == L
'0') {
756 sfrac
[*frac_len
] = L
'\0';
760 setsuffix(bws_get_iter_value(s
),si
);
762 if ((*main_len
+ *frac_len
) == 0)
769 * Implements string sort.
772 wstrcoll(struct key_value
*kv1
, struct key_value
*kv2
, size_t offset
)
777 printf("; offset=%d\n", (int) offset
);
778 bwsprintf(stdout
, kv1
->k
, "; k1=<", ">");
779 printf("(%zu)", BWSLEN(kv1
->k
));
780 bwsprintf(stdout
, kv2
->k
, ", k2=<", ">");
781 printf("(%zu)", BWSLEN(kv2
->k
));
784 return (bwscoll(kv1
->k
, kv2
->k
, offset
));
788 * Compare two suffixes
791 cmpsuffix(unsigned char si1
, unsigned char si2
)
794 return ((char)si1
- (char)si2
);
798 * Implements numeric sort for -n and -h.
801 numcoll_impl(struct key_value
*kv1
, struct key_value
*kv2
,
802 size_t offset __unused
, bool use_suffix
)
804 struct bwstring
*s1
, *s2
;
805 wchar_t sfrac1
[MAX_NUM_SIZE
+ 1], sfrac2
[MAX_NUM_SIZE
+ 1];
806 wchar_t smain1
[MAX_NUM_SIZE
+ 1], smain2
[MAX_NUM_SIZE
+ 1];
807 int cmp_res
, sign1
, sign2
;
808 size_t frac1
, frac2
, main1
, main2
;
809 unsigned char SI1
, SI2
;
810 bool e1
, e2
, key1_read
, key2_read
;
819 key1_read
= key2_read
= false;
822 bwsprintf(stdout
, s1
, "; k1=<", ">");
823 bwsprintf(stdout
, s2
, ", k2=<", ">");
829 if (kv1
->hint
->status
== HS_UNINITIALIZED
) {
830 /* read the number from the string */
831 read_number(s1
, &sign1
, smain1
, &main1
, sfrac1
, &frac1
, &SI1
);
833 kv1
->hint
->v
.nh
.n1
= wcstoull(smain1
, NULL
, 10);
834 if(main1
< 1 && frac1
< 1)
835 kv1
->hint
->v
.nh
.empty
=true;
836 kv1
->hint
->v
.nh
.si
= SI1
;
837 kv1
->hint
->status
= (kv1
->hint
->v
.nh
.n1
!= ULLONG_MAX
) ?
838 HS_INITIALIZED
: HS_ERROR
;
839 kv1
->hint
->v
.nh
.neg
= (sign1
< 0) ? true : false;
842 if (kv2
->hint
->status
== HS_UNINITIALIZED
) {
843 /* read the number from the string */
844 read_number(s2
, &sign2
, smain2
, &main2
, sfrac2
, &frac2
,&SI2
);
846 kv2
->hint
->v
.nh
.n1
= wcstoull(smain2
, NULL
, 10);
847 if(main2
< 1 && frac2
< 1)
848 kv2
->hint
->v
.nh
.empty
=true;
849 kv2
->hint
->v
.nh
.si
= SI2
;
850 kv2
->hint
->status
= (kv2
->hint
->v
.nh
.n1
!= ULLONG_MAX
) ?
851 HS_INITIALIZED
: HS_ERROR
;
852 kv2
->hint
->v
.nh
.neg
= (sign2
< 0) ? true : false;
855 if (kv1
->hint
->status
== HS_INITIALIZED
&& kv2
->hint
->status
==
857 unsigned long long n1
, n2
;
860 e1
= kv1
->hint
->v
.nh
.empty
;
861 e2
= kv2
->hint
->v
.nh
.empty
;
866 neg1
= kv1
->hint
->v
.nh
.neg
;
867 neg2
= kv2
->hint
->v
.nh
.neg
;
875 return (neg2
? +1 : -1);
877 return (neg1
? -1 : +1);
881 cmp_res
= cmpsuffix(kv1
->hint
->v
.nh
.si
, kv2
->hint
->v
.nh
.si
);
883 return (neg1
? -cmp_res
: cmp_res
);
886 n1
= kv1
->hint
->v
.nh
.n1
;
887 n2
= kv2
->hint
->v
.nh
.n1
;
889 return (neg1
? +1 : -1);
891 return (neg1
? -1 : +1);
894 /* read the numbers from the strings */
896 read_number(s1
, &sign1
, smain1
, &main1
, sfrac1
, &frac1
, &SI1
);
898 read_number(s2
, &sign2
, smain2
, &main2
, sfrac2
, &frac2
, &SI2
);
900 e1
= ((main1
+ frac1
) == 0);
901 e2
= ((main2
+ frac2
) == 0);
906 /* we know the result if the signs are different */
907 if (sign1
< 0 && sign2
>= 0)
909 if (sign1
>= 0 && sign2
< 0)
913 return ((sign2
< 0) ? +1 : -1);
915 return ((sign1
< 0) ? -1 : +1);
918 cmp_res
= cmpsuffix(SI1
, SI2
);
920 return ((sign1
< 0) ? -cmp_res
: cmp_res
);
923 /* if both numbers are empty assume that the strings are equal */
924 if (main1
< 1 && main2
< 1 && frac1
< 1 && frac2
< 1)
928 * if the main part is of different size, we know the result
929 * (because the leading zeros are removed)
933 else if (main1
> main2
)
935 /* if the sizes are equal then simple non-collate string compare gives the correct result */
937 cmp_res
= wcscmp(smain1
, smain2
);
941 cmp_res
= wcscmp(sfrac1
, sfrac2
);
946 /* reverse result if the signs are negative */
947 if (sign1
< 0 && sign2
< 0)
954 * Implements numeric sort (-n).
957 numcoll(struct key_value
*kv1
, struct key_value
*kv2
, size_t offset
)
960 return (numcoll_impl(kv1
, kv2
, offset
, false));
964 * Implements 'human' numeric sort (-h).
967 hnumcoll(struct key_value
*kv1
, struct key_value
*kv2
, size_t offset
)
970 return (numcoll_impl(kv1
, kv2
, offset
, true));
974 * Implements random sort (-R).
976 #if defined(SORT_RANDOM)
978 randomcollend(MD5_CTX
*ctx
)
980 unsigned char digest
[MD5_DIGEST_LENGTH
];
981 static const char hex
[]="0123456789abcdef";
985 buf
= malloc(MD5_DIGEST_LENGTH
* 2 + 1);
988 MD5_Final(digest
, ctx
);
989 for (i
= 0; i
< MD5_DIGEST_LENGTH
; i
++) {
990 buf
[2*i
] = hex
[digest
[i
] >> 4];
991 buf
[2*i
+1] = hex
[digest
[i
] & 0x0f];
993 buf
[MD5_DIGEST_LENGTH
* 2] = '\0';
998 randomcoll(struct key_value
*kv1
, struct key_value
*kv2
,
999 size_t offset __unused
)
1001 struct bwstring
*s1
, *s2
;
1009 bwsprintf(stdout
, s1
, "; k1=<", ">");
1010 bwsprintf(stdout
, s2
, ", k2=<", ">");
1016 memcpy(&ctx1
,&md5_ctx
,sizeof(MD5_CTX
));
1017 memcpy(&ctx2
,&md5_ctx
,sizeof(MD5_CTX
));
1019 MD5_Update(&ctx1
, bwsrawdata(s1
), bwsrawlen(s1
));
1020 MD5_Update(&ctx2
, bwsrawdata(s2
), bwsrawlen(s2
));
1021 b1
= randomcollend(&ctx1
);
1022 b2
= randomcollend(&ctx2
);
1030 } else if (b2
== NULL
) {
1036 cmp_res
= strcmp(b1
,b2
);
1041 cmp_res
= bwscoll(s1
, s2
, 0);
1049 * Implements version sort (-V).
1052 versioncoll(struct key_value
*kv1
, struct key_value
*kv2
,
1053 size_t offset __unused
)
1055 struct bwstring
*s1
, *s2
;
1061 bwsprintf(stdout
, s1
, "; k1=<", ">");
1062 bwsprintf(stdout
, s2
, ", k2=<", ">");
1068 return (vcmp(s1
, s2
));
1072 * Check for minus infinity
1075 huge_minus(double d
, int err1
)
1079 if (d
== -HUGE_VAL
|| d
== -HUGE_VALF
|| d
== -HUGE_VALL
)
1086 * Check for plus infinity
1089 huge_plus(double d
, int err1
)
1093 if (d
== HUGE_VAL
|| d
== HUGE_VALF
|| d
== HUGE_VALL
)
1100 * Check whether a function is a NAN
1105 return ((d
== NAN
) || (isnan(d
)));
1112 cmp_nans(double d1
, double d2
)
1123 * Implements general numeric sort (-g).
1126 gnumcoll(struct key_value
*kv1
, struct key_value
*kv2
,
1127 size_t offset __unused
)
1131 bool empty1
, empty2
, key1_read
, key2_read
;
1135 key1_read
= key2_read
= false;
1138 bwsprintf(stdout
, kv1
->k
, "; k1=<", ">");
1139 bwsprintf(stdout
, kv2
->k
, "; k2=<", ">");
1142 if (kv1
->hint
->status
== HS_UNINITIALIZED
) {
1144 d1
= bwstod(kv1
->k
, &empty1
);
1148 kv1
->hint
->v
.gh
.notnum
= true;
1149 else if (err1
== 0) {
1150 kv1
->hint
->v
.gh
.d
= d1
;
1151 kv1
->hint
->v
.gh
.nan
= is_nan(d1
);
1152 kv1
->hint
->status
= HS_INITIALIZED
;
1154 kv1
->hint
->status
= HS_ERROR
;
1159 if (kv2
->hint
->status
== HS_UNINITIALIZED
) {
1161 d2
= bwstod(kv2
->k
, &empty2
);
1165 kv2
->hint
->v
.gh
.notnum
= true;
1166 else if (err2
== 0) {
1167 kv2
->hint
->v
.gh
.d
= d2
;
1168 kv2
->hint
->v
.gh
.nan
= is_nan(d2
);
1169 kv2
->hint
->status
= HS_INITIALIZED
;
1171 kv2
->hint
->status
= HS_ERROR
;
1176 if (kv1
->hint
->status
== HS_INITIALIZED
&&
1177 kv2
->hint
->status
== HS_INITIALIZED
) {
1178 if (kv1
->hint
->v
.gh
.notnum
)
1179 return ((kv2
->hint
->v
.gh
.notnum
) ? 0 : -1);
1180 else if (kv2
->hint
->v
.gh
.notnum
)
1183 if (kv1
->hint
->v
.gh
.nan
)
1184 return ((kv2
->hint
->v
.gh
.nan
) ?
1185 cmp_nans(kv1
->hint
->v
.gh
.d
, kv2
->hint
->v
.gh
.d
) :
1187 else if (kv2
->hint
->v
.gh
.nan
)
1190 d1
= kv1
->hint
->v
.gh
.d
;
1191 d2
= kv2
->hint
->v
.gh
.d
;
1203 d1
= bwstod(kv1
->k
, &empty1
);
1209 d2
= bwstod(kv2
->k
, &empty2
);
1213 /* Non-value case: */
1215 return (empty2
? 0 : -1);
1221 return (is_nan(d2
) ? cmp_nans(d1
, d2
) : -1);
1222 else if (is_nan(d2
))
1226 if (err1
== ERANGE
|| err2
== ERANGE
) {
1227 /* Minus infinity case */
1228 if (huge_minus(d1
, err1
)) {
1229 if (huge_minus(d2
, err2
)) {
1238 } else if (huge_minus(d2
, err2
)) {
1239 if (huge_minus(d1
, err1
)) {
1249 /* Plus infinity case */
1250 if (huge_plus(d1
, err1
)) {
1251 if (huge_plus(d2
, err2
)) {
1259 } else if (huge_plus(d2
, err2
)) {
1260 if (huge_plus(d1
, err1
)) {
1280 * Implements month sort (-M).
1283 monthcoll(struct key_value
*kv1
, struct key_value
*kv2
, size_t offset __unused
)
1286 bool key1_read
, key2_read
;
1289 key1_read
= key2_read
= false;
1292 bwsprintf(stdout
, kv1
->k
, "; k1=<", ">");
1293 bwsprintf(stdout
, kv2
->k
, "; k2=<", ">");
1296 if (kv1
->hint
->status
== HS_UNINITIALIZED
) {
1297 kv1
->hint
->v
.Mh
.m
= bws_month_score(kv1
->k
);
1299 kv1
->hint
->status
= HS_INITIALIZED
;
1302 if (kv2
->hint
->status
== HS_UNINITIALIZED
) {
1303 kv2
->hint
->v
.Mh
.m
= bws_month_score(kv2
->k
);
1305 kv2
->hint
->status
= HS_INITIALIZED
;
1308 if (kv1
->hint
->status
== HS_INITIALIZED
) {
1309 val1
= kv1
->hint
->v
.Mh
.m
;
1313 if (kv2
->hint
->status
== HS_INITIALIZED
) {
1314 val2
= kv2
->hint
->v
.Mh
.m
;
1319 val1
= bws_month_score(kv1
->k
);
1321 val2
= bws_month_score(kv2
->k
);