150fc853eSJohn Marino /*-
250fc853eSJohn Marino * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
350fc853eSJohn Marino * Copyright (C) 2012 Oleg Moskalenko <mom040267@gmail.com>
450fc853eSJohn Marino * All rights reserved.
550fc853eSJohn Marino *
650fc853eSJohn Marino * Redistribution and use in source and binary forms, with or without
750fc853eSJohn Marino * modification, are permitted provided that the following conditions
850fc853eSJohn Marino * are met:
950fc853eSJohn Marino * 1. Redistributions of source code must retain the above copyright
1050fc853eSJohn Marino * notice, this list of conditions and the following disclaimer.
1150fc853eSJohn Marino * 2. Redistributions in binary form must reproduce the above copyright
1250fc853eSJohn Marino * notice, this list of conditions and the following disclaimer in the
1350fc853eSJohn Marino * documentation and/or other materials provided with the distribution.
1450fc853eSJohn Marino *
1550fc853eSJohn Marino * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1650fc853eSJohn Marino * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1750fc853eSJohn Marino * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1850fc853eSJohn Marino * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1950fc853eSJohn Marino * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2050fc853eSJohn Marino * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2150fc853eSJohn Marino * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2250fc853eSJohn Marino * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2350fc853eSJohn Marino * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2450fc853eSJohn Marino * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2550fc853eSJohn Marino * SUCH DAMAGE.
2650fc853eSJohn Marino *
2750fc853eSJohn Marino * $FreeBSD: head/usr.bin/sort/coll.c 281132 2015-04-06 02:35:55Z pfg $
2850fc853eSJohn Marino */
2950fc853eSJohn Marino
3050fc853eSJohn Marino
3150fc853eSJohn Marino #include <sys/types.h>
3250fc853eSJohn Marino
3350fc853eSJohn Marino #include <errno.h>
3450fc853eSJohn Marino #include <err.h>
3550fc853eSJohn Marino #include <langinfo.h>
3650fc853eSJohn Marino #include <limits.h>
3750fc853eSJohn Marino #include <math.h>
3850fc853eSJohn Marino #include <stdlib.h>
3950fc853eSJohn Marino #include <string.h>
4050fc853eSJohn Marino #include <wchar.h>
4150fc853eSJohn Marino #include <wctype.h>
42*a98f7024Szrj #if defined(SORT_RANDOM)
43*a98f7024Szrj #include <openssl/md5.h>
44*a98f7024Szrj #endif
4550fc853eSJohn Marino
4650fc853eSJohn Marino #include "coll.h"
4750fc853eSJohn Marino #include "vsort.h"
4850fc853eSJohn Marino
4950fc853eSJohn Marino struct key_specs *keys;
5050fc853eSJohn Marino size_t keys_num = 0;
5150fc853eSJohn Marino
5250fc853eSJohn Marino wint_t symbol_decimal_point = L'.';
5350fc853eSJohn Marino /* there is no default thousands separator in collate rules: */
5450fc853eSJohn Marino wint_t symbol_thousands_sep = 0;
5550fc853eSJohn Marino wint_t symbol_negative_sign = L'-';
5650fc853eSJohn Marino wint_t symbol_positive_sign = L'+';
5750fc853eSJohn Marino
5850fc853eSJohn Marino static int wstrcoll(struct key_value *kv1, struct key_value *kv2, size_t offset);
5950fc853eSJohn Marino static int gnumcoll(struct key_value*, struct key_value *, size_t offset);
6050fc853eSJohn Marino static int monthcoll(struct key_value*, struct key_value *, size_t offset);
6150fc853eSJohn Marino static int numcoll(struct key_value*, struct key_value *, size_t offset);
6250fc853eSJohn Marino static int hnumcoll(struct key_value*, struct key_value *, size_t offset);
636d7e22ecSzrj #if defined(SORT_RANDOM)
6450fc853eSJohn Marino static int randomcoll(struct key_value*, struct key_value *, size_t offset);
656d7e22ecSzrj #endif
6650fc853eSJohn Marino static int versioncoll(struct key_value*, struct key_value *, size_t offset);
6750fc853eSJohn Marino
6850fc853eSJohn Marino /*
6950fc853eSJohn Marino * Allocate keys array
7050fc853eSJohn Marino */
7150fc853eSJohn Marino struct keys_array *
keys_array_alloc(void)7250fc853eSJohn Marino keys_array_alloc(void)
7350fc853eSJohn Marino {
7450fc853eSJohn Marino struct keys_array *ka;
7550fc853eSJohn Marino size_t sz;
7650fc853eSJohn Marino
7750fc853eSJohn Marino sz = keys_array_size();
7850fc853eSJohn Marino ka = sort_malloc(sz);
7950fc853eSJohn Marino memset(ka, 0, sz);
8050fc853eSJohn Marino
8150fc853eSJohn Marino return (ka);
8250fc853eSJohn Marino }
8350fc853eSJohn Marino
8450fc853eSJohn Marino /*
8550fc853eSJohn Marino * Calculate whether we need key hint space
8650fc853eSJohn Marino */
8750fc853eSJohn Marino static size_t
key_hint_size(void)8850fc853eSJohn Marino key_hint_size(void)
8950fc853eSJohn Marino {
9050fc853eSJohn Marino
9150fc853eSJohn Marino return (need_hint ? sizeof(struct key_hint) : 0);
9250fc853eSJohn Marino }
9350fc853eSJohn Marino
9450fc853eSJohn Marino /*
9550fc853eSJohn Marino * Calculate keys array size
9650fc853eSJohn Marino */
9750fc853eSJohn Marino size_t
keys_array_size(void)9850fc853eSJohn Marino keys_array_size(void)
9950fc853eSJohn Marino {
10050fc853eSJohn Marino
10150fc853eSJohn Marino return (keys_num * (sizeof(struct key_value) + key_hint_size()));
10250fc853eSJohn Marino }
10350fc853eSJohn Marino
10450fc853eSJohn Marino /*
10550fc853eSJohn Marino * Clean data of keys array
10650fc853eSJohn Marino */
10750fc853eSJohn Marino void
clean_keys_array(const struct bwstring * s,struct keys_array * ka)10850fc853eSJohn Marino clean_keys_array(const struct bwstring *s, struct keys_array *ka)
10950fc853eSJohn Marino {
11050fc853eSJohn Marino
11150fc853eSJohn Marino if (ka) {
11250fc853eSJohn Marino for (size_t i = 0; i < keys_num; ++i)
11350fc853eSJohn Marino if (ka->key[i].k && ka->key[i].k != s)
11450fc853eSJohn Marino bwsfree(ka->key[i].k);
11550fc853eSJohn Marino memset(ka, 0, keys_array_size());
11650fc853eSJohn Marino }
11750fc853eSJohn Marino }
11850fc853eSJohn Marino
11950fc853eSJohn Marino /*
12050fc853eSJohn Marino * Set value of a key in the keys set
12150fc853eSJohn Marino */
12250fc853eSJohn Marino void
set_key_on_keys_array(struct keys_array * ka,struct bwstring * s,size_t ind)12350fc853eSJohn Marino set_key_on_keys_array(struct keys_array *ka, struct bwstring *s, size_t ind)
12450fc853eSJohn Marino {
12550fc853eSJohn Marino
12650fc853eSJohn Marino if (ka && keys_num > ind) {
12750fc853eSJohn Marino struct key_value *kv;
12850fc853eSJohn Marino
12950fc853eSJohn Marino kv = &(ka->key[ind]);
13050fc853eSJohn Marino
13150fc853eSJohn Marino if (kv->k && kv->k != s)
13250fc853eSJohn Marino bwsfree(kv->k);
13350fc853eSJohn Marino kv->k = s;
13450fc853eSJohn Marino }
13550fc853eSJohn Marino }
13650fc853eSJohn Marino
13750fc853eSJohn Marino /*
13850fc853eSJohn Marino * Initialize a sort list item
13950fc853eSJohn Marino */
14050fc853eSJohn Marino struct sort_list_item *
sort_list_item_alloc(void)14150fc853eSJohn Marino sort_list_item_alloc(void)
14250fc853eSJohn Marino {
14350fc853eSJohn Marino struct sort_list_item *si;
14450fc853eSJohn Marino size_t sz;
14550fc853eSJohn Marino
14650fc853eSJohn Marino sz = sizeof(struct sort_list_item) + keys_array_size();
14750fc853eSJohn Marino si = sort_malloc(sz);
14850fc853eSJohn Marino memset(si, 0, sz);
14950fc853eSJohn Marino
15050fc853eSJohn Marino return (si);
15150fc853eSJohn Marino }
15250fc853eSJohn Marino
15350fc853eSJohn Marino size_t
sort_list_item_size(struct sort_list_item * si)15450fc853eSJohn Marino sort_list_item_size(struct sort_list_item *si)
15550fc853eSJohn Marino {
15650fc853eSJohn Marino size_t ret = 0;
15750fc853eSJohn Marino
15850fc853eSJohn Marino if (si) {
15950fc853eSJohn Marino ret = sizeof(struct sort_list_item) + keys_array_size();
16050fc853eSJohn Marino if (si->str)
16150fc853eSJohn Marino ret += bws_memsize(si->str);
16250fc853eSJohn Marino for (size_t i = 0; i < keys_num; ++i) {
16350fc853eSJohn Marino struct key_value *kv;
16450fc853eSJohn Marino
16550fc853eSJohn Marino kv = &(si->ka.key[i]);
16650fc853eSJohn Marino
16750fc853eSJohn Marino if (kv->k != si->str)
16850fc853eSJohn Marino ret += bws_memsize(kv->k);
16950fc853eSJohn Marino }
17050fc853eSJohn Marino }
17150fc853eSJohn Marino return (ret);
17250fc853eSJohn Marino }
17350fc853eSJohn Marino
17450fc853eSJohn Marino /*
17550fc853eSJohn Marino * Calculate key for a sort list item
17650fc853eSJohn Marino */
17750fc853eSJohn Marino static void
sort_list_item_make_key(struct sort_list_item * si)17850fc853eSJohn Marino sort_list_item_make_key(struct sort_list_item *si)
17950fc853eSJohn Marino {
18050fc853eSJohn Marino
18150fc853eSJohn Marino preproc(si->str, &(si->ka));
18250fc853eSJohn Marino }
18350fc853eSJohn Marino
18450fc853eSJohn Marino /*
18550fc853eSJohn Marino * Set value of a sort list item.
18650fc853eSJohn Marino * Return combined string and keys memory size.
18750fc853eSJohn Marino */
18850fc853eSJohn Marino void
sort_list_item_set(struct sort_list_item * si,struct bwstring * str)18950fc853eSJohn Marino sort_list_item_set(struct sort_list_item *si, struct bwstring *str)
19050fc853eSJohn Marino {
19150fc853eSJohn Marino
19250fc853eSJohn Marino if (si) {
19350fc853eSJohn Marino clean_keys_array(si->str, &(si->ka));
19450fc853eSJohn Marino if (si->str) {
19550fc853eSJohn Marino if (si->str == str) {
19650fc853eSJohn Marino /* we are trying to reset the same string */
19750fc853eSJohn Marino return;
19850fc853eSJohn Marino } else {
19950fc853eSJohn Marino bwsfree(si->str);
20050fc853eSJohn Marino si->str = NULL;
20150fc853eSJohn Marino }
20250fc853eSJohn Marino }
20350fc853eSJohn Marino si->str = str;
20450fc853eSJohn Marino sort_list_item_make_key(si);
20550fc853eSJohn Marino }
20650fc853eSJohn Marino }
20750fc853eSJohn Marino
20850fc853eSJohn Marino /*
20950fc853eSJohn Marino * De-allocate a sort list item object memory
21050fc853eSJohn Marino */
21150fc853eSJohn Marino void
sort_list_item_clean(struct sort_list_item * si)21250fc853eSJohn Marino sort_list_item_clean(struct sort_list_item *si)
21350fc853eSJohn Marino {
21450fc853eSJohn Marino
21550fc853eSJohn Marino if (si) {
21650fc853eSJohn Marino clean_keys_array(si->str, &(si->ka));
21750fc853eSJohn Marino if (si->str) {
21850fc853eSJohn Marino bwsfree(si->str);
21950fc853eSJohn Marino si->str = NULL;
22050fc853eSJohn Marino }
22150fc853eSJohn Marino }
22250fc853eSJohn Marino }
22350fc853eSJohn Marino
22450fc853eSJohn Marino /*
22550fc853eSJohn Marino * Skip columns according to specs
22650fc853eSJohn Marino */
22750fc853eSJohn Marino static size_t
skip_cols_to_start(const struct bwstring * s,size_t cols,size_t start,bool skip_blanks,bool * empty_key)22850fc853eSJohn Marino skip_cols_to_start(const struct bwstring *s, size_t cols, size_t start,
22950fc853eSJohn Marino bool skip_blanks, bool *empty_key)
23050fc853eSJohn Marino {
23150fc853eSJohn Marino if (cols < 1)
23250fc853eSJohn Marino return (BWSLEN(s) + 1);
23350fc853eSJohn Marino
23450fc853eSJohn Marino if (skip_blanks)
23550fc853eSJohn Marino while (start < BWSLEN(s) && iswblank(BWS_GET(s,start)))
23650fc853eSJohn Marino ++start;
23750fc853eSJohn Marino
23850fc853eSJohn Marino while (start < BWSLEN(s) && cols > 1) {
23950fc853eSJohn Marino --cols;
24050fc853eSJohn Marino ++start;
24150fc853eSJohn Marino }
24250fc853eSJohn Marino
24350fc853eSJohn Marino if (start >= BWSLEN(s))
24450fc853eSJohn Marino *empty_key = true;
24550fc853eSJohn Marino
24650fc853eSJohn Marino return (start);
24750fc853eSJohn Marino }
24850fc853eSJohn Marino
24950fc853eSJohn Marino /*
25050fc853eSJohn Marino * Skip fields according to specs
25150fc853eSJohn Marino */
25250fc853eSJohn Marino static size_t
skip_fields_to_start(const struct bwstring * s,size_t fields,bool * empty_field)25350fc853eSJohn Marino skip_fields_to_start(const struct bwstring *s, size_t fields, bool *empty_field)
25450fc853eSJohn Marino {
25550fc853eSJohn Marino
25650fc853eSJohn Marino if (fields < 2) {
25750fc853eSJohn Marino if (BWSLEN(s) == 0)
25850fc853eSJohn Marino *empty_field = true;
25950fc853eSJohn Marino return (0);
26050fc853eSJohn Marino } else if (!(sort_opts_vals.tflag)) {
26150fc853eSJohn Marino size_t cpos = 0;
26250fc853eSJohn Marino bool pb = true;
26350fc853eSJohn Marino
26450fc853eSJohn Marino while (cpos < BWSLEN(s)) {
26550fc853eSJohn Marino bool isblank;
26650fc853eSJohn Marino
26750fc853eSJohn Marino isblank = iswblank(BWS_GET(s, cpos));
26850fc853eSJohn Marino
26950fc853eSJohn Marino if (isblank && !pb) {
27050fc853eSJohn Marino --fields;
27150fc853eSJohn Marino if (fields <= 1)
27250fc853eSJohn Marino return (cpos);
27350fc853eSJohn Marino }
27450fc853eSJohn Marino pb = isblank;
27550fc853eSJohn Marino ++cpos;
27650fc853eSJohn Marino }
27750fc853eSJohn Marino if (fields > 1)
27850fc853eSJohn Marino *empty_field = true;
27950fc853eSJohn Marino return (cpos);
28050fc853eSJohn Marino } else {
28150fc853eSJohn Marino size_t cpos = 0;
28250fc853eSJohn Marino
28350fc853eSJohn Marino while (cpos < BWSLEN(s)) {
28450fc853eSJohn Marino if (BWS_GET(s,cpos) == (wchar_t)sort_opts_vals.field_sep) {
28550fc853eSJohn Marino --fields;
28650fc853eSJohn Marino if (fields <= 1)
28750fc853eSJohn Marino return (cpos + 1);
28850fc853eSJohn Marino }
28950fc853eSJohn Marino ++cpos;
29050fc853eSJohn Marino }
29150fc853eSJohn Marino if (fields > 1)
29250fc853eSJohn Marino *empty_field = true;
29350fc853eSJohn Marino return (cpos);
29450fc853eSJohn Marino }
29550fc853eSJohn Marino }
29650fc853eSJohn Marino
29750fc853eSJohn Marino /*
29850fc853eSJohn Marino * Find fields start
29950fc853eSJohn Marino */
30050fc853eSJohn Marino static void
find_field_start(const struct bwstring * s,struct key_specs * ks,size_t * field_start,size_t * key_start,bool * empty_field,bool * empty_key)30150fc853eSJohn Marino find_field_start(const struct bwstring *s, struct key_specs *ks,
30250fc853eSJohn Marino size_t *field_start, size_t *key_start, bool *empty_field, bool *empty_key)
30350fc853eSJohn Marino {
30450fc853eSJohn Marino
30550fc853eSJohn Marino *field_start = skip_fields_to_start(s, ks->f1, empty_field);
30650fc853eSJohn Marino if (!*empty_field)
30750fc853eSJohn Marino *key_start = skip_cols_to_start(s, ks->c1, *field_start,
30850fc853eSJohn Marino ks->pos1b, empty_key);
30950fc853eSJohn Marino else
31050fc853eSJohn Marino *empty_key = true;
31150fc853eSJohn Marino }
31250fc853eSJohn Marino
31350fc853eSJohn Marino /*
31450fc853eSJohn Marino * Find end key position
31550fc853eSJohn Marino */
31650fc853eSJohn Marino static size_t
find_field_end(const struct bwstring * s,struct key_specs * ks)31750fc853eSJohn Marino find_field_end(const struct bwstring *s, struct key_specs *ks)
31850fc853eSJohn Marino {
31950fc853eSJohn Marino size_t f2, next_field_start, pos_end;
32050fc853eSJohn Marino bool empty_field, empty_key;
32150fc853eSJohn Marino
32250fc853eSJohn Marino pos_end = 0;
32350fc853eSJohn Marino next_field_start = 0;
32450fc853eSJohn Marino empty_field = false;
32550fc853eSJohn Marino empty_key = false;
32650fc853eSJohn Marino f2 = ks->f2;
32750fc853eSJohn Marino
32850fc853eSJohn Marino if (f2 == 0)
32950fc853eSJohn Marino return (BWSLEN(s) + 1);
33050fc853eSJohn Marino else {
33150fc853eSJohn Marino if (ks->c2 == 0) {
33250fc853eSJohn Marino next_field_start = skip_fields_to_start(s, f2 + 1,
33350fc853eSJohn Marino &empty_field);
33450fc853eSJohn Marino if ((next_field_start > 0) && sort_opts_vals.tflag &&
33550fc853eSJohn Marino ((wchar_t)sort_opts_vals.field_sep == BWS_GET(s,
33650fc853eSJohn Marino next_field_start - 1)))
33750fc853eSJohn Marino --next_field_start;
33850fc853eSJohn Marino } else
33950fc853eSJohn Marino next_field_start = skip_fields_to_start(s, f2,
34050fc853eSJohn Marino &empty_field);
34150fc853eSJohn Marino }
34250fc853eSJohn Marino
34350fc853eSJohn Marino if (empty_field || (next_field_start >= BWSLEN(s)))
34450fc853eSJohn Marino return (BWSLEN(s) + 1);
34550fc853eSJohn Marino
34650fc853eSJohn Marino if (ks->c2) {
34750fc853eSJohn Marino pos_end = skip_cols_to_start(s, ks->c2, next_field_start,
34850fc853eSJohn Marino ks->pos2b, &empty_key);
34950fc853eSJohn Marino if (pos_end < BWSLEN(s))
35050fc853eSJohn Marino ++pos_end;
35150fc853eSJohn Marino } else
35250fc853eSJohn Marino pos_end = next_field_start;
35350fc853eSJohn Marino
35450fc853eSJohn Marino return (pos_end);
35550fc853eSJohn Marino }
35650fc853eSJohn Marino
35750fc853eSJohn Marino /*
35850fc853eSJohn Marino * Cut a field according to the key specs
35950fc853eSJohn Marino */
36050fc853eSJohn Marino static struct bwstring *
cut_field(const struct bwstring * s,struct key_specs * ks)36150fc853eSJohn Marino cut_field(const struct bwstring *s, struct key_specs *ks)
36250fc853eSJohn Marino {
36350fc853eSJohn Marino struct bwstring *ret = NULL;
36450fc853eSJohn Marino
36550fc853eSJohn Marino if (s && ks) {
36650fc853eSJohn Marino size_t field_start, key_end, key_start, sz;
36750fc853eSJohn Marino bool empty_field, empty_key;
36850fc853eSJohn Marino
36950fc853eSJohn Marino field_start = 0;
37050fc853eSJohn Marino key_start = 0;
37150fc853eSJohn Marino empty_field = false;
37250fc853eSJohn Marino empty_key = false;
37350fc853eSJohn Marino
37450fc853eSJohn Marino find_field_start(s, ks, &field_start, &key_start,
37550fc853eSJohn Marino &empty_field, &empty_key);
37650fc853eSJohn Marino
37750fc853eSJohn Marino if (empty_key)
37850fc853eSJohn Marino sz = 0;
37950fc853eSJohn Marino else {
38050fc853eSJohn Marino key_end = find_field_end(s, ks);
38150fc853eSJohn Marino sz = (key_end < key_start) ? 0 : (key_end - key_start);
38250fc853eSJohn Marino }
38350fc853eSJohn Marino
38450fc853eSJohn Marino ret = bwsalloc(sz);
38550fc853eSJohn Marino if (sz)
38650fc853eSJohn Marino bwsnocpy(ret, s, key_start, sz);
38750fc853eSJohn Marino } else
38850fc853eSJohn Marino ret = bwsalloc(0);
38950fc853eSJohn Marino
39050fc853eSJohn Marino return (ret);
39150fc853eSJohn Marino }
39250fc853eSJohn Marino
39350fc853eSJohn Marino /*
39450fc853eSJohn Marino * Preprocesses a line applying the necessary transformations
39550fc853eSJohn Marino * specified by command line options and returns the preprocessed
39650fc853eSJohn Marino * string, which can be used to compare.
39750fc853eSJohn Marino */
39850fc853eSJohn Marino int
preproc(struct bwstring * s,struct keys_array * ka)39950fc853eSJohn Marino preproc(struct bwstring *s, struct keys_array *ka)
40050fc853eSJohn Marino {
40150fc853eSJohn Marino
40250fc853eSJohn Marino if (sort_opts_vals.kflag)
40350fc853eSJohn Marino for (size_t i = 0; i < keys_num; i++) {
40450fc853eSJohn Marino struct bwstring *key;
40550fc853eSJohn Marino struct key_specs *kspecs;
40650fc853eSJohn Marino struct sort_mods *sm;
40750fc853eSJohn Marino
40850fc853eSJohn Marino kspecs = &(keys[i]);
40950fc853eSJohn Marino key = cut_field(s, kspecs);
41050fc853eSJohn Marino
41150fc853eSJohn Marino sm = &(kspecs->sm);
41250fc853eSJohn Marino if (sm->dflag)
41350fc853eSJohn Marino key = dictionary_order(key);
41450fc853eSJohn Marino else if (sm->iflag)
41550fc853eSJohn Marino key = ignore_nonprinting(key);
41650fc853eSJohn Marino if (sm->fflag || sm->Mflag)
41750fc853eSJohn Marino key = ignore_case(key);
41850fc853eSJohn Marino
41950fc853eSJohn Marino set_key_on_keys_array(ka, key, i);
42050fc853eSJohn Marino }
42150fc853eSJohn Marino else {
42250fc853eSJohn Marino struct bwstring *ret = NULL;
42350fc853eSJohn Marino struct sort_mods *sm = default_sort_mods;
42450fc853eSJohn Marino
42550fc853eSJohn Marino if (sm->bflag) {
42650fc853eSJohn Marino if (ret == NULL)
42750fc853eSJohn Marino ret = bwsdup(s);
42850fc853eSJohn Marino ret = ignore_leading_blanks(ret);
42950fc853eSJohn Marino }
43050fc853eSJohn Marino if (sm->dflag) {
43150fc853eSJohn Marino if (ret == NULL)
43250fc853eSJohn Marino ret = bwsdup(s);
43350fc853eSJohn Marino ret = dictionary_order(ret);
43450fc853eSJohn Marino } else if (sm->iflag) {
43550fc853eSJohn Marino if (ret == NULL)
43650fc853eSJohn Marino ret = bwsdup(s);
43750fc853eSJohn Marino ret = ignore_nonprinting(ret);
43850fc853eSJohn Marino }
43950fc853eSJohn Marino if (sm->fflag || sm->Mflag) {
44050fc853eSJohn Marino if (ret == NULL)
44150fc853eSJohn Marino ret = bwsdup(s);
44250fc853eSJohn Marino ret = ignore_case(ret);
44350fc853eSJohn Marino }
44450fc853eSJohn Marino if (ret == NULL)
44550fc853eSJohn Marino set_key_on_keys_array(ka, s, 0);
44650fc853eSJohn Marino else
44750fc853eSJohn Marino set_key_on_keys_array(ka, ret, 0);
44850fc853eSJohn Marino }
44950fc853eSJohn Marino
45050fc853eSJohn Marino return 0;
45150fc853eSJohn Marino }
45250fc853eSJohn Marino
45350fc853eSJohn Marino cmpcoll_t
get_sort_func(struct sort_mods * sm)45450fc853eSJohn Marino get_sort_func(struct sort_mods *sm)
45550fc853eSJohn Marino {
45650fc853eSJohn Marino
45750fc853eSJohn Marino if (sm->nflag)
45850fc853eSJohn Marino return (numcoll);
45950fc853eSJohn Marino else if (sm->hflag)
46050fc853eSJohn Marino return (hnumcoll);
46150fc853eSJohn Marino else if (sm->gflag)
46250fc853eSJohn Marino return (gnumcoll);
46350fc853eSJohn Marino else if (sm->Mflag)
46450fc853eSJohn Marino return (monthcoll);
4656d7e22ecSzrj #if defined(SORT_RANDOM)
46650fc853eSJohn Marino else if (sm->Rflag)
46750fc853eSJohn Marino return (randomcoll);
4686d7e22ecSzrj #endif
46950fc853eSJohn Marino else if (sm->Vflag)
47050fc853eSJohn Marino return (versioncoll);
47150fc853eSJohn Marino else
47250fc853eSJohn Marino return (wstrcoll);
47350fc853eSJohn Marino }
47450fc853eSJohn Marino
47550fc853eSJohn Marino /*
47650fc853eSJohn Marino * Compares the given strings. Returns a positive number if
47750fc853eSJohn Marino * the first precedes the second, a negative number if the second is
47850fc853eSJohn Marino * the preceding one, and zero if they are equal. This function calls
47950fc853eSJohn Marino * the underlying collate functions, which done the actual comparison.
48050fc853eSJohn Marino */
48150fc853eSJohn Marino int
key_coll(struct keys_array * ps1,struct keys_array * ps2,size_t offset)48250fc853eSJohn Marino key_coll(struct keys_array *ps1, struct keys_array *ps2, size_t offset)
48350fc853eSJohn Marino {
48450fc853eSJohn Marino struct sort_mods *sm;
48550fc853eSJohn Marino int res = 0;
48650fc853eSJohn Marino
48750fc853eSJohn Marino for (size_t i = 0; i < keys_num; ++i) {
48850fc853eSJohn Marino sm = &(keys[i].sm);
48950fc853eSJohn Marino
49050fc853eSJohn Marino if (sm->rflag)
49150fc853eSJohn Marino res = sm->func(&(ps2->key[i]), &(ps1->key[i]), offset);
49250fc853eSJohn Marino else
49350fc853eSJohn Marino res = sm->func(&(ps1->key[i]), &(ps2->key[i]), offset);
49450fc853eSJohn Marino
49550fc853eSJohn Marino if (res)
49650fc853eSJohn Marino break;
49750fc853eSJohn Marino
49850fc853eSJohn Marino /* offset applies to only the first key */
49950fc853eSJohn Marino offset = 0;
50050fc853eSJohn Marino }
50150fc853eSJohn Marino return (res);
50250fc853eSJohn Marino }
50350fc853eSJohn Marino
50450fc853eSJohn Marino /*
50550fc853eSJohn Marino * Compare two strings.
50650fc853eSJohn Marino * Plain symbol-by-symbol comparison.
50750fc853eSJohn Marino */
50850fc853eSJohn Marino int
top_level_str_coll(const struct bwstring * s1,const struct bwstring * s2)50950fc853eSJohn Marino top_level_str_coll(const struct bwstring *s1, const struct bwstring *s2)
51050fc853eSJohn Marino {
51150fc853eSJohn Marino
51250fc853eSJohn Marino if (default_sort_mods->rflag) {
51350fc853eSJohn Marino const struct bwstring *tmp;
51450fc853eSJohn Marino
51550fc853eSJohn Marino tmp = s1;
51650fc853eSJohn Marino s1 = s2;
51750fc853eSJohn Marino s2 = tmp;
51850fc853eSJohn Marino }
51950fc853eSJohn Marino
52050fc853eSJohn Marino return (bwscoll(s1, s2, 0));
52150fc853eSJohn Marino }
52250fc853eSJohn Marino
52350fc853eSJohn Marino /*
52450fc853eSJohn Marino * Compare a string and a sort list item, according to the sort specs.
52550fc853eSJohn Marino */
52650fc853eSJohn Marino int
str_list_coll(struct bwstring * str1,struct sort_list_item ** ss2)52750fc853eSJohn Marino str_list_coll(struct bwstring *str1, struct sort_list_item **ss2)
52850fc853eSJohn Marino {
52950fc853eSJohn Marino struct keys_array *ka1;
53050fc853eSJohn Marino int ret = 0;
53150fc853eSJohn Marino
53250fc853eSJohn Marino ka1 = keys_array_alloc();
53350fc853eSJohn Marino
53450fc853eSJohn Marino preproc(str1, ka1);
53550fc853eSJohn Marino
53650fc853eSJohn Marino sort_list_item_make_key(*ss2);
53750fc853eSJohn Marino
53850fc853eSJohn Marino if (debug_sort) {
53950fc853eSJohn Marino bwsprintf(stdout, str1, "; s1=<", ">");
54050fc853eSJohn Marino bwsprintf(stdout, (*ss2)->str, ", s2=<", ">");
54150fc853eSJohn Marino }
54250fc853eSJohn Marino
54350fc853eSJohn Marino ret = key_coll(ka1, &((*ss2)->ka), 0);
54450fc853eSJohn Marino
54550fc853eSJohn Marino if (debug_sort)
54650fc853eSJohn Marino printf("; cmp1=%d", ret);
54750fc853eSJohn Marino
54850fc853eSJohn Marino clean_keys_array(str1, ka1);
54950fc853eSJohn Marino sort_free(ka1);
55050fc853eSJohn Marino
55150fc853eSJohn Marino if ((ret == 0) && !(sort_opts_vals.sflag) && sort_opts_vals.complex_sort) {
55250fc853eSJohn Marino ret = top_level_str_coll(str1, ((*ss2)->str));
55350fc853eSJohn Marino if (debug_sort)
55450fc853eSJohn Marino printf("; cmp2=%d", ret);
55550fc853eSJohn Marino }
55650fc853eSJohn Marino
55750fc853eSJohn Marino if (debug_sort)
55850fc853eSJohn Marino printf("\n");
55950fc853eSJohn Marino
56050fc853eSJohn Marino return (ret);
56150fc853eSJohn Marino }
56250fc853eSJohn Marino
56350fc853eSJohn Marino /*
56450fc853eSJohn Marino * Compare two sort list items, according to the sort specs.
56550fc853eSJohn Marino */
56650fc853eSJohn Marino int
list_coll_offset(struct sort_list_item ** ss1,struct sort_list_item ** ss2,size_t offset)56750fc853eSJohn Marino list_coll_offset(struct sort_list_item **ss1, struct sort_list_item **ss2,
56850fc853eSJohn Marino size_t offset)
56950fc853eSJohn Marino {
57050fc853eSJohn Marino int ret;
57150fc853eSJohn Marino
57250fc853eSJohn Marino ret = key_coll(&((*ss1)->ka), &((*ss2)->ka), offset);
57350fc853eSJohn Marino
57450fc853eSJohn Marino if (debug_sort) {
57550fc853eSJohn Marino if (offset)
57650fc853eSJohn Marino printf("; offset=%d", (int) offset);
57750fc853eSJohn Marino bwsprintf(stdout, ((*ss1)->str), "; s1=<", ">");
57850fc853eSJohn Marino bwsprintf(stdout, ((*ss2)->str), ", s2=<", ">");
57950fc853eSJohn Marino printf("; cmp1=%d\n", ret);
58050fc853eSJohn Marino }
58150fc853eSJohn Marino
58250fc853eSJohn Marino if (ret)
58350fc853eSJohn Marino return (ret);
58450fc853eSJohn Marino
58550fc853eSJohn Marino if (!(sort_opts_vals.sflag) && sort_opts_vals.complex_sort) {
58650fc853eSJohn Marino ret = top_level_str_coll(((*ss1)->str), ((*ss2)->str));
58750fc853eSJohn Marino if (debug_sort)
58850fc853eSJohn Marino printf("; cmp2=%d\n", ret);
58950fc853eSJohn Marino }
59050fc853eSJohn Marino
59150fc853eSJohn Marino return (ret);
59250fc853eSJohn Marino }
59350fc853eSJohn Marino
59450fc853eSJohn Marino /*
59550fc853eSJohn Marino * Compare two sort list items, according to the sort specs.
59650fc853eSJohn Marino */
59750fc853eSJohn Marino int
list_coll(struct sort_list_item ** ss1,struct sort_list_item ** ss2)59850fc853eSJohn Marino list_coll(struct sort_list_item **ss1, struct sort_list_item **ss2)
59950fc853eSJohn Marino {
60050fc853eSJohn Marino
60150fc853eSJohn Marino return (list_coll_offset(ss1, ss2, 0));
60250fc853eSJohn Marino }
60350fc853eSJohn Marino
60450fc853eSJohn Marino #define LSCDEF(N) \
60550fc853eSJohn Marino static int \
60650fc853eSJohn Marino list_coll_##N(struct sort_list_item **ss1, struct sort_list_item **ss2) \
60750fc853eSJohn Marino { \
60850fc853eSJohn Marino \
60950fc853eSJohn Marino return (list_coll_offset(ss1, ss2, N)); \
61050fc853eSJohn Marino }
61150fc853eSJohn Marino
61250fc853eSJohn Marino LSCDEF(1)
61350fc853eSJohn Marino LSCDEF(2)
61450fc853eSJohn Marino LSCDEF(3)
61550fc853eSJohn Marino LSCDEF(4)
61650fc853eSJohn Marino LSCDEF(5)
61750fc853eSJohn Marino LSCDEF(6)
61850fc853eSJohn Marino LSCDEF(7)
61950fc853eSJohn Marino LSCDEF(8)
62050fc853eSJohn Marino LSCDEF(9)
62150fc853eSJohn Marino LSCDEF(10)
62250fc853eSJohn Marino LSCDEF(11)
62350fc853eSJohn Marino LSCDEF(12)
62450fc853eSJohn Marino LSCDEF(13)
62550fc853eSJohn Marino LSCDEF(14)
62650fc853eSJohn Marino LSCDEF(15)
62750fc853eSJohn Marino LSCDEF(16)
62850fc853eSJohn Marino LSCDEF(17)
62950fc853eSJohn Marino LSCDEF(18)
63050fc853eSJohn Marino LSCDEF(19)
63150fc853eSJohn Marino LSCDEF(20)
63250fc853eSJohn Marino
63350fc853eSJohn Marino listcoll_t
get_list_call_func(size_t offset)63450fc853eSJohn Marino get_list_call_func(size_t offset)
63550fc853eSJohn Marino {
63650fc853eSJohn Marino static const listcoll_t lsarray[] = { list_coll, list_coll_1,
63750fc853eSJohn Marino list_coll_2, list_coll_3, list_coll_4, list_coll_5,
63850fc853eSJohn Marino list_coll_6, list_coll_7, list_coll_8, list_coll_9,
63950fc853eSJohn Marino list_coll_10, list_coll_11, list_coll_12, list_coll_13,
64050fc853eSJohn Marino list_coll_14, list_coll_15, list_coll_16, list_coll_17,
64150fc853eSJohn Marino list_coll_18, list_coll_19, list_coll_20 };
64250fc853eSJohn Marino
64350fc853eSJohn Marino if (offset <= 20)
64450fc853eSJohn Marino return (lsarray[offset]);
64550fc853eSJohn Marino
64650fc853eSJohn Marino return (list_coll);
64750fc853eSJohn Marino }
64850fc853eSJohn Marino
64950fc853eSJohn Marino /*
65050fc853eSJohn Marino * Compare two sort list items, only by their original string.
65150fc853eSJohn Marino */
65250fc853eSJohn Marino int
list_coll_by_str_only(struct sort_list_item ** ss1,struct sort_list_item ** ss2)65350fc853eSJohn Marino list_coll_by_str_only(struct sort_list_item **ss1, struct sort_list_item **ss2)
65450fc853eSJohn Marino {
65550fc853eSJohn Marino
65650fc853eSJohn Marino return (top_level_str_coll(((*ss1)->str), ((*ss2)->str)));
65750fc853eSJohn Marino }
65850fc853eSJohn Marino
65950fc853eSJohn Marino /*
66050fc853eSJohn Marino * Maximum size of a number in the string (before or after decimal point)
66150fc853eSJohn Marino */
66250fc853eSJohn Marino #define MAX_NUM_SIZE (128)
66350fc853eSJohn Marino
66450fc853eSJohn Marino /*
66550fc853eSJohn Marino * Set suffix value
66650fc853eSJohn Marino */
setsuffix(wchar_t c,unsigned char * si)66750fc853eSJohn Marino static void setsuffix(wchar_t c, unsigned char *si)
66850fc853eSJohn Marino {
66950fc853eSJohn Marino switch (c){
67050fc853eSJohn Marino case L'k':
67150fc853eSJohn Marino case L'K':
67250fc853eSJohn Marino *si = 1;
67350fc853eSJohn Marino break;
67450fc853eSJohn Marino case L'M':
67550fc853eSJohn Marino *si = 2;
67650fc853eSJohn Marino break;
67750fc853eSJohn Marino case L'G':
67850fc853eSJohn Marino *si = 3;
67950fc853eSJohn Marino break;
68050fc853eSJohn Marino case L'T':
68150fc853eSJohn Marino *si = 4;
68250fc853eSJohn Marino break;
68350fc853eSJohn Marino case L'P':
68450fc853eSJohn Marino *si = 5;
68550fc853eSJohn Marino break;
68650fc853eSJohn Marino case L'E':
68750fc853eSJohn Marino *si = 6;
68850fc853eSJohn Marino break;
68950fc853eSJohn Marino case L'Z':
69050fc853eSJohn Marino *si = 7;
69150fc853eSJohn Marino break;
69250fc853eSJohn Marino case L'Y':
69350fc853eSJohn Marino *si = 8;
69450fc853eSJohn Marino break;
69550fc853eSJohn Marino default:
69650fc853eSJohn Marino *si = 0;
69750fc853eSJohn Marino };
69850fc853eSJohn Marino }
69950fc853eSJohn Marino
70050fc853eSJohn Marino /*
70150fc853eSJohn Marino * Read string s and parse the string into a fixed-decimal-point number.
70250fc853eSJohn Marino * sign equals -1 if the number is negative (explicit plus is not allowed,
70350fc853eSJohn Marino * according to GNU sort's "info sort".
70450fc853eSJohn Marino * The number part before decimal point is in the smain, after the decimal
70550fc853eSJohn Marino * point is in sfrac, tail is the pointer to the remainder of the string.
70650fc853eSJohn Marino */
70750fc853eSJohn Marino static int
read_number(struct bwstring * s0,int * sign,wchar_t * smain,size_t * main_len,wchar_t * sfrac,size_t * frac_len,unsigned char * si)70850fc853eSJohn Marino read_number(struct bwstring *s0, int *sign, wchar_t *smain, size_t *main_len, wchar_t *sfrac, size_t *frac_len, unsigned char *si)
70950fc853eSJohn Marino {
71050fc853eSJohn Marino bwstring_iterator s;
71150fc853eSJohn Marino
71250fc853eSJohn Marino s = bws_begin(s0);
71350fc853eSJohn Marino
71450fc853eSJohn Marino /* always end the fraction with zero, even if we have no fraction */
71550fc853eSJohn Marino sfrac[0] = 0;
71650fc853eSJohn Marino
71750fc853eSJohn Marino while (iswblank(bws_get_iter_value(s)))
71850fc853eSJohn Marino s = bws_iterator_inc(s, 1);
71950fc853eSJohn Marino
72050fc853eSJohn Marino if (bws_get_iter_value(s) == (wchar_t)symbol_negative_sign) {
72150fc853eSJohn Marino *sign = -1;
72250fc853eSJohn Marino s = bws_iterator_inc(s, 1);
72350fc853eSJohn Marino }
72450fc853eSJohn Marino
72550fc853eSJohn Marino // This is '0', not '\0', do not change this
72650fc853eSJohn Marino while (iswdigit(bws_get_iter_value(s)) &&
72750fc853eSJohn Marino (bws_get_iter_value(s) == L'0'))
72850fc853eSJohn Marino s = bws_iterator_inc(s, 1);
72950fc853eSJohn Marino
73050fc853eSJohn Marino while (bws_get_iter_value(s) && *main_len < MAX_NUM_SIZE) {
73150fc853eSJohn Marino if (iswdigit(bws_get_iter_value(s))) {
73250fc853eSJohn Marino smain[*main_len] = bws_get_iter_value(s);
73350fc853eSJohn Marino s = bws_iterator_inc(s, 1);
73450fc853eSJohn Marino *main_len += 1;
73550fc853eSJohn Marino } else if (symbol_thousands_sep &&
73650fc853eSJohn Marino (bws_get_iter_value(s) == (wchar_t)symbol_thousands_sep))
73750fc853eSJohn Marino s = bws_iterator_inc(s, 1);
73850fc853eSJohn Marino else
73950fc853eSJohn Marino break;
74050fc853eSJohn Marino }
74150fc853eSJohn Marino
74250fc853eSJohn Marino smain[*main_len] = 0;
74350fc853eSJohn Marino
74450fc853eSJohn Marino if (bws_get_iter_value(s) == (wchar_t)symbol_decimal_point) {
74550fc853eSJohn Marino s = bws_iterator_inc(s, 1);
74650fc853eSJohn Marino while (iswdigit(bws_get_iter_value(s)) &&
74750fc853eSJohn Marino *frac_len < MAX_NUM_SIZE) {
74850fc853eSJohn Marino sfrac[*frac_len] = bws_get_iter_value(s);
74950fc853eSJohn Marino s = bws_iterator_inc(s, 1);
75050fc853eSJohn Marino *frac_len += 1;
75150fc853eSJohn Marino }
75250fc853eSJohn Marino sfrac[*frac_len] = 0;
75350fc853eSJohn Marino
75450fc853eSJohn Marino while (*frac_len > 0 && sfrac[*frac_len - 1] == L'0') {
75550fc853eSJohn Marino --(*frac_len);
75650fc853eSJohn Marino sfrac[*frac_len] = L'\0';
75750fc853eSJohn Marino }
75850fc853eSJohn Marino }
75950fc853eSJohn Marino
76050fc853eSJohn Marino setsuffix(bws_get_iter_value(s),si);
76150fc853eSJohn Marino
76250fc853eSJohn Marino if ((*main_len + *frac_len) == 0)
76350fc853eSJohn Marino *sign = 0;
76450fc853eSJohn Marino
76550fc853eSJohn Marino return (0);
76650fc853eSJohn Marino }
76750fc853eSJohn Marino
76850fc853eSJohn Marino /*
76950fc853eSJohn Marino * Implements string sort.
77050fc853eSJohn Marino */
77150fc853eSJohn Marino static int
wstrcoll(struct key_value * kv1,struct key_value * kv2,size_t offset)77250fc853eSJohn Marino wstrcoll(struct key_value *kv1, struct key_value *kv2, size_t offset)
77350fc853eSJohn Marino {
77450fc853eSJohn Marino
77550fc853eSJohn Marino if (debug_sort) {
77650fc853eSJohn Marino if (offset)
77750fc853eSJohn Marino printf("; offset=%d\n", (int) offset);
77850fc853eSJohn Marino bwsprintf(stdout, kv1->k, "; k1=<", ">");
77950fc853eSJohn Marino printf("(%zu)", BWSLEN(kv1->k));
78050fc853eSJohn Marino bwsprintf(stdout, kv2->k, ", k2=<", ">");
78150fc853eSJohn Marino printf("(%zu)", BWSLEN(kv2->k));
78250fc853eSJohn Marino }
78350fc853eSJohn Marino
78450fc853eSJohn Marino return (bwscoll(kv1->k, kv2->k, offset));
78550fc853eSJohn Marino }
78650fc853eSJohn Marino
78750fc853eSJohn Marino /*
78850fc853eSJohn Marino * Compare two suffixes
78950fc853eSJohn Marino */
79050fc853eSJohn Marino static inline int
cmpsuffix(unsigned char si1,unsigned char si2)79150fc853eSJohn Marino cmpsuffix(unsigned char si1, unsigned char si2)
79250fc853eSJohn Marino {
79350fc853eSJohn Marino
79450fc853eSJohn Marino return ((char)si1 - (char)si2);
79550fc853eSJohn Marino }
79650fc853eSJohn Marino
79750fc853eSJohn Marino /*
79850fc853eSJohn Marino * Implements numeric sort for -n and -h.
79950fc853eSJohn Marino */
80050fc853eSJohn Marino static int
numcoll_impl(struct key_value * kv1,struct key_value * kv2,size_t offset __unused,bool use_suffix)80150fc853eSJohn Marino numcoll_impl(struct key_value *kv1, struct key_value *kv2,
80250fc853eSJohn Marino size_t offset __unused, bool use_suffix)
80350fc853eSJohn Marino {
80450fc853eSJohn Marino struct bwstring *s1, *s2;
80550fc853eSJohn Marino wchar_t sfrac1[MAX_NUM_SIZE + 1], sfrac2[MAX_NUM_SIZE + 1];
80650fc853eSJohn Marino wchar_t smain1[MAX_NUM_SIZE + 1], smain2[MAX_NUM_SIZE + 1];
80750fc853eSJohn Marino int cmp_res, sign1, sign2;
80850fc853eSJohn Marino size_t frac1, frac2, main1, main2;
80950fc853eSJohn Marino unsigned char SI1, SI2;
81050fc853eSJohn Marino bool e1, e2, key1_read, key2_read;
81150fc853eSJohn Marino
81250fc853eSJohn Marino s1 = kv1->k;
81350fc853eSJohn Marino s2 = kv2->k;
81450fc853eSJohn Marino sign1 = sign2 = 0;
81550fc853eSJohn Marino main1 = main2 = 0;
81650fc853eSJohn Marino frac1 = frac2 = 0;
81750fc853eSJohn Marino
81850fc853eSJohn Marino cmp_res = 0;
81950fc853eSJohn Marino key1_read = key2_read = false;
82050fc853eSJohn Marino
82150fc853eSJohn Marino if (debug_sort) {
82250fc853eSJohn Marino bwsprintf(stdout, s1, "; k1=<", ">");
82350fc853eSJohn Marino bwsprintf(stdout, s2, ", k2=<", ">");
82450fc853eSJohn Marino }
82550fc853eSJohn Marino
82650fc853eSJohn Marino if (s1 == s2)
82750fc853eSJohn Marino return (0);
82850fc853eSJohn Marino
82950fc853eSJohn Marino if (kv1->hint->status == HS_UNINITIALIZED) {
83050fc853eSJohn Marino /* read the number from the string */
83150fc853eSJohn Marino read_number(s1, &sign1, smain1, &main1, sfrac1, &frac1, &SI1);
83250fc853eSJohn Marino key1_read = true;
83350fc853eSJohn Marino kv1->hint->v.nh.n1 = wcstoull(smain1, NULL, 10);
83450fc853eSJohn Marino if(main1 < 1 && frac1 < 1)
83550fc853eSJohn Marino kv1->hint->v.nh.empty=true;
83650fc853eSJohn Marino kv1->hint->v.nh.si = SI1;
83750fc853eSJohn Marino kv1->hint->status = (kv1->hint->v.nh.n1 != ULLONG_MAX) ?
83850fc853eSJohn Marino HS_INITIALIZED : HS_ERROR;
83950fc853eSJohn Marino kv1->hint->v.nh.neg = (sign1 < 0) ? true : false;
84050fc853eSJohn Marino }
84150fc853eSJohn Marino
84250fc853eSJohn Marino if (kv2->hint->status == HS_UNINITIALIZED) {
84350fc853eSJohn Marino /* read the number from the string */
84450fc853eSJohn Marino read_number(s2, &sign2, smain2, &main2, sfrac2, &frac2,&SI2);
84550fc853eSJohn Marino key2_read = true;
84650fc853eSJohn Marino kv2->hint->v.nh.n1 = wcstoull(smain2, NULL, 10);
84750fc853eSJohn Marino if(main2 < 1 && frac2 < 1)
84850fc853eSJohn Marino kv2->hint->v.nh.empty=true;
84950fc853eSJohn Marino kv2->hint->v.nh.si = SI2;
85050fc853eSJohn Marino kv2->hint->status = (kv2->hint->v.nh.n1 != ULLONG_MAX) ?
85150fc853eSJohn Marino HS_INITIALIZED : HS_ERROR;
85250fc853eSJohn Marino kv2->hint->v.nh.neg = (sign2 < 0) ? true : false;
85350fc853eSJohn Marino }
85450fc853eSJohn Marino
85550fc853eSJohn Marino if (kv1->hint->status == HS_INITIALIZED && kv2->hint->status ==
85650fc853eSJohn Marino HS_INITIALIZED) {
85750fc853eSJohn Marino unsigned long long n1, n2;
85850fc853eSJohn Marino bool neg1, neg2;
85950fc853eSJohn Marino
86050fc853eSJohn Marino e1 = kv1->hint->v.nh.empty;
86150fc853eSJohn Marino e2 = kv2->hint->v.nh.empty;
86250fc853eSJohn Marino
86350fc853eSJohn Marino if (e1 && e2)
86450fc853eSJohn Marino return (0);
86550fc853eSJohn Marino
86650fc853eSJohn Marino neg1 = kv1->hint->v.nh.neg;
86750fc853eSJohn Marino neg2 = kv2->hint->v.nh.neg;
86850fc853eSJohn Marino
86950fc853eSJohn Marino if (neg1 && !neg2)
87050fc853eSJohn Marino return (-1);
87150fc853eSJohn Marino if (neg2 && !neg1)
87250fc853eSJohn Marino return (+1);
87350fc853eSJohn Marino
87450fc853eSJohn Marino if (e1)
87550fc853eSJohn Marino return (neg2 ? +1 : -1);
87650fc853eSJohn Marino else if (e2)
87750fc853eSJohn Marino return (neg1 ? -1 : +1);
87850fc853eSJohn Marino
87950fc853eSJohn Marino
88050fc853eSJohn Marino if (use_suffix) {
88150fc853eSJohn Marino cmp_res = cmpsuffix(kv1->hint->v.nh.si, kv2->hint->v.nh.si);
88250fc853eSJohn Marino if (cmp_res)
88350fc853eSJohn Marino return (neg1 ? -cmp_res : cmp_res);
88450fc853eSJohn Marino }
88550fc853eSJohn Marino
88650fc853eSJohn Marino n1 = kv1->hint->v.nh.n1;
88750fc853eSJohn Marino n2 = kv2->hint->v.nh.n1;
88850fc853eSJohn Marino if (n1 < n2)
88950fc853eSJohn Marino return (neg1 ? +1 : -1);
89050fc853eSJohn Marino else if (n1 > n2)
89150fc853eSJohn Marino return (neg1 ? -1 : +1);
89250fc853eSJohn Marino }
89350fc853eSJohn Marino
89450fc853eSJohn Marino /* read the numbers from the strings */
89550fc853eSJohn Marino if (!key1_read)
89650fc853eSJohn Marino read_number(s1, &sign1, smain1, &main1, sfrac1, &frac1, &SI1);
89750fc853eSJohn Marino if (!key2_read)
89850fc853eSJohn Marino read_number(s2, &sign2, smain2, &main2, sfrac2, &frac2, &SI2);
89950fc853eSJohn Marino
90050fc853eSJohn Marino e1 = ((main1 + frac1) == 0);
90150fc853eSJohn Marino e2 = ((main2 + frac2) == 0);
90250fc853eSJohn Marino
90350fc853eSJohn Marino if (e1 && e2)
90450fc853eSJohn Marino return (0);
90550fc853eSJohn Marino
90650fc853eSJohn Marino /* we know the result if the signs are different */
90750fc853eSJohn Marino if (sign1 < 0 && sign2 >= 0)
90850fc853eSJohn Marino return (-1);
90950fc853eSJohn Marino if (sign1 >= 0 && sign2 < 0)
91050fc853eSJohn Marino return (+1);
91150fc853eSJohn Marino
91250fc853eSJohn Marino if (e1)
91350fc853eSJohn Marino return ((sign2 < 0) ? +1 : -1);
91450fc853eSJohn Marino else if (e2)
91550fc853eSJohn Marino return ((sign1 < 0) ? -1 : +1);
91650fc853eSJohn Marino
91750fc853eSJohn Marino if (use_suffix) {
91850fc853eSJohn Marino cmp_res = cmpsuffix(SI1, SI2);
91950fc853eSJohn Marino if (cmp_res)
92050fc853eSJohn Marino return ((sign1 < 0) ? -cmp_res : cmp_res);
92150fc853eSJohn Marino }
92250fc853eSJohn Marino
92350fc853eSJohn Marino /* if both numbers are empty assume that the strings are equal */
92450fc853eSJohn Marino if (main1 < 1 && main2 < 1 && frac1 < 1 && frac2 < 1)
92550fc853eSJohn Marino return (0);
92650fc853eSJohn Marino
92750fc853eSJohn Marino /*
92850fc853eSJohn Marino * if the main part is of different size, we know the result
92950fc853eSJohn Marino * (because the leading zeros are removed)
93050fc853eSJohn Marino */
93150fc853eSJohn Marino if (main1 < main2)
93250fc853eSJohn Marino cmp_res = -1;
93350fc853eSJohn Marino else if (main1 > main2)
93450fc853eSJohn Marino cmp_res = +1;
93550fc853eSJohn Marino /* if the sizes are equal then simple non-collate string compare gives the correct result */
93650fc853eSJohn Marino else
93750fc853eSJohn Marino cmp_res = wcscmp(smain1, smain2);
93850fc853eSJohn Marino
93950fc853eSJohn Marino /* check fraction */
94050fc853eSJohn Marino if (!cmp_res)
94150fc853eSJohn Marino cmp_res = wcscmp(sfrac1, sfrac2);
94250fc853eSJohn Marino
94350fc853eSJohn Marino if (!cmp_res)
94450fc853eSJohn Marino return (0);
94550fc853eSJohn Marino
94650fc853eSJohn Marino /* reverse result if the signs are negative */
94750fc853eSJohn Marino if (sign1 < 0 && sign2 < 0)
94850fc853eSJohn Marino cmp_res = -cmp_res;
94950fc853eSJohn Marino
95050fc853eSJohn Marino return (cmp_res);
95150fc853eSJohn Marino }
95250fc853eSJohn Marino
95350fc853eSJohn Marino /*
95450fc853eSJohn Marino * Implements numeric sort (-n).
95550fc853eSJohn Marino */
95650fc853eSJohn Marino static int
numcoll(struct key_value * kv1,struct key_value * kv2,size_t offset)95750fc853eSJohn Marino numcoll(struct key_value *kv1, struct key_value *kv2, size_t offset)
95850fc853eSJohn Marino {
95950fc853eSJohn Marino
96050fc853eSJohn Marino return (numcoll_impl(kv1, kv2, offset, false));
96150fc853eSJohn Marino }
96250fc853eSJohn Marino
96350fc853eSJohn Marino /*
96450fc853eSJohn Marino * Implements 'human' numeric sort (-h).
96550fc853eSJohn Marino */
96650fc853eSJohn Marino static int
hnumcoll(struct key_value * kv1,struct key_value * kv2,size_t offset)96750fc853eSJohn Marino hnumcoll(struct key_value *kv1, struct key_value *kv2, size_t offset)
96850fc853eSJohn Marino {
96950fc853eSJohn Marino
97050fc853eSJohn Marino return (numcoll_impl(kv1, kv2, offset, true));
97150fc853eSJohn Marino }
97250fc853eSJohn Marino
97350fc853eSJohn Marino /*
97450fc853eSJohn Marino * Implements random sort (-R).
97550fc853eSJohn Marino */
9766d7e22ecSzrj #if defined(SORT_RANDOM)
977*a98f7024Szrj static char *
randomcollend(MD5_CTX * ctx)978*a98f7024Szrj randomcollend(MD5_CTX *ctx)
979*a98f7024Szrj {
980*a98f7024Szrj unsigned char digest[MD5_DIGEST_LENGTH];
981*a98f7024Szrj static const char hex[]="0123456789abcdef";
982*a98f7024Szrj char *buf;
983*a98f7024Szrj int i;
984*a98f7024Szrj
985*a98f7024Szrj buf = malloc(MD5_DIGEST_LENGTH * 2 + 1);
986*a98f7024Szrj if (!buf)
987*a98f7024Szrj return NULL;
988*a98f7024Szrj MD5_Final(digest, ctx);
989*a98f7024Szrj for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
990*a98f7024Szrj buf[2*i] = hex[digest[i] >> 4];
991*a98f7024Szrj buf[2*i+1] = hex[digest[i] & 0x0f];
992*a98f7024Szrj }
993*a98f7024Szrj buf[MD5_DIGEST_LENGTH * 2] = '\0';
994*a98f7024Szrj return buf;
995*a98f7024Szrj }
996*a98f7024Szrj
99750fc853eSJohn Marino static int
randomcoll(struct key_value * kv1,struct key_value * kv2,size_t offset __unused)99850fc853eSJohn Marino randomcoll(struct key_value *kv1, struct key_value *kv2,
99950fc853eSJohn Marino size_t offset __unused)
100050fc853eSJohn Marino {
100150fc853eSJohn Marino struct bwstring *s1, *s2;
100250fc853eSJohn Marino MD5_CTX ctx1, ctx2;
100350fc853eSJohn Marino char *b1, *b2;
100450fc853eSJohn Marino
100550fc853eSJohn Marino s1 = kv1->k;
100650fc853eSJohn Marino s2 = kv2->k;
100750fc853eSJohn Marino
100850fc853eSJohn Marino if (debug_sort) {
100950fc853eSJohn Marino bwsprintf(stdout, s1, "; k1=<", ">");
101050fc853eSJohn Marino bwsprintf(stdout, s2, ", k2=<", ">");
101150fc853eSJohn Marino }
101250fc853eSJohn Marino
101350fc853eSJohn Marino if (s1 == s2)
101450fc853eSJohn Marino return (0);
101550fc853eSJohn Marino
101650fc853eSJohn Marino memcpy(&ctx1,&md5_ctx,sizeof(MD5_CTX));
101750fc853eSJohn Marino memcpy(&ctx2,&md5_ctx,sizeof(MD5_CTX));
101850fc853eSJohn Marino
1019*a98f7024Szrj MD5_Update(&ctx1, bwsrawdata(s1), bwsrawlen(s1));
1020*a98f7024Szrj MD5_Update(&ctx2, bwsrawdata(s2), bwsrawlen(s2));
1021*a98f7024Szrj b1 = randomcollend(&ctx1);
1022*a98f7024Szrj b2 = randomcollend(&ctx2);
102350fc853eSJohn Marino if (b1 == NULL) {
102450fc853eSJohn Marino if (b2 == NULL)
102550fc853eSJohn Marino return (0);
102650fc853eSJohn Marino else {
102750fc853eSJohn Marino sort_free(b2);
102850fc853eSJohn Marino return (-1);
102950fc853eSJohn Marino }
103050fc853eSJohn Marino } else if (b2 == NULL) {
103150fc853eSJohn Marino sort_free(b1);
103250fc853eSJohn Marino return (+1);
103350fc853eSJohn Marino } else {
103450fc853eSJohn Marino int cmp_res;
103550fc853eSJohn Marino
103650fc853eSJohn Marino cmp_res = strcmp(b1,b2);
103750fc853eSJohn Marino sort_free(b1);
103850fc853eSJohn Marino sort_free(b2);
103950fc853eSJohn Marino
104050fc853eSJohn Marino if (!cmp_res)
104150fc853eSJohn Marino cmp_res = bwscoll(s1, s2, 0);
104250fc853eSJohn Marino
104350fc853eSJohn Marino return (cmp_res);
104450fc853eSJohn Marino }
104550fc853eSJohn Marino }
10466d7e22ecSzrj #endif
104750fc853eSJohn Marino
104850fc853eSJohn Marino /*
104950fc853eSJohn Marino * Implements version sort (-V).
105050fc853eSJohn Marino */
105150fc853eSJohn Marino static int
versioncoll(struct key_value * kv1,struct key_value * kv2,size_t offset __unused)105250fc853eSJohn Marino versioncoll(struct key_value *kv1, struct key_value *kv2,
105350fc853eSJohn Marino size_t offset __unused)
105450fc853eSJohn Marino {
105550fc853eSJohn Marino struct bwstring *s1, *s2;
105650fc853eSJohn Marino
105750fc853eSJohn Marino s1 = kv1->k;
105850fc853eSJohn Marino s2 = kv2->k;
105950fc853eSJohn Marino
106050fc853eSJohn Marino if (debug_sort) {
106150fc853eSJohn Marino bwsprintf(stdout, s1, "; k1=<", ">");
106250fc853eSJohn Marino bwsprintf(stdout, s2, ", k2=<", ">");
106350fc853eSJohn Marino }
106450fc853eSJohn Marino
106550fc853eSJohn Marino if (s1 == s2)
106650fc853eSJohn Marino return (0);
106750fc853eSJohn Marino
106850fc853eSJohn Marino return (vcmp(s1, s2));
106950fc853eSJohn Marino }
107050fc853eSJohn Marino
107150fc853eSJohn Marino /*
107250fc853eSJohn Marino * Check for minus infinity
107350fc853eSJohn Marino */
107450fc853eSJohn Marino static inline bool
huge_minus(double d,int err1)107550fc853eSJohn Marino huge_minus(double d, int err1)
107650fc853eSJohn Marino {
107750fc853eSJohn Marino
107850fc853eSJohn Marino if (err1 == ERANGE)
107950fc853eSJohn Marino if (d == -HUGE_VAL || d == -HUGE_VALF || d == -HUGE_VALL)
108050fc853eSJohn Marino return (+1);
108150fc853eSJohn Marino
108250fc853eSJohn Marino return (0);
108350fc853eSJohn Marino }
108450fc853eSJohn Marino
108550fc853eSJohn Marino /*
108650fc853eSJohn Marino * Check for plus infinity
108750fc853eSJohn Marino */
108850fc853eSJohn Marino static inline bool
huge_plus(double d,int err1)108950fc853eSJohn Marino huge_plus(double d, int err1)
109050fc853eSJohn Marino {
109150fc853eSJohn Marino
109250fc853eSJohn Marino if (err1 == ERANGE)
109350fc853eSJohn Marino if (d == HUGE_VAL || d == HUGE_VALF || d == HUGE_VALL)
109450fc853eSJohn Marino return (+1);
109550fc853eSJohn Marino
109650fc853eSJohn Marino return (0);
109750fc853eSJohn Marino }
109850fc853eSJohn Marino
109950fc853eSJohn Marino /*
110050fc853eSJohn Marino * Check whether a function is a NAN
110150fc853eSJohn Marino */
110250fc853eSJohn Marino static bool
is_nan(double d)110350fc853eSJohn Marino is_nan(double d)
110450fc853eSJohn Marino {
110550fc853eSJohn Marino return ((d == NAN) || (isnan(d)));
110650fc853eSJohn Marino }
110750fc853eSJohn Marino
110850fc853eSJohn Marino /*
110950fc853eSJohn Marino * Compare two NANs
111050fc853eSJohn Marino */
111150fc853eSJohn Marino static int
cmp_nans(double d1,double d2)111250fc853eSJohn Marino cmp_nans(double d1, double d2)
111350fc853eSJohn Marino {
111450fc853eSJohn Marino
111550fc853eSJohn Marino if (d1 < d2)
111650fc853eSJohn Marino return (-1);
111794400e62SJohn Marino if (d1 > d2)
111850fc853eSJohn Marino return (+1);
111950fc853eSJohn Marino return (0);
112050fc853eSJohn Marino }
112150fc853eSJohn Marino
112250fc853eSJohn Marino /*
112350fc853eSJohn Marino * Implements general numeric sort (-g).
112450fc853eSJohn Marino */
112550fc853eSJohn Marino static int
gnumcoll(struct key_value * kv1,struct key_value * kv2,size_t offset __unused)112650fc853eSJohn Marino gnumcoll(struct key_value *kv1, struct key_value *kv2,
112750fc853eSJohn Marino size_t offset __unused)
112850fc853eSJohn Marino {
112950fc853eSJohn Marino double d1, d2;
113050fc853eSJohn Marino int err1, err2;
113150fc853eSJohn Marino bool empty1, empty2, key1_read, key2_read;
113250fc853eSJohn Marino
113350fc853eSJohn Marino d1 = d2 = 0;
113450fc853eSJohn Marino err1 = err2 = 0;
113550fc853eSJohn Marino key1_read = key2_read = false;
113650fc853eSJohn Marino
113750fc853eSJohn Marino if (debug_sort) {
113850fc853eSJohn Marino bwsprintf(stdout, kv1->k, "; k1=<", ">");
113950fc853eSJohn Marino bwsprintf(stdout, kv2->k, "; k2=<", ">");
114050fc853eSJohn Marino }
114150fc853eSJohn Marino
114250fc853eSJohn Marino if (kv1->hint->status == HS_UNINITIALIZED) {
114350fc853eSJohn Marino errno = 0;
114450fc853eSJohn Marino d1 = bwstod(kv1->k, &empty1);
114550fc853eSJohn Marino err1 = errno;
114650fc853eSJohn Marino
114750fc853eSJohn Marino if (empty1)
114850fc853eSJohn Marino kv1->hint->v.gh.notnum = true;
114950fc853eSJohn Marino else if (err1 == 0) {
115050fc853eSJohn Marino kv1->hint->v.gh.d = d1;
115150fc853eSJohn Marino kv1->hint->v.gh.nan = is_nan(d1);
115250fc853eSJohn Marino kv1->hint->status = HS_INITIALIZED;
115350fc853eSJohn Marino } else
115450fc853eSJohn Marino kv1->hint->status = HS_ERROR;
115550fc853eSJohn Marino
115650fc853eSJohn Marino key1_read = true;
115750fc853eSJohn Marino }
115850fc853eSJohn Marino
115950fc853eSJohn Marino if (kv2->hint->status == HS_UNINITIALIZED) {
116050fc853eSJohn Marino errno = 0;
116150fc853eSJohn Marino d2 = bwstod(kv2->k, &empty2);
116250fc853eSJohn Marino err2 = errno;
116350fc853eSJohn Marino
116450fc853eSJohn Marino if (empty2)
116550fc853eSJohn Marino kv2->hint->v.gh.notnum = true;
116650fc853eSJohn Marino else if (err2 == 0) {
116750fc853eSJohn Marino kv2->hint->v.gh.d = d2;
116850fc853eSJohn Marino kv2->hint->v.gh.nan = is_nan(d2);
116950fc853eSJohn Marino kv2->hint->status = HS_INITIALIZED;
117050fc853eSJohn Marino } else
117150fc853eSJohn Marino kv2->hint->status = HS_ERROR;
117250fc853eSJohn Marino
117350fc853eSJohn Marino key2_read = true;
117450fc853eSJohn Marino }
117550fc853eSJohn Marino
117650fc853eSJohn Marino if (kv1->hint->status == HS_INITIALIZED &&
117750fc853eSJohn Marino kv2->hint->status == HS_INITIALIZED) {
117850fc853eSJohn Marino if (kv1->hint->v.gh.notnum)
117950fc853eSJohn Marino return ((kv2->hint->v.gh.notnum) ? 0 : -1);
118050fc853eSJohn Marino else if (kv2->hint->v.gh.notnum)
118150fc853eSJohn Marino return (+1);
118250fc853eSJohn Marino
118350fc853eSJohn Marino if (kv1->hint->v.gh.nan)
118450fc853eSJohn Marino return ((kv2->hint->v.gh.nan) ?
118550fc853eSJohn Marino cmp_nans(kv1->hint->v.gh.d, kv2->hint->v.gh.d) :
118650fc853eSJohn Marino -1);
118750fc853eSJohn Marino else if (kv2->hint->v.gh.nan)
118850fc853eSJohn Marino return (+1);
118950fc853eSJohn Marino
119050fc853eSJohn Marino d1 = kv1->hint->v.gh.d;
119150fc853eSJohn Marino d2 = kv2->hint->v.gh.d;
119250fc853eSJohn Marino
119350fc853eSJohn Marino if (d1 < d2)
119450fc853eSJohn Marino return (-1);
119550fc853eSJohn Marino else if (d1 > d2)
119650fc853eSJohn Marino return (+1);
119750fc853eSJohn Marino else
119850fc853eSJohn Marino return (0);
119950fc853eSJohn Marino }
120050fc853eSJohn Marino
120150fc853eSJohn Marino if (!key1_read) {
120250fc853eSJohn Marino errno = 0;
120350fc853eSJohn Marino d1 = bwstod(kv1->k, &empty1);
120450fc853eSJohn Marino err1 = errno;
120550fc853eSJohn Marino }
120650fc853eSJohn Marino
120750fc853eSJohn Marino if (!key2_read) {
120850fc853eSJohn Marino errno = 0;
120950fc853eSJohn Marino d2 = bwstod(kv2->k, &empty2);
121050fc853eSJohn Marino err2 = errno;
121150fc853eSJohn Marino }
121250fc853eSJohn Marino
121350fc853eSJohn Marino /* Non-value case: */
121450fc853eSJohn Marino if (empty1)
121550fc853eSJohn Marino return (empty2 ? 0 : -1);
121650fc853eSJohn Marino else if (empty2)
121750fc853eSJohn Marino return (+1);
121850fc853eSJohn Marino
121950fc853eSJohn Marino /* NAN case */
122050fc853eSJohn Marino if (is_nan(d1))
122150fc853eSJohn Marino return (is_nan(d2) ? cmp_nans(d1, d2) : -1);
122250fc853eSJohn Marino else if (is_nan(d2))
122350fc853eSJohn Marino return (+1);
122450fc853eSJohn Marino
122550fc853eSJohn Marino /* Infinities */
122650fc853eSJohn Marino if (err1 == ERANGE || err2 == ERANGE) {
122750fc853eSJohn Marino /* Minus infinity case */
122850fc853eSJohn Marino if (huge_minus(d1, err1)) {
122950fc853eSJohn Marino if (huge_minus(d2, err2)) {
123050fc853eSJohn Marino if (d1 < d2)
123150fc853eSJohn Marino return (-1);
123250fc853eSJohn Marino if (d1 > d2)
123350fc853eSJohn Marino return (+1);
123450fc853eSJohn Marino return (0);
123550fc853eSJohn Marino } else
123650fc853eSJohn Marino return (-1);
123750fc853eSJohn Marino
123850fc853eSJohn Marino } else if (huge_minus(d2, err2)) {
123950fc853eSJohn Marino if (huge_minus(d1, err1)) {
124050fc853eSJohn Marino if (d1 < d2)
124150fc853eSJohn Marino return (-1);
124250fc853eSJohn Marino if (d1 > d2)
124350fc853eSJohn Marino return (+1);
124450fc853eSJohn Marino return (0);
124550fc853eSJohn Marino } else
124650fc853eSJohn Marino return (+1);
124750fc853eSJohn Marino }
124850fc853eSJohn Marino
124950fc853eSJohn Marino /* Plus infinity case */
125050fc853eSJohn Marino if (huge_plus(d1, err1)) {
125150fc853eSJohn Marino if (huge_plus(d2, err2)) {
125250fc853eSJohn Marino if (d1 < d2)
125350fc853eSJohn Marino return (-1);
125450fc853eSJohn Marino if (d1 > d2)
125550fc853eSJohn Marino return (+1);
125650fc853eSJohn Marino return (0);
125750fc853eSJohn Marino } else
125850fc853eSJohn Marino return (+1);
125950fc853eSJohn Marino } else if (huge_plus(d2, err2)) {
126050fc853eSJohn Marino if (huge_plus(d1, err1)) {
126150fc853eSJohn Marino if (d1 < d2)
126250fc853eSJohn Marino return (-1);
126350fc853eSJohn Marino if (d1 > d2)
126450fc853eSJohn Marino return (+1);
126550fc853eSJohn Marino return (0);
126650fc853eSJohn Marino } else
126750fc853eSJohn Marino return (-1);
126850fc853eSJohn Marino }
126950fc853eSJohn Marino }
127050fc853eSJohn Marino
127150fc853eSJohn Marino if (d1 < d2)
127250fc853eSJohn Marino return (-1);
127350fc853eSJohn Marino if (d1 > d2)
127450fc853eSJohn Marino return (+1);
127550fc853eSJohn Marino
127650fc853eSJohn Marino return (0);
127750fc853eSJohn Marino }
127850fc853eSJohn Marino
127950fc853eSJohn Marino /*
128050fc853eSJohn Marino * Implements month sort (-M).
128150fc853eSJohn Marino */
128250fc853eSJohn Marino static int
monthcoll(struct key_value * kv1,struct key_value * kv2,size_t offset __unused)128350fc853eSJohn Marino monthcoll(struct key_value *kv1, struct key_value *kv2, size_t offset __unused)
128450fc853eSJohn Marino {
128550fc853eSJohn Marino int val1, val2;
128650fc853eSJohn Marino bool key1_read, key2_read;
128750fc853eSJohn Marino
128850fc853eSJohn Marino val1 = val2 = 0;
128950fc853eSJohn Marino key1_read = key2_read = false;
129050fc853eSJohn Marino
129150fc853eSJohn Marino if (debug_sort) {
129250fc853eSJohn Marino bwsprintf(stdout, kv1->k, "; k1=<", ">");
129350fc853eSJohn Marino bwsprintf(stdout, kv2->k, "; k2=<", ">");
129450fc853eSJohn Marino }
129550fc853eSJohn Marino
129650fc853eSJohn Marino if (kv1->hint->status == HS_UNINITIALIZED) {
129750fc853eSJohn Marino kv1->hint->v.Mh.m = bws_month_score(kv1->k);
129850fc853eSJohn Marino key1_read = true;
129950fc853eSJohn Marino kv1->hint->status = HS_INITIALIZED;
130050fc853eSJohn Marino }
130150fc853eSJohn Marino
130250fc853eSJohn Marino if (kv2->hint->status == HS_UNINITIALIZED) {
130350fc853eSJohn Marino kv2->hint->v.Mh.m = bws_month_score(kv2->k);
130450fc853eSJohn Marino key2_read = true;
130550fc853eSJohn Marino kv2->hint->status = HS_INITIALIZED;
130650fc853eSJohn Marino }
130750fc853eSJohn Marino
130850fc853eSJohn Marino if (kv1->hint->status == HS_INITIALIZED) {
130950fc853eSJohn Marino val1 = kv1->hint->v.Mh.m;
131050fc853eSJohn Marino key1_read = true;
131150fc853eSJohn Marino }
131250fc853eSJohn Marino
131350fc853eSJohn Marino if (kv2->hint->status == HS_INITIALIZED) {
131450fc853eSJohn Marino val2 = kv2->hint->v.Mh.m;
131550fc853eSJohn Marino key2_read = true;
131650fc853eSJohn Marino }
131750fc853eSJohn Marino
131850fc853eSJohn Marino if (!key1_read)
131950fc853eSJohn Marino val1 = bws_month_score(kv1->k);
132050fc853eSJohn Marino if (!key2_read)
132150fc853eSJohn Marino val2 = bws_month_score(kv2->k);
132250fc853eSJohn Marino
132350fc853eSJohn Marino if (val1 == val2) {
132450fc853eSJohn Marino return (0);
132550fc853eSJohn Marino }
132650fc853eSJohn Marino if (val1 < val2)
132750fc853eSJohn Marino return (-1);
132850fc853eSJohn Marino return (+1);
132950fc853eSJohn Marino }
1330