1c66bbc91SGabor Kovesdan /*- 21de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 31de7b4b8SPedro F. Giffuni * 4c66bbc91SGabor Kovesdan * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org> 5c859c6ddSGabor Kovesdan * Copyright (C) 2012 Oleg Moskalenko <mom040267@gmail.com> 6c66bbc91SGabor Kovesdan * All rights reserved. 7c66bbc91SGabor Kovesdan * 8c66bbc91SGabor Kovesdan * Redistribution and use in source and binary forms, with or without 9c66bbc91SGabor Kovesdan * modification, are permitted provided that the following conditions 10c66bbc91SGabor Kovesdan * are met: 11c66bbc91SGabor Kovesdan * 1. Redistributions of source code must retain the above copyright 12c66bbc91SGabor Kovesdan * notice, this list of conditions and the following disclaimer. 13c66bbc91SGabor Kovesdan * 2. Redistributions in binary form must reproduce the above copyright 14c66bbc91SGabor Kovesdan * notice, this list of conditions and the following disclaimer in the 15c66bbc91SGabor Kovesdan * documentation and/or other materials provided with the distribution. 16c66bbc91SGabor Kovesdan * 17c66bbc91SGabor Kovesdan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18c66bbc91SGabor Kovesdan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19c66bbc91SGabor Kovesdan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20c66bbc91SGabor Kovesdan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21c66bbc91SGabor Kovesdan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22c66bbc91SGabor Kovesdan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23c66bbc91SGabor Kovesdan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24c66bbc91SGabor Kovesdan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25c66bbc91SGabor Kovesdan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26c66bbc91SGabor Kovesdan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27c66bbc91SGabor Kovesdan * SUCH DAMAGE. 28c66bbc91SGabor Kovesdan */ 29c66bbc91SGabor Kovesdan 30c66bbc91SGabor Kovesdan #include <sys/cdefs.h> 31c66bbc91SGabor Kovesdan __FBSDID("$FreeBSD$"); 32c66bbc91SGabor Kovesdan 33c66bbc91SGabor Kovesdan #include <sys/types.h> 34c66bbc91SGabor Kovesdan 35c66bbc91SGabor Kovesdan #include <errno.h> 36c66bbc91SGabor Kovesdan #include <err.h> 37c66bbc91SGabor Kovesdan #include <langinfo.h> 38c66bbc91SGabor Kovesdan #include <limits.h> 39c66bbc91SGabor Kovesdan #include <math.h> 40c66bbc91SGabor Kovesdan #include <md5.h> 41c66bbc91SGabor Kovesdan #include <stdlib.h> 42c66bbc91SGabor Kovesdan #include <string.h> 43c66bbc91SGabor Kovesdan #include <wchar.h> 44c66bbc91SGabor Kovesdan #include <wctype.h> 45c66bbc91SGabor Kovesdan 46c66bbc91SGabor Kovesdan #include "coll.h" 47c66bbc91SGabor Kovesdan #include "vsort.h" 48c66bbc91SGabor Kovesdan 49ce1e997fSGabor Kovesdan struct key_specs *keys; 50c66bbc91SGabor Kovesdan size_t keys_num = 0; 51c66bbc91SGabor Kovesdan 52e8da8c74SGabor Kovesdan wint_t symbol_decimal_point = L'.'; 53c66bbc91SGabor Kovesdan /* there is no default thousands separator in collate rules: */ 54e8da8c74SGabor Kovesdan wint_t symbol_thousands_sep = 0; 55e8da8c74SGabor Kovesdan wint_t symbol_negative_sign = L'-'; 56e8da8c74SGabor Kovesdan wint_t symbol_positive_sign = L'+'; 57c66bbc91SGabor Kovesdan 58c66bbc91SGabor Kovesdan static int wstrcoll(struct key_value *kv1, struct key_value *kv2, size_t offset); 59c66bbc91SGabor Kovesdan static int gnumcoll(struct key_value*, struct key_value *, size_t offset); 60c66bbc91SGabor Kovesdan static int monthcoll(struct key_value*, struct key_value *, size_t offset); 61c66bbc91SGabor Kovesdan static int numcoll(struct key_value*, struct key_value *, size_t offset); 62c66bbc91SGabor Kovesdan static int hnumcoll(struct key_value*, struct key_value *, size_t offset); 63c66bbc91SGabor Kovesdan static int randomcoll(struct key_value*, struct key_value *, size_t offset); 64c66bbc91SGabor Kovesdan static int versioncoll(struct key_value*, struct key_value *, size_t offset); 65c66bbc91SGabor Kovesdan 66c66bbc91SGabor Kovesdan /* 67c66bbc91SGabor Kovesdan * Allocate keys array 68c66bbc91SGabor Kovesdan */ 69c66bbc91SGabor Kovesdan struct keys_array * 70c66bbc91SGabor Kovesdan keys_array_alloc(void) 71c66bbc91SGabor Kovesdan { 72c66bbc91SGabor Kovesdan struct keys_array *ka; 73c66bbc91SGabor Kovesdan size_t sz; 74c66bbc91SGabor Kovesdan 75c66bbc91SGabor Kovesdan sz = keys_array_size(); 76c66bbc91SGabor Kovesdan ka = sort_malloc(sz); 77c66bbc91SGabor Kovesdan memset(ka, 0, sz); 78c66bbc91SGabor Kovesdan 79c66bbc91SGabor Kovesdan return (ka); 80c66bbc91SGabor Kovesdan } 81c66bbc91SGabor Kovesdan 82c66bbc91SGabor Kovesdan /* 83c66bbc91SGabor Kovesdan * Calculate whether we need key hint space 84c66bbc91SGabor Kovesdan */ 85c66bbc91SGabor Kovesdan static size_t 86c66bbc91SGabor Kovesdan key_hint_size(void) 87c66bbc91SGabor Kovesdan { 88c66bbc91SGabor Kovesdan 89c66bbc91SGabor Kovesdan return (need_hint ? sizeof(struct key_hint) : 0); 90c66bbc91SGabor Kovesdan } 91c66bbc91SGabor Kovesdan 92c66bbc91SGabor Kovesdan /* 93c66bbc91SGabor Kovesdan * Calculate keys array size 94c66bbc91SGabor Kovesdan */ 95c66bbc91SGabor Kovesdan size_t 96c66bbc91SGabor Kovesdan keys_array_size(void) 97c66bbc91SGabor Kovesdan { 98e5f71a07SPedro F. Giffuni 99c66bbc91SGabor Kovesdan return (keys_num * (sizeof(struct key_value) + key_hint_size())); 100c66bbc91SGabor Kovesdan } 101c66bbc91SGabor Kovesdan 102c66bbc91SGabor Kovesdan /* 103c66bbc91SGabor Kovesdan * Clean data of keys array 104c66bbc91SGabor Kovesdan */ 105c66bbc91SGabor Kovesdan void 106c66bbc91SGabor Kovesdan clean_keys_array(const struct bwstring *s, struct keys_array *ka) 107c66bbc91SGabor Kovesdan { 108e5f71a07SPedro F. Giffuni 109c66bbc91SGabor Kovesdan if (ka) { 110ed7aec1eSMarius Strobl for (size_t i = 0; i < keys_num; ++i) { 111ed7aec1eSMarius Strobl const struct key_value *kv; 112ed7aec1eSMarius Strobl 113ed7aec1eSMarius Strobl kv = get_key_from_keys_array(ka, i); 114ed7aec1eSMarius Strobl if (kv->k && kv->k != s) 115ed7aec1eSMarius Strobl bwsfree(kv->k); 116ed7aec1eSMarius Strobl } 117c66bbc91SGabor Kovesdan memset(ka, 0, keys_array_size()); 118c66bbc91SGabor Kovesdan } 119c66bbc91SGabor Kovesdan } 120c66bbc91SGabor Kovesdan 121c66bbc91SGabor Kovesdan /* 122ed7aec1eSMarius Strobl * Get pointer to a key value in the keys set 123ed7aec1eSMarius Strobl */ 124ed7aec1eSMarius Strobl struct key_value * 125ed7aec1eSMarius Strobl get_key_from_keys_array(struct keys_array *ka, size_t ind) 126ed7aec1eSMarius Strobl { 127ed7aec1eSMarius Strobl 128ed7aec1eSMarius Strobl return ((struct key_value *)((caddr_t)ka->key + 129ed7aec1eSMarius Strobl ind * (sizeof(struct key_value) + key_hint_size()))); 130ed7aec1eSMarius Strobl } 131ed7aec1eSMarius Strobl 132ed7aec1eSMarius Strobl /* 133c66bbc91SGabor Kovesdan * Set value of a key in the keys set 134c66bbc91SGabor Kovesdan */ 135c66bbc91SGabor Kovesdan void 136c66bbc91SGabor Kovesdan set_key_on_keys_array(struct keys_array *ka, struct bwstring *s, size_t ind) 137c66bbc91SGabor Kovesdan { 138e5f71a07SPedro F. Giffuni 139c66bbc91SGabor Kovesdan if (ka && keys_num > ind) { 140c66bbc91SGabor Kovesdan struct key_value *kv; 141c66bbc91SGabor Kovesdan 142ed7aec1eSMarius Strobl kv = get_key_from_keys_array(ka, ind); 143c66bbc91SGabor Kovesdan 144c66bbc91SGabor Kovesdan if (kv->k && kv->k != s) 145c66bbc91SGabor Kovesdan bwsfree(kv->k); 146c66bbc91SGabor Kovesdan kv->k = s; 147c66bbc91SGabor Kovesdan } 148c66bbc91SGabor Kovesdan } 149c66bbc91SGabor Kovesdan 150c66bbc91SGabor Kovesdan /* 151c66bbc91SGabor Kovesdan * Initialize a sort list item 152c66bbc91SGabor Kovesdan */ 153c66bbc91SGabor Kovesdan struct sort_list_item * 154c66bbc91SGabor Kovesdan sort_list_item_alloc(void) 155c66bbc91SGabor Kovesdan { 156c66bbc91SGabor Kovesdan struct sort_list_item *si; 157c66bbc91SGabor Kovesdan size_t sz; 158c66bbc91SGabor Kovesdan 159c66bbc91SGabor Kovesdan sz = sizeof(struct sort_list_item) + keys_array_size(); 160c66bbc91SGabor Kovesdan si = sort_malloc(sz); 161c66bbc91SGabor Kovesdan memset(si, 0, sz); 162c66bbc91SGabor Kovesdan 163c66bbc91SGabor Kovesdan return (si); 164c66bbc91SGabor Kovesdan } 165c66bbc91SGabor Kovesdan 166c66bbc91SGabor Kovesdan size_t 167c66bbc91SGabor Kovesdan sort_list_item_size(struct sort_list_item *si) 168c66bbc91SGabor Kovesdan { 169c66bbc91SGabor Kovesdan size_t ret = 0; 170c66bbc91SGabor Kovesdan 171c66bbc91SGabor Kovesdan if (si) { 172c66bbc91SGabor Kovesdan ret = sizeof(struct sort_list_item) + keys_array_size(); 173c66bbc91SGabor Kovesdan if (si->str) 174c66bbc91SGabor Kovesdan ret += bws_memsize(si->str); 175c66bbc91SGabor Kovesdan for (size_t i = 0; i < keys_num; ++i) { 176ed7aec1eSMarius Strobl const struct key_value *kv; 177c66bbc91SGabor Kovesdan 178ed7aec1eSMarius Strobl kv = get_key_from_keys_array(&si->ka, i); 179c66bbc91SGabor Kovesdan 180c66bbc91SGabor Kovesdan if (kv->k != si->str) 181c66bbc91SGabor Kovesdan ret += bws_memsize(kv->k); 182c66bbc91SGabor Kovesdan } 183c66bbc91SGabor Kovesdan } 184c66bbc91SGabor Kovesdan return (ret); 185c66bbc91SGabor Kovesdan } 186c66bbc91SGabor Kovesdan 187c66bbc91SGabor Kovesdan /* 188c66bbc91SGabor Kovesdan * Calculate key for a sort list item 189c66bbc91SGabor Kovesdan */ 190c66bbc91SGabor Kovesdan static void 191c66bbc91SGabor Kovesdan sort_list_item_make_key(struct sort_list_item *si) 192c66bbc91SGabor Kovesdan { 193e5f71a07SPedro F. Giffuni 194c66bbc91SGabor Kovesdan preproc(si->str, &(si->ka)); 195c66bbc91SGabor Kovesdan } 196c66bbc91SGabor Kovesdan 197c66bbc91SGabor Kovesdan /* 198c66bbc91SGabor Kovesdan * Set value of a sort list item. 199c66bbc91SGabor Kovesdan * Return combined string and keys memory size. 200c66bbc91SGabor Kovesdan */ 201c66bbc91SGabor Kovesdan void 202c66bbc91SGabor Kovesdan sort_list_item_set(struct sort_list_item *si, struct bwstring *str) 203c66bbc91SGabor Kovesdan { 204e5f71a07SPedro F. Giffuni 205c66bbc91SGabor Kovesdan if (si) { 206c66bbc91SGabor Kovesdan clean_keys_array(si->str, &(si->ka)); 207c66bbc91SGabor Kovesdan if (si->str) { 208c66bbc91SGabor Kovesdan if (si->str == str) { 209c66bbc91SGabor Kovesdan /* we are trying to reset the same string */ 210c66bbc91SGabor Kovesdan return; 211c66bbc91SGabor Kovesdan } else { 212c66bbc91SGabor Kovesdan bwsfree(si->str); 213c66bbc91SGabor Kovesdan si->str = NULL; 214c66bbc91SGabor Kovesdan } 215c66bbc91SGabor Kovesdan } 216c66bbc91SGabor Kovesdan si->str = str; 217c66bbc91SGabor Kovesdan sort_list_item_make_key(si); 218c66bbc91SGabor Kovesdan } 219c66bbc91SGabor Kovesdan } 220c66bbc91SGabor Kovesdan 221c66bbc91SGabor Kovesdan /* 222c66bbc91SGabor Kovesdan * De-allocate a sort list item object memory 223c66bbc91SGabor Kovesdan */ 224c66bbc91SGabor Kovesdan void 225c66bbc91SGabor Kovesdan sort_list_item_clean(struct sort_list_item *si) 226c66bbc91SGabor Kovesdan { 227e5f71a07SPedro F. Giffuni 228c66bbc91SGabor Kovesdan if (si) { 229c66bbc91SGabor Kovesdan clean_keys_array(si->str, &(si->ka)); 230c66bbc91SGabor Kovesdan if (si->str) { 231c66bbc91SGabor Kovesdan bwsfree(si->str); 232c66bbc91SGabor Kovesdan si->str = NULL; 233c66bbc91SGabor Kovesdan } 234c66bbc91SGabor Kovesdan } 235c66bbc91SGabor Kovesdan } 236c66bbc91SGabor Kovesdan 237c66bbc91SGabor Kovesdan /* 238c66bbc91SGabor Kovesdan * Skip columns according to specs 239c66bbc91SGabor Kovesdan */ 240c66bbc91SGabor Kovesdan static size_t 241c66bbc91SGabor Kovesdan skip_cols_to_start(const struct bwstring *s, size_t cols, size_t start, 242c66bbc91SGabor Kovesdan bool skip_blanks, bool *empty_key) 243c66bbc91SGabor Kovesdan { 244c66bbc91SGabor Kovesdan if (cols < 1) 245c66bbc91SGabor Kovesdan return (BWSLEN(s) + 1); 246c66bbc91SGabor Kovesdan 247c66bbc91SGabor Kovesdan if (skip_blanks) 248c66bbc91SGabor Kovesdan while (start < BWSLEN(s) && iswblank(BWS_GET(s,start))) 249c66bbc91SGabor Kovesdan ++start; 250c66bbc91SGabor Kovesdan 251c66bbc91SGabor Kovesdan while (start < BWSLEN(s) && cols > 1) { 252c66bbc91SGabor Kovesdan --cols; 253c66bbc91SGabor Kovesdan ++start; 254c66bbc91SGabor Kovesdan } 255c66bbc91SGabor Kovesdan 256c66bbc91SGabor Kovesdan if (start >= BWSLEN(s)) 257c66bbc91SGabor Kovesdan *empty_key = true; 258c66bbc91SGabor Kovesdan 259c66bbc91SGabor Kovesdan return (start); 260c66bbc91SGabor Kovesdan } 261c66bbc91SGabor Kovesdan 262c66bbc91SGabor Kovesdan /* 263c66bbc91SGabor Kovesdan * Skip fields according to specs 264c66bbc91SGabor Kovesdan */ 265c66bbc91SGabor Kovesdan static size_t 266c66bbc91SGabor Kovesdan skip_fields_to_start(const struct bwstring *s, size_t fields, bool *empty_field) 267c66bbc91SGabor Kovesdan { 268e5f71a07SPedro F. Giffuni 269c66bbc91SGabor Kovesdan if (fields < 2) { 270c66bbc91SGabor Kovesdan if (BWSLEN(s) == 0) 271c66bbc91SGabor Kovesdan *empty_field = true; 272c66bbc91SGabor Kovesdan return (0); 273c66bbc91SGabor Kovesdan } else if (!(sort_opts_vals.tflag)) { 274c66bbc91SGabor Kovesdan size_t cpos = 0; 275c66bbc91SGabor Kovesdan bool pb = true; 276c66bbc91SGabor Kovesdan 277c66bbc91SGabor Kovesdan while (cpos < BWSLEN(s)) { 278c66bbc91SGabor Kovesdan bool isblank; 279c66bbc91SGabor Kovesdan 280c66bbc91SGabor Kovesdan isblank = iswblank(BWS_GET(s, cpos)); 281c66bbc91SGabor Kovesdan 282c66bbc91SGabor Kovesdan if (isblank && !pb) { 283c66bbc91SGabor Kovesdan --fields; 284c66bbc91SGabor Kovesdan if (fields <= 1) 285c66bbc91SGabor Kovesdan return (cpos); 286c66bbc91SGabor Kovesdan } 287c66bbc91SGabor Kovesdan pb = isblank; 288c66bbc91SGabor Kovesdan ++cpos; 289c66bbc91SGabor Kovesdan } 290c66bbc91SGabor Kovesdan if (fields > 1) 291c66bbc91SGabor Kovesdan *empty_field = true; 292c66bbc91SGabor Kovesdan return (cpos); 293c66bbc91SGabor Kovesdan } else { 294c66bbc91SGabor Kovesdan size_t cpos = 0; 295c66bbc91SGabor Kovesdan 296c66bbc91SGabor Kovesdan while (cpos < BWSLEN(s)) { 297e8da8c74SGabor Kovesdan if (BWS_GET(s,cpos) == (wchar_t)sort_opts_vals.field_sep) { 298c66bbc91SGabor Kovesdan --fields; 299c66bbc91SGabor Kovesdan if (fields <= 1) 300c66bbc91SGabor Kovesdan return (cpos + 1); 301c66bbc91SGabor Kovesdan } 302c66bbc91SGabor Kovesdan ++cpos; 303c66bbc91SGabor Kovesdan } 304c66bbc91SGabor Kovesdan if (fields > 1) 305c66bbc91SGabor Kovesdan *empty_field = true; 306c66bbc91SGabor Kovesdan return (cpos); 307c66bbc91SGabor Kovesdan } 308c66bbc91SGabor Kovesdan } 309c66bbc91SGabor Kovesdan 310c66bbc91SGabor Kovesdan /* 311c66bbc91SGabor Kovesdan * Find fields start 312c66bbc91SGabor Kovesdan */ 313c66bbc91SGabor Kovesdan static void 314c66bbc91SGabor Kovesdan find_field_start(const struct bwstring *s, struct key_specs *ks, 315c66bbc91SGabor Kovesdan size_t *field_start, size_t *key_start, bool *empty_field, bool *empty_key) 316c66bbc91SGabor Kovesdan { 317e5f71a07SPedro F. Giffuni 318c66bbc91SGabor Kovesdan *field_start = skip_fields_to_start(s, ks->f1, empty_field); 319c66bbc91SGabor Kovesdan if (!*empty_field) 320c66bbc91SGabor Kovesdan *key_start = skip_cols_to_start(s, ks->c1, *field_start, 321c66bbc91SGabor Kovesdan ks->pos1b, empty_key); 322c66bbc91SGabor Kovesdan else 323c66bbc91SGabor Kovesdan *empty_key = true; 324c66bbc91SGabor Kovesdan } 325c66bbc91SGabor Kovesdan 326c66bbc91SGabor Kovesdan /* 327c66bbc91SGabor Kovesdan * Find end key position 328c66bbc91SGabor Kovesdan */ 329c66bbc91SGabor Kovesdan static size_t 330c66bbc91SGabor Kovesdan find_field_end(const struct bwstring *s, struct key_specs *ks) 331c66bbc91SGabor Kovesdan { 332c66bbc91SGabor Kovesdan size_t f2, next_field_start, pos_end; 333c66bbc91SGabor Kovesdan bool empty_field, empty_key; 334c66bbc91SGabor Kovesdan 335c66bbc91SGabor Kovesdan empty_field = false; 336c66bbc91SGabor Kovesdan empty_key = false; 337c66bbc91SGabor Kovesdan f2 = ks->f2; 338c66bbc91SGabor Kovesdan 339c66bbc91SGabor Kovesdan if (f2 == 0) 340c66bbc91SGabor Kovesdan return (BWSLEN(s) + 1); 341c66bbc91SGabor Kovesdan else { 342c66bbc91SGabor Kovesdan if (ks->c2 == 0) { 343c66bbc91SGabor Kovesdan next_field_start = skip_fields_to_start(s, f2 + 1, 344c66bbc91SGabor Kovesdan &empty_field); 345c66bbc91SGabor Kovesdan if ((next_field_start > 0) && sort_opts_vals.tflag && 346e8da8c74SGabor Kovesdan ((wchar_t)sort_opts_vals.field_sep == BWS_GET(s, 347c66bbc91SGabor Kovesdan next_field_start - 1))) 348c66bbc91SGabor Kovesdan --next_field_start; 349c66bbc91SGabor Kovesdan } else 350c66bbc91SGabor Kovesdan next_field_start = skip_fields_to_start(s, f2, 351c66bbc91SGabor Kovesdan &empty_field); 352c66bbc91SGabor Kovesdan } 353c66bbc91SGabor Kovesdan 354c66bbc91SGabor Kovesdan if (empty_field || (next_field_start >= BWSLEN(s))) 355c66bbc91SGabor Kovesdan return (BWSLEN(s) + 1); 356c66bbc91SGabor Kovesdan 357c66bbc91SGabor Kovesdan if (ks->c2) { 358c66bbc91SGabor Kovesdan pos_end = skip_cols_to_start(s, ks->c2, next_field_start, 359c66bbc91SGabor Kovesdan ks->pos2b, &empty_key); 360c66bbc91SGabor Kovesdan if (pos_end < BWSLEN(s)) 361c66bbc91SGabor Kovesdan ++pos_end; 362c66bbc91SGabor Kovesdan } else 363c66bbc91SGabor Kovesdan pos_end = next_field_start; 364c66bbc91SGabor Kovesdan 365c66bbc91SGabor Kovesdan return (pos_end); 366c66bbc91SGabor Kovesdan } 367c66bbc91SGabor Kovesdan 368c66bbc91SGabor Kovesdan /* 369c66bbc91SGabor Kovesdan * Cut a field according to the key specs 370c66bbc91SGabor Kovesdan */ 371c66bbc91SGabor Kovesdan static struct bwstring * 372c66bbc91SGabor Kovesdan cut_field(const struct bwstring *s, struct key_specs *ks) 373c66bbc91SGabor Kovesdan { 374c66bbc91SGabor Kovesdan struct bwstring *ret = NULL; 375c66bbc91SGabor Kovesdan 376c66bbc91SGabor Kovesdan if (s && ks) { 377c66bbc91SGabor Kovesdan size_t field_start, key_end, key_start, sz; 378c66bbc91SGabor Kovesdan bool empty_field, empty_key; 379c66bbc91SGabor Kovesdan 380c66bbc91SGabor Kovesdan field_start = 0; 381c66bbc91SGabor Kovesdan key_start = 0; 382c66bbc91SGabor Kovesdan empty_field = false; 383c66bbc91SGabor Kovesdan empty_key = false; 384c66bbc91SGabor Kovesdan 385c66bbc91SGabor Kovesdan find_field_start(s, ks, &field_start, &key_start, 386c66bbc91SGabor Kovesdan &empty_field, &empty_key); 387c66bbc91SGabor Kovesdan 388c66bbc91SGabor Kovesdan if (empty_key) 389c66bbc91SGabor Kovesdan sz = 0; 390c66bbc91SGabor Kovesdan else { 391c66bbc91SGabor Kovesdan key_end = find_field_end(s, ks); 392c66bbc91SGabor Kovesdan sz = (key_end < key_start) ? 0 : (key_end - key_start); 393c66bbc91SGabor Kovesdan } 394c66bbc91SGabor Kovesdan 395c66bbc91SGabor Kovesdan ret = bwsalloc(sz); 396c66bbc91SGabor Kovesdan if (sz) 397c66bbc91SGabor Kovesdan bwsnocpy(ret, s, key_start, sz); 398c66bbc91SGabor Kovesdan } else 399c66bbc91SGabor Kovesdan ret = bwsalloc(0); 400c66bbc91SGabor Kovesdan 401c66bbc91SGabor Kovesdan return (ret); 402c66bbc91SGabor Kovesdan } 403c66bbc91SGabor Kovesdan 404c66bbc91SGabor Kovesdan /* 405c66bbc91SGabor Kovesdan * Preprocesses a line applying the necessary transformations 406c66bbc91SGabor Kovesdan * specified by command line options and returns the preprocessed 407c66bbc91SGabor Kovesdan * string, which can be used to compare. 408c66bbc91SGabor Kovesdan */ 409c66bbc91SGabor Kovesdan int 410c66bbc91SGabor Kovesdan preproc(struct bwstring *s, struct keys_array *ka) 411c66bbc91SGabor Kovesdan { 412e5f71a07SPedro F. Giffuni 413c66bbc91SGabor Kovesdan if (sort_opts_vals.kflag) 414c66bbc91SGabor Kovesdan for (size_t i = 0; i < keys_num; i++) { 415c66bbc91SGabor Kovesdan struct bwstring *key; 416c66bbc91SGabor Kovesdan struct key_specs *kspecs; 417c66bbc91SGabor Kovesdan struct sort_mods *sm; 418c66bbc91SGabor Kovesdan 419c66bbc91SGabor Kovesdan kspecs = &(keys[i]); 420c66bbc91SGabor Kovesdan key = cut_field(s, kspecs); 421c66bbc91SGabor Kovesdan 422c66bbc91SGabor Kovesdan sm = &(kspecs->sm); 423c66bbc91SGabor Kovesdan if (sm->dflag) 424c66bbc91SGabor Kovesdan key = dictionary_order(key); 425c66bbc91SGabor Kovesdan else if (sm->iflag) 426c66bbc91SGabor Kovesdan key = ignore_nonprinting(key); 427c66bbc91SGabor Kovesdan if (sm->fflag || sm->Mflag) 428c66bbc91SGabor Kovesdan key = ignore_case(key); 429c66bbc91SGabor Kovesdan 430c66bbc91SGabor Kovesdan set_key_on_keys_array(ka, key, i); 431c66bbc91SGabor Kovesdan } 432c66bbc91SGabor Kovesdan else { 433c66bbc91SGabor Kovesdan struct bwstring *ret = NULL; 434c66bbc91SGabor Kovesdan struct sort_mods *sm = default_sort_mods; 435c66bbc91SGabor Kovesdan 436c66bbc91SGabor Kovesdan if (sm->bflag) { 437c66bbc91SGabor Kovesdan if (ret == NULL) 438c66bbc91SGabor Kovesdan ret = bwsdup(s); 439c66bbc91SGabor Kovesdan ret = ignore_leading_blanks(ret); 440c66bbc91SGabor Kovesdan } 441c66bbc91SGabor Kovesdan if (sm->dflag) { 442c66bbc91SGabor Kovesdan if (ret == NULL) 443c66bbc91SGabor Kovesdan ret = bwsdup(s); 444c66bbc91SGabor Kovesdan ret = dictionary_order(ret); 445c66bbc91SGabor Kovesdan } else if (sm->iflag) { 446c66bbc91SGabor Kovesdan if (ret == NULL) 447c66bbc91SGabor Kovesdan ret = bwsdup(s); 448c66bbc91SGabor Kovesdan ret = ignore_nonprinting(ret); 449c66bbc91SGabor Kovesdan } 450c66bbc91SGabor Kovesdan if (sm->fflag || sm->Mflag) { 451c66bbc91SGabor Kovesdan if (ret == NULL) 452c66bbc91SGabor Kovesdan ret = bwsdup(s); 453c66bbc91SGabor Kovesdan ret = ignore_case(ret); 454c66bbc91SGabor Kovesdan } 455c66bbc91SGabor Kovesdan if (ret == NULL) 456c66bbc91SGabor Kovesdan set_key_on_keys_array(ka, s, 0); 457c66bbc91SGabor Kovesdan else 458c66bbc91SGabor Kovesdan set_key_on_keys_array(ka, ret, 0); 459c66bbc91SGabor Kovesdan } 460c66bbc91SGabor Kovesdan 461c66bbc91SGabor Kovesdan return 0; 462c66bbc91SGabor Kovesdan } 463c66bbc91SGabor Kovesdan 464c66bbc91SGabor Kovesdan cmpcoll_t 465c66bbc91SGabor Kovesdan get_sort_func(struct sort_mods *sm) 466c66bbc91SGabor Kovesdan { 467e5f71a07SPedro F. Giffuni 468c66bbc91SGabor Kovesdan if (sm->nflag) 469c66bbc91SGabor Kovesdan return (numcoll); 470c66bbc91SGabor Kovesdan else if (sm->hflag) 471c66bbc91SGabor Kovesdan return (hnumcoll); 472c66bbc91SGabor Kovesdan else if (sm->gflag) 473c66bbc91SGabor Kovesdan return (gnumcoll); 474c66bbc91SGabor Kovesdan else if (sm->Mflag) 475c66bbc91SGabor Kovesdan return (monthcoll); 476c66bbc91SGabor Kovesdan else if (sm->Rflag) 477c66bbc91SGabor Kovesdan return (randomcoll); 478c66bbc91SGabor Kovesdan else if (sm->Vflag) 479c66bbc91SGabor Kovesdan return (versioncoll); 480c66bbc91SGabor Kovesdan else 481c66bbc91SGabor Kovesdan return (wstrcoll); 482c66bbc91SGabor Kovesdan } 483c66bbc91SGabor Kovesdan 484c66bbc91SGabor Kovesdan /* 485c66bbc91SGabor Kovesdan * Compares the given strings. Returns a positive number if 486c66bbc91SGabor Kovesdan * the first precedes the second, a negative number if the second is 487c66bbc91SGabor Kovesdan * the preceding one, and zero if they are equal. This function calls 488c66bbc91SGabor Kovesdan * the underlying collate functions, which done the actual comparison. 489c66bbc91SGabor Kovesdan */ 490c66bbc91SGabor Kovesdan int 491c66bbc91SGabor Kovesdan key_coll(struct keys_array *ps1, struct keys_array *ps2, size_t offset) 492c66bbc91SGabor Kovesdan { 493ed7aec1eSMarius Strobl struct key_value *kv1, *kv2; 494c66bbc91SGabor Kovesdan struct sort_mods *sm; 495c66bbc91SGabor Kovesdan int res = 0; 496c66bbc91SGabor Kovesdan 497c66bbc91SGabor Kovesdan for (size_t i = 0; i < keys_num; ++i) { 498ed7aec1eSMarius Strobl kv1 = get_key_from_keys_array(ps1, i); 499ed7aec1eSMarius Strobl kv2 = get_key_from_keys_array(ps2, i); 500c66bbc91SGabor Kovesdan sm = &(keys[i].sm); 501c66bbc91SGabor Kovesdan 502c66bbc91SGabor Kovesdan if (sm->rflag) 503ed7aec1eSMarius Strobl res = sm->func(kv2, kv1, offset); 504c66bbc91SGabor Kovesdan else 505ed7aec1eSMarius Strobl res = sm->func(kv1, kv2, offset); 506c66bbc91SGabor Kovesdan 507c66bbc91SGabor Kovesdan if (res) 508c66bbc91SGabor Kovesdan break; 509c66bbc91SGabor Kovesdan 510c66bbc91SGabor Kovesdan /* offset applies to only the first key */ 511c66bbc91SGabor Kovesdan offset = 0; 512c66bbc91SGabor Kovesdan } 513c66bbc91SGabor Kovesdan return (res); 514c66bbc91SGabor Kovesdan } 515c66bbc91SGabor Kovesdan 516c66bbc91SGabor Kovesdan /* 517c66bbc91SGabor Kovesdan * Compare two strings. 518c66bbc91SGabor Kovesdan * Plain symbol-by-symbol comparison. 519c66bbc91SGabor Kovesdan */ 520c66bbc91SGabor Kovesdan int 521c66bbc91SGabor Kovesdan top_level_str_coll(const struct bwstring *s1, const struct bwstring *s2) 522c66bbc91SGabor Kovesdan { 523e5f71a07SPedro F. Giffuni 524c66bbc91SGabor Kovesdan if (default_sort_mods->rflag) { 525c66bbc91SGabor Kovesdan const struct bwstring *tmp; 526c66bbc91SGabor Kovesdan 527c66bbc91SGabor Kovesdan tmp = s1; 528c66bbc91SGabor Kovesdan s1 = s2; 529c66bbc91SGabor Kovesdan s2 = tmp; 530c66bbc91SGabor Kovesdan } 531c66bbc91SGabor Kovesdan 532c66bbc91SGabor Kovesdan return (bwscoll(s1, s2, 0)); 533c66bbc91SGabor Kovesdan } 534c66bbc91SGabor Kovesdan 535c66bbc91SGabor Kovesdan /* 536c66bbc91SGabor Kovesdan * Compare a string and a sort list item, according to the sort specs. 537c66bbc91SGabor Kovesdan */ 538c66bbc91SGabor Kovesdan int 539c66bbc91SGabor Kovesdan str_list_coll(struct bwstring *str1, struct sort_list_item **ss2) 540c66bbc91SGabor Kovesdan { 541c66bbc91SGabor Kovesdan struct keys_array *ka1; 542c66bbc91SGabor Kovesdan int ret = 0; 543c66bbc91SGabor Kovesdan 544c66bbc91SGabor Kovesdan ka1 = keys_array_alloc(); 545c66bbc91SGabor Kovesdan 546c66bbc91SGabor Kovesdan preproc(str1, ka1); 547c66bbc91SGabor Kovesdan 548c66bbc91SGabor Kovesdan sort_list_item_make_key(*ss2); 549c66bbc91SGabor Kovesdan 550c66bbc91SGabor Kovesdan if (debug_sort) { 551c66bbc91SGabor Kovesdan bwsprintf(stdout, str1, "; s1=<", ">"); 552c66bbc91SGabor Kovesdan bwsprintf(stdout, (*ss2)->str, ", s2=<", ">"); 553c66bbc91SGabor Kovesdan } 554c66bbc91SGabor Kovesdan 555c66bbc91SGabor Kovesdan ret = key_coll(ka1, &((*ss2)->ka), 0); 556c66bbc91SGabor Kovesdan 557c66bbc91SGabor Kovesdan if (debug_sort) 558c66bbc91SGabor Kovesdan printf("; cmp1=%d", ret); 559c66bbc91SGabor Kovesdan 560c66bbc91SGabor Kovesdan clean_keys_array(str1, ka1); 561c66bbc91SGabor Kovesdan sort_free(ka1); 562c66bbc91SGabor Kovesdan 563c66bbc91SGabor Kovesdan if ((ret == 0) && !(sort_opts_vals.sflag) && sort_opts_vals.complex_sort) { 564c66bbc91SGabor Kovesdan ret = top_level_str_coll(str1, ((*ss2)->str)); 565c66bbc91SGabor Kovesdan if (debug_sort) 566c66bbc91SGabor Kovesdan printf("; cmp2=%d", ret); 567c66bbc91SGabor Kovesdan } 568c66bbc91SGabor Kovesdan 569c66bbc91SGabor Kovesdan if (debug_sort) 570c66bbc91SGabor Kovesdan printf("\n"); 571c66bbc91SGabor Kovesdan 572c66bbc91SGabor Kovesdan return (ret); 573c66bbc91SGabor Kovesdan } 574c66bbc91SGabor Kovesdan 575c66bbc91SGabor Kovesdan /* 576c66bbc91SGabor Kovesdan * Compare two sort list items, according to the sort specs. 577c66bbc91SGabor Kovesdan */ 578c66bbc91SGabor Kovesdan int 579c66bbc91SGabor Kovesdan list_coll_offset(struct sort_list_item **ss1, struct sort_list_item **ss2, 580c66bbc91SGabor Kovesdan size_t offset) 581c66bbc91SGabor Kovesdan { 582c66bbc91SGabor Kovesdan int ret; 583c66bbc91SGabor Kovesdan 584c66bbc91SGabor Kovesdan ret = key_coll(&((*ss1)->ka), &((*ss2)->ka), offset); 585c66bbc91SGabor Kovesdan 586c66bbc91SGabor Kovesdan if (debug_sort) { 587c66bbc91SGabor Kovesdan if (offset) 588c66bbc91SGabor Kovesdan printf("; offset=%d", (int) offset); 589c66bbc91SGabor Kovesdan bwsprintf(stdout, ((*ss1)->str), "; s1=<", ">"); 590c66bbc91SGabor Kovesdan bwsprintf(stdout, ((*ss2)->str), ", s2=<", ">"); 591c66bbc91SGabor Kovesdan printf("; cmp1=%d\n", ret); 592c66bbc91SGabor Kovesdan } 593c66bbc91SGabor Kovesdan 594c66bbc91SGabor Kovesdan if (ret) 595c66bbc91SGabor Kovesdan return (ret); 596c66bbc91SGabor Kovesdan 597c66bbc91SGabor Kovesdan if (!(sort_opts_vals.sflag) && sort_opts_vals.complex_sort) { 598c66bbc91SGabor Kovesdan ret = top_level_str_coll(((*ss1)->str), ((*ss2)->str)); 599c66bbc91SGabor Kovesdan if (debug_sort) 600c66bbc91SGabor Kovesdan printf("; cmp2=%d\n", ret); 601c66bbc91SGabor Kovesdan } 602c66bbc91SGabor Kovesdan 603c66bbc91SGabor Kovesdan return (ret); 604c66bbc91SGabor Kovesdan } 605c66bbc91SGabor Kovesdan 606c66bbc91SGabor Kovesdan /* 607c66bbc91SGabor Kovesdan * Compare two sort list items, according to the sort specs. 608c66bbc91SGabor Kovesdan */ 609c66bbc91SGabor Kovesdan int 610c66bbc91SGabor Kovesdan list_coll(struct sort_list_item **ss1, struct sort_list_item **ss2) 611c66bbc91SGabor Kovesdan { 612e5f71a07SPedro F. Giffuni 613c66bbc91SGabor Kovesdan return (list_coll_offset(ss1, ss2, 0)); 614c66bbc91SGabor Kovesdan } 615c66bbc91SGabor Kovesdan 616c66bbc91SGabor Kovesdan #define LSCDEF(N) \ 617c66bbc91SGabor Kovesdan static int \ 618c66bbc91SGabor Kovesdan list_coll_##N(struct sort_list_item **ss1, struct sort_list_item **ss2) \ 619c66bbc91SGabor Kovesdan { \ 620c66bbc91SGabor Kovesdan \ 621c66bbc91SGabor Kovesdan return (list_coll_offset(ss1, ss2, N)); \ 622c66bbc91SGabor Kovesdan } 623c66bbc91SGabor Kovesdan 624c66bbc91SGabor Kovesdan LSCDEF(1) 625c66bbc91SGabor Kovesdan LSCDEF(2) 626c66bbc91SGabor Kovesdan LSCDEF(3) 627c66bbc91SGabor Kovesdan LSCDEF(4) 628c66bbc91SGabor Kovesdan LSCDEF(5) 629c66bbc91SGabor Kovesdan LSCDEF(6) 630c66bbc91SGabor Kovesdan LSCDEF(7) 631c66bbc91SGabor Kovesdan LSCDEF(8) 632c66bbc91SGabor Kovesdan LSCDEF(9) 633c66bbc91SGabor Kovesdan LSCDEF(10) 634c66bbc91SGabor Kovesdan LSCDEF(11) 635c66bbc91SGabor Kovesdan LSCDEF(12) 636c66bbc91SGabor Kovesdan LSCDEF(13) 637c66bbc91SGabor Kovesdan LSCDEF(14) 638c66bbc91SGabor Kovesdan LSCDEF(15) 639c66bbc91SGabor Kovesdan LSCDEF(16) 640c66bbc91SGabor Kovesdan LSCDEF(17) 641c66bbc91SGabor Kovesdan LSCDEF(18) 642c66bbc91SGabor Kovesdan LSCDEF(19) 643c66bbc91SGabor Kovesdan LSCDEF(20) 644c66bbc91SGabor Kovesdan 645c66bbc91SGabor Kovesdan listcoll_t 646c66bbc91SGabor Kovesdan get_list_call_func(size_t offset) 647c66bbc91SGabor Kovesdan { 648c66bbc91SGabor Kovesdan static const listcoll_t lsarray[] = { list_coll, list_coll_1, 649c66bbc91SGabor Kovesdan list_coll_2, list_coll_3, list_coll_4, list_coll_5, 650c66bbc91SGabor Kovesdan list_coll_6, list_coll_7, list_coll_8, list_coll_9, 651c66bbc91SGabor Kovesdan list_coll_10, list_coll_11, list_coll_12, list_coll_13, 652c66bbc91SGabor Kovesdan list_coll_14, list_coll_15, list_coll_16, list_coll_17, 653c66bbc91SGabor Kovesdan list_coll_18, list_coll_19, list_coll_20 }; 654c66bbc91SGabor Kovesdan 655c66bbc91SGabor Kovesdan if (offset <= 20) 656c66bbc91SGabor Kovesdan return (lsarray[offset]); 657c66bbc91SGabor Kovesdan 658c66bbc91SGabor Kovesdan return (list_coll); 659c66bbc91SGabor Kovesdan } 660c66bbc91SGabor Kovesdan 661c66bbc91SGabor Kovesdan /* 662c66bbc91SGabor Kovesdan * Compare two sort list items, only by their original string. 663c66bbc91SGabor Kovesdan */ 664c66bbc91SGabor Kovesdan int 665c66bbc91SGabor Kovesdan list_coll_by_str_only(struct sort_list_item **ss1, struct sort_list_item **ss2) 666c66bbc91SGabor Kovesdan { 667e5f71a07SPedro F. Giffuni 668c66bbc91SGabor Kovesdan return (top_level_str_coll(((*ss1)->str), ((*ss2)->str))); 669c66bbc91SGabor Kovesdan } 670c66bbc91SGabor Kovesdan 671c66bbc91SGabor Kovesdan /* 672c66bbc91SGabor Kovesdan * Maximum size of a number in the string (before or after decimal point) 673c66bbc91SGabor Kovesdan */ 674c66bbc91SGabor Kovesdan #define MAX_NUM_SIZE (128) 675c66bbc91SGabor Kovesdan 676c66bbc91SGabor Kovesdan /* 677c66bbc91SGabor Kovesdan * Set suffix value 678c66bbc91SGabor Kovesdan */ 679c66bbc91SGabor Kovesdan static void setsuffix(wchar_t c, unsigned char *si) 680c66bbc91SGabor Kovesdan { 681c66bbc91SGabor Kovesdan switch (c){ 682c66bbc91SGabor Kovesdan case L'k': 683c66bbc91SGabor Kovesdan case L'K': 684c66bbc91SGabor Kovesdan *si = 1; 685c66bbc91SGabor Kovesdan break; 686c66bbc91SGabor Kovesdan case L'M': 687c66bbc91SGabor Kovesdan *si = 2; 688c66bbc91SGabor Kovesdan break; 689c66bbc91SGabor Kovesdan case L'G': 690c66bbc91SGabor Kovesdan *si = 3; 691c66bbc91SGabor Kovesdan break; 692c66bbc91SGabor Kovesdan case L'T': 693c66bbc91SGabor Kovesdan *si = 4; 694c66bbc91SGabor Kovesdan break; 695c66bbc91SGabor Kovesdan case L'P': 696c66bbc91SGabor Kovesdan *si = 5; 697c66bbc91SGabor Kovesdan break; 698c66bbc91SGabor Kovesdan case L'E': 699c66bbc91SGabor Kovesdan *si = 6; 700c66bbc91SGabor Kovesdan break; 701c66bbc91SGabor Kovesdan case L'Z': 702c66bbc91SGabor Kovesdan *si = 7; 703c66bbc91SGabor Kovesdan break; 704c66bbc91SGabor Kovesdan case L'Y': 705c66bbc91SGabor Kovesdan *si = 8; 706c66bbc91SGabor Kovesdan break; 707c66bbc91SGabor Kovesdan default: 708c66bbc91SGabor Kovesdan *si = 0; 70980c7cc1cSPedro F. Giffuni } 710c66bbc91SGabor Kovesdan } 711c66bbc91SGabor Kovesdan 712c66bbc91SGabor Kovesdan /* 713c66bbc91SGabor Kovesdan * Read string s and parse the string into a fixed-decimal-point number. 714c66bbc91SGabor Kovesdan * sign equals -1 if the number is negative (explicit plus is not allowed, 715c66bbc91SGabor Kovesdan * according to GNU sort's "info sort". 716c66bbc91SGabor Kovesdan * The number part before decimal point is in the smain, after the decimal 717c66bbc91SGabor Kovesdan * point is in sfrac, tail is the pointer to the remainder of the string. 718c66bbc91SGabor Kovesdan */ 719c66bbc91SGabor Kovesdan static int 720e8da8c74SGabor Kovesdan read_number(struct bwstring *s0, int *sign, wchar_t *smain, size_t *main_len, wchar_t *sfrac, size_t *frac_len, unsigned char *si) 721c66bbc91SGabor Kovesdan { 722c66bbc91SGabor Kovesdan bwstring_iterator s; 723c66bbc91SGabor Kovesdan 724c66bbc91SGabor Kovesdan s = bws_begin(s0); 725c66bbc91SGabor Kovesdan 726c66bbc91SGabor Kovesdan /* always end the fraction with zero, even if we have no fraction */ 727c66bbc91SGabor Kovesdan sfrac[0] = 0; 728c66bbc91SGabor Kovesdan 729c66bbc91SGabor Kovesdan while (iswblank(bws_get_iter_value(s))) 730c66bbc91SGabor Kovesdan s = bws_iterator_inc(s, 1); 731c66bbc91SGabor Kovesdan 732e8da8c74SGabor Kovesdan if (bws_get_iter_value(s) == (wchar_t)symbol_negative_sign) { 733c66bbc91SGabor Kovesdan *sign = -1; 734c66bbc91SGabor Kovesdan s = bws_iterator_inc(s, 1); 735c66bbc91SGabor Kovesdan } 736c66bbc91SGabor Kovesdan 737c66bbc91SGabor Kovesdan // This is '0', not '\0', do not change this 738c66bbc91SGabor Kovesdan while (iswdigit(bws_get_iter_value(s)) && 739c66bbc91SGabor Kovesdan (bws_get_iter_value(s) == L'0')) 740c66bbc91SGabor Kovesdan s = bws_iterator_inc(s, 1); 741c66bbc91SGabor Kovesdan 742c66bbc91SGabor Kovesdan while (bws_get_iter_value(s) && *main_len < MAX_NUM_SIZE) { 743c66bbc91SGabor Kovesdan if (iswdigit(bws_get_iter_value(s))) { 744c66bbc91SGabor Kovesdan smain[*main_len] = bws_get_iter_value(s); 745c66bbc91SGabor Kovesdan s = bws_iterator_inc(s, 1); 746c66bbc91SGabor Kovesdan *main_len += 1; 747c66bbc91SGabor Kovesdan } else if (symbol_thousands_sep && 748e8da8c74SGabor Kovesdan (bws_get_iter_value(s) == (wchar_t)symbol_thousands_sep)) 749c66bbc91SGabor Kovesdan s = bws_iterator_inc(s, 1); 750c66bbc91SGabor Kovesdan else 751c66bbc91SGabor Kovesdan break; 752c66bbc91SGabor Kovesdan } 753c66bbc91SGabor Kovesdan 754c66bbc91SGabor Kovesdan smain[*main_len] = 0; 755c66bbc91SGabor Kovesdan 756e8da8c74SGabor Kovesdan if (bws_get_iter_value(s) == (wchar_t)symbol_decimal_point) { 757c66bbc91SGabor Kovesdan s = bws_iterator_inc(s, 1); 758c66bbc91SGabor Kovesdan while (iswdigit(bws_get_iter_value(s)) && 759c66bbc91SGabor Kovesdan *frac_len < MAX_NUM_SIZE) { 760c66bbc91SGabor Kovesdan sfrac[*frac_len] = bws_get_iter_value(s); 761c66bbc91SGabor Kovesdan s = bws_iterator_inc(s, 1); 762c66bbc91SGabor Kovesdan *frac_len += 1; 763c66bbc91SGabor Kovesdan } 764c66bbc91SGabor Kovesdan sfrac[*frac_len] = 0; 765c66bbc91SGabor Kovesdan 766c66bbc91SGabor Kovesdan while (*frac_len > 0 && sfrac[*frac_len - 1] == L'0') { 767c66bbc91SGabor Kovesdan --(*frac_len); 768c66bbc91SGabor Kovesdan sfrac[*frac_len] = L'\0'; 769c66bbc91SGabor Kovesdan } 770c66bbc91SGabor Kovesdan } 771c66bbc91SGabor Kovesdan 772c66bbc91SGabor Kovesdan setsuffix(bws_get_iter_value(s),si); 773c66bbc91SGabor Kovesdan 774c66bbc91SGabor Kovesdan if ((*main_len + *frac_len) == 0) 775c66bbc91SGabor Kovesdan *sign = 0; 776c66bbc91SGabor Kovesdan 777c66bbc91SGabor Kovesdan return (0); 778c66bbc91SGabor Kovesdan } 779c66bbc91SGabor Kovesdan 780c66bbc91SGabor Kovesdan /* 781c66bbc91SGabor Kovesdan * Implements string sort. 782c66bbc91SGabor Kovesdan */ 783c66bbc91SGabor Kovesdan static int 784c66bbc91SGabor Kovesdan wstrcoll(struct key_value *kv1, struct key_value *kv2, size_t offset) 785c66bbc91SGabor Kovesdan { 786c66bbc91SGabor Kovesdan 787c66bbc91SGabor Kovesdan if (debug_sort) { 788c66bbc91SGabor Kovesdan if (offset) 789c66bbc91SGabor Kovesdan printf("; offset=%d\n", (int) offset); 790c66bbc91SGabor Kovesdan bwsprintf(stdout, kv1->k, "; k1=<", ">"); 791c66bbc91SGabor Kovesdan printf("(%zu)", BWSLEN(kv1->k)); 792c66bbc91SGabor Kovesdan bwsprintf(stdout, kv2->k, ", k2=<", ">"); 793c66bbc91SGabor Kovesdan printf("(%zu)", BWSLEN(kv2->k)); 794c66bbc91SGabor Kovesdan } 795c66bbc91SGabor Kovesdan 796c66bbc91SGabor Kovesdan return (bwscoll(kv1->k, kv2->k, offset)); 797c66bbc91SGabor Kovesdan } 798c66bbc91SGabor Kovesdan 799c66bbc91SGabor Kovesdan /* 800c66bbc91SGabor Kovesdan * Compare two suffixes 801c66bbc91SGabor Kovesdan */ 802c66bbc91SGabor Kovesdan static inline int 803c66bbc91SGabor Kovesdan cmpsuffix(unsigned char si1, unsigned char si2) 804c66bbc91SGabor Kovesdan { 805e5f71a07SPedro F. Giffuni 806c66bbc91SGabor Kovesdan return ((char)si1 - (char)si2); 807c66bbc91SGabor Kovesdan } 808c66bbc91SGabor Kovesdan 809c66bbc91SGabor Kovesdan /* 810c66bbc91SGabor Kovesdan * Implements numeric sort for -n and -h. 811c66bbc91SGabor Kovesdan */ 812c66bbc91SGabor Kovesdan static int 81389b7a587SGabor Kovesdan numcoll_impl(struct key_value *kv1, struct key_value *kv2, 81489b7a587SGabor Kovesdan size_t offset __unused, bool use_suffix) 815c66bbc91SGabor Kovesdan { 816c66bbc91SGabor Kovesdan struct bwstring *s1, *s2; 817c66bbc91SGabor Kovesdan wchar_t sfrac1[MAX_NUM_SIZE + 1], sfrac2[MAX_NUM_SIZE + 1]; 818c66bbc91SGabor Kovesdan wchar_t smain1[MAX_NUM_SIZE + 1], smain2[MAX_NUM_SIZE + 1]; 819e8da8c74SGabor Kovesdan int cmp_res, sign1, sign2; 820e8da8c74SGabor Kovesdan size_t frac1, frac2, main1, main2; 821c66bbc91SGabor Kovesdan unsigned char SI1, SI2; 822c66bbc91SGabor Kovesdan bool e1, e2, key1_read, key2_read; 823c66bbc91SGabor Kovesdan 824c66bbc91SGabor Kovesdan s1 = kv1->k; 825c66bbc91SGabor Kovesdan s2 = kv2->k; 826c66bbc91SGabor Kovesdan sign1 = sign2 = 0; 827c66bbc91SGabor Kovesdan main1 = main2 = 0; 828c66bbc91SGabor Kovesdan frac1 = frac2 = 0; 829c66bbc91SGabor Kovesdan 830c66bbc91SGabor Kovesdan key1_read = key2_read = false; 831c66bbc91SGabor Kovesdan 832c66bbc91SGabor Kovesdan if (debug_sort) { 833c66bbc91SGabor Kovesdan bwsprintf(stdout, s1, "; k1=<", ">"); 834c66bbc91SGabor Kovesdan bwsprintf(stdout, s2, ", k2=<", ">"); 835c66bbc91SGabor Kovesdan } 836c66bbc91SGabor Kovesdan 837c66bbc91SGabor Kovesdan if (s1 == s2) 838c66bbc91SGabor Kovesdan return (0); 839c66bbc91SGabor Kovesdan 840c66bbc91SGabor Kovesdan if (kv1->hint->status == HS_UNINITIALIZED) { 841c66bbc91SGabor Kovesdan /* read the number from the string */ 842c66bbc91SGabor Kovesdan read_number(s1, &sign1, smain1, &main1, sfrac1, &frac1, &SI1); 843c66bbc91SGabor Kovesdan key1_read = true; 844c66bbc91SGabor Kovesdan kv1->hint->v.nh.n1 = wcstoull(smain1, NULL, 10); 845c66bbc91SGabor Kovesdan if(main1 < 1 && frac1 < 1) 846c66bbc91SGabor Kovesdan kv1->hint->v.nh.empty=true; 847c66bbc91SGabor Kovesdan kv1->hint->v.nh.si = SI1; 848c66bbc91SGabor Kovesdan kv1->hint->status = (kv1->hint->v.nh.n1 != ULLONG_MAX) ? 849c66bbc91SGabor Kovesdan HS_INITIALIZED : HS_ERROR; 850c66bbc91SGabor Kovesdan kv1->hint->v.nh.neg = (sign1 < 0) ? true : false; 851c66bbc91SGabor Kovesdan } 852c66bbc91SGabor Kovesdan 853c66bbc91SGabor Kovesdan if (kv2->hint->status == HS_UNINITIALIZED) { 854c66bbc91SGabor Kovesdan /* read the number from the string */ 855c66bbc91SGabor Kovesdan read_number(s2, &sign2, smain2, &main2, sfrac2, &frac2,&SI2); 856c66bbc91SGabor Kovesdan key2_read = true; 857c66bbc91SGabor Kovesdan kv2->hint->v.nh.n1 = wcstoull(smain2, NULL, 10); 858c66bbc91SGabor Kovesdan if(main2 < 1 && frac2 < 1) 859c66bbc91SGabor Kovesdan kv2->hint->v.nh.empty=true; 860c66bbc91SGabor Kovesdan kv2->hint->v.nh.si = SI2; 861c66bbc91SGabor Kovesdan kv2->hint->status = (kv2->hint->v.nh.n1 != ULLONG_MAX) ? 862c66bbc91SGabor Kovesdan HS_INITIALIZED : HS_ERROR; 863c66bbc91SGabor Kovesdan kv2->hint->v.nh.neg = (sign2 < 0) ? true : false; 864c66bbc91SGabor Kovesdan } 865c66bbc91SGabor Kovesdan 866c66bbc91SGabor Kovesdan if (kv1->hint->status == HS_INITIALIZED && kv2->hint->status == 867c66bbc91SGabor Kovesdan HS_INITIALIZED) { 868c66bbc91SGabor Kovesdan unsigned long long n1, n2; 869c66bbc91SGabor Kovesdan bool neg1, neg2; 870c66bbc91SGabor Kovesdan 871c66bbc91SGabor Kovesdan e1 = kv1->hint->v.nh.empty; 872c66bbc91SGabor Kovesdan e2 = kv2->hint->v.nh.empty; 873c66bbc91SGabor Kovesdan 874c66bbc91SGabor Kovesdan if (e1 && e2) 875c66bbc91SGabor Kovesdan return (0); 876c66bbc91SGabor Kovesdan 877c66bbc91SGabor Kovesdan neg1 = kv1->hint->v.nh.neg; 878c66bbc91SGabor Kovesdan neg2 = kv2->hint->v.nh.neg; 879c66bbc91SGabor Kovesdan 880c66bbc91SGabor Kovesdan if (neg1 && !neg2) 881c66bbc91SGabor Kovesdan return (-1); 882c66bbc91SGabor Kovesdan if (neg2 && !neg1) 883c66bbc91SGabor Kovesdan return (+1); 884c66bbc91SGabor Kovesdan 885c66bbc91SGabor Kovesdan if (e1) 886c66bbc91SGabor Kovesdan return (neg2 ? +1 : -1); 887c66bbc91SGabor Kovesdan else if (e2) 888c66bbc91SGabor Kovesdan return (neg1 ? -1 : +1); 889c66bbc91SGabor Kovesdan 890c66bbc91SGabor Kovesdan 891c66bbc91SGabor Kovesdan if (use_suffix) { 892c66bbc91SGabor Kovesdan cmp_res = cmpsuffix(kv1->hint->v.nh.si, kv2->hint->v.nh.si); 893c66bbc91SGabor Kovesdan if (cmp_res) 894c66bbc91SGabor Kovesdan return (neg1 ? -cmp_res : cmp_res); 895c66bbc91SGabor Kovesdan } 896c66bbc91SGabor Kovesdan 897c66bbc91SGabor Kovesdan n1 = kv1->hint->v.nh.n1; 898c66bbc91SGabor Kovesdan n2 = kv2->hint->v.nh.n1; 899c66bbc91SGabor Kovesdan if (n1 < n2) 900c66bbc91SGabor Kovesdan return (neg1 ? +1 : -1); 901c66bbc91SGabor Kovesdan else if (n1 > n2) 902c66bbc91SGabor Kovesdan return (neg1 ? -1 : +1); 903c66bbc91SGabor Kovesdan } 904c66bbc91SGabor Kovesdan 905c66bbc91SGabor Kovesdan /* read the numbers from the strings */ 906c66bbc91SGabor Kovesdan if (!key1_read) 907c66bbc91SGabor Kovesdan read_number(s1, &sign1, smain1, &main1, sfrac1, &frac1, &SI1); 908c66bbc91SGabor Kovesdan if (!key2_read) 909c66bbc91SGabor Kovesdan read_number(s2, &sign2, smain2, &main2, sfrac2, &frac2, &SI2); 910c66bbc91SGabor Kovesdan 911c66bbc91SGabor Kovesdan e1 = ((main1 + frac1) == 0); 912c66bbc91SGabor Kovesdan e2 = ((main2 + frac2) == 0); 913c66bbc91SGabor Kovesdan 914c66bbc91SGabor Kovesdan if (e1 && e2) 915c66bbc91SGabor Kovesdan return (0); 916c66bbc91SGabor Kovesdan 917c66bbc91SGabor Kovesdan /* we know the result if the signs are different */ 918c66bbc91SGabor Kovesdan if (sign1 < 0 && sign2 >= 0) 919c66bbc91SGabor Kovesdan return (-1); 920c66bbc91SGabor Kovesdan if (sign1 >= 0 && sign2 < 0) 921c66bbc91SGabor Kovesdan return (+1); 922c66bbc91SGabor Kovesdan 923c66bbc91SGabor Kovesdan if (e1) 924c66bbc91SGabor Kovesdan return ((sign2 < 0) ? +1 : -1); 925c66bbc91SGabor Kovesdan else if (e2) 926c66bbc91SGabor Kovesdan return ((sign1 < 0) ? -1 : +1); 927c66bbc91SGabor Kovesdan 928c66bbc91SGabor Kovesdan if (use_suffix) { 929c66bbc91SGabor Kovesdan cmp_res = cmpsuffix(SI1, SI2); 930c66bbc91SGabor Kovesdan if (cmp_res) 931c66bbc91SGabor Kovesdan return ((sign1 < 0) ? -cmp_res : cmp_res); 932c66bbc91SGabor Kovesdan } 933c66bbc91SGabor Kovesdan 934c66bbc91SGabor Kovesdan /* if both numbers are empty assume that the strings are equal */ 935c66bbc91SGabor Kovesdan if (main1 < 1 && main2 < 1 && frac1 < 1 && frac2 < 1) 936c66bbc91SGabor Kovesdan return (0); 937c66bbc91SGabor Kovesdan 938c66bbc91SGabor Kovesdan /* 939c66bbc91SGabor Kovesdan * if the main part is of different size, we know the result 940c66bbc91SGabor Kovesdan * (because the leading zeros are removed) 941c66bbc91SGabor Kovesdan */ 942c66bbc91SGabor Kovesdan if (main1 < main2) 943c66bbc91SGabor Kovesdan cmp_res = -1; 944c66bbc91SGabor Kovesdan else if (main1 > main2) 945c66bbc91SGabor Kovesdan cmp_res = +1; 946c66bbc91SGabor Kovesdan /* if the sizes are equal then simple non-collate string compare gives the correct result */ 947c66bbc91SGabor Kovesdan else 948c66bbc91SGabor Kovesdan cmp_res = wcscmp(smain1, smain2); 949c66bbc91SGabor Kovesdan 950c66bbc91SGabor Kovesdan /* check fraction */ 951c66bbc91SGabor Kovesdan if (!cmp_res) 952c66bbc91SGabor Kovesdan cmp_res = wcscmp(sfrac1, sfrac2); 953c66bbc91SGabor Kovesdan 954c66bbc91SGabor Kovesdan if (!cmp_res) 955c66bbc91SGabor Kovesdan return (0); 956c66bbc91SGabor Kovesdan 957c66bbc91SGabor Kovesdan /* reverse result if the signs are negative */ 958c66bbc91SGabor Kovesdan if (sign1 < 0 && sign2 < 0) 959c66bbc91SGabor Kovesdan cmp_res = -cmp_res; 960c66bbc91SGabor Kovesdan 961c66bbc91SGabor Kovesdan return (cmp_res); 962c66bbc91SGabor Kovesdan } 963c66bbc91SGabor Kovesdan 964c66bbc91SGabor Kovesdan /* 965c66bbc91SGabor Kovesdan * Implements numeric sort (-n). 966c66bbc91SGabor Kovesdan */ 967c66bbc91SGabor Kovesdan static int 968c66bbc91SGabor Kovesdan numcoll(struct key_value *kv1, struct key_value *kv2, size_t offset) 969c66bbc91SGabor Kovesdan { 970e5f71a07SPedro F. Giffuni 971c66bbc91SGabor Kovesdan return (numcoll_impl(kv1, kv2, offset, false)); 972c66bbc91SGabor Kovesdan } 973c66bbc91SGabor Kovesdan 974c66bbc91SGabor Kovesdan /* 975c66bbc91SGabor Kovesdan * Implements 'human' numeric sort (-h). 976c66bbc91SGabor Kovesdan */ 977c66bbc91SGabor Kovesdan static int 978c66bbc91SGabor Kovesdan hnumcoll(struct key_value *kv1, struct key_value *kv2, size_t offset) 979c66bbc91SGabor Kovesdan { 980e5f71a07SPedro F. Giffuni 981c66bbc91SGabor Kovesdan return (numcoll_impl(kv1, kv2, offset, true)); 982c66bbc91SGabor Kovesdan } 983c66bbc91SGabor Kovesdan 984c66bbc91SGabor Kovesdan /* 985c66bbc91SGabor Kovesdan * Implements random sort (-R). 986c66bbc91SGabor Kovesdan */ 987c66bbc91SGabor Kovesdan static int 98889b7a587SGabor Kovesdan randomcoll(struct key_value *kv1, struct key_value *kv2, 98989b7a587SGabor Kovesdan size_t offset __unused) 990c66bbc91SGabor Kovesdan { 991c66bbc91SGabor Kovesdan struct bwstring *s1, *s2; 992c66bbc91SGabor Kovesdan MD5_CTX ctx1, ctx2; 993*fff4eaebSConrad Meyer unsigned char hash1[MD5_DIGEST_LENGTH], hash2[MD5_DIGEST_LENGTH]; 994c66bbc91SGabor Kovesdan 995c66bbc91SGabor Kovesdan s1 = kv1->k; 996c66bbc91SGabor Kovesdan s2 = kv2->k; 997c66bbc91SGabor Kovesdan 998c66bbc91SGabor Kovesdan if (debug_sort) { 999c66bbc91SGabor Kovesdan bwsprintf(stdout, s1, "; k1=<", ">"); 1000c66bbc91SGabor Kovesdan bwsprintf(stdout, s2, ", k2=<", ">"); 1001c66bbc91SGabor Kovesdan } 1002c66bbc91SGabor Kovesdan 1003c66bbc91SGabor Kovesdan if (s1 == s2) 1004c66bbc91SGabor Kovesdan return (0); 1005c66bbc91SGabor Kovesdan 1006c66bbc91SGabor Kovesdan memcpy(&ctx1, &md5_ctx, sizeof(MD5_CTX)); 1007c66bbc91SGabor Kovesdan memcpy(&ctx2, &md5_ctx, sizeof(MD5_CTX)); 1008c66bbc91SGabor Kovesdan 1009c66bbc91SGabor Kovesdan MD5Update(&ctx1, bwsrawdata(s1), bwsrawlen(s1)); 1010c66bbc91SGabor Kovesdan MD5Update(&ctx2, bwsrawdata(s2), bwsrawlen(s2)); 1011c66bbc91SGabor Kovesdan 1012*fff4eaebSConrad Meyer MD5Final(hash1, &ctx1); 1013*fff4eaebSConrad Meyer MD5Final(hash2, &ctx2); 1014c66bbc91SGabor Kovesdan 1015*fff4eaebSConrad Meyer return (memcmp(hash1, hash2, sizeof(hash1))); 1016c66bbc91SGabor Kovesdan } 1017c66bbc91SGabor Kovesdan 1018c66bbc91SGabor Kovesdan /* 1019c66bbc91SGabor Kovesdan * Implements version sort (-V). 1020c66bbc91SGabor Kovesdan */ 1021c66bbc91SGabor Kovesdan static int 102289b7a587SGabor Kovesdan versioncoll(struct key_value *kv1, struct key_value *kv2, 102389b7a587SGabor Kovesdan size_t offset __unused) 1024c66bbc91SGabor Kovesdan { 1025c66bbc91SGabor Kovesdan struct bwstring *s1, *s2; 1026c66bbc91SGabor Kovesdan 1027c66bbc91SGabor Kovesdan s1 = kv1->k; 1028c66bbc91SGabor Kovesdan s2 = kv2->k; 1029c66bbc91SGabor Kovesdan 1030c66bbc91SGabor Kovesdan if (debug_sort) { 1031c66bbc91SGabor Kovesdan bwsprintf(stdout, s1, "; k1=<", ">"); 1032c66bbc91SGabor Kovesdan bwsprintf(stdout, s2, ", k2=<", ">"); 1033c66bbc91SGabor Kovesdan } 1034c66bbc91SGabor Kovesdan 1035c66bbc91SGabor Kovesdan if (s1 == s2) 1036c66bbc91SGabor Kovesdan return (0); 1037c66bbc91SGabor Kovesdan 1038c66bbc91SGabor Kovesdan return (vcmp(s1, s2)); 1039c66bbc91SGabor Kovesdan } 1040c66bbc91SGabor Kovesdan 1041c66bbc91SGabor Kovesdan /* 1042c66bbc91SGabor Kovesdan * Check for minus infinity 1043c66bbc91SGabor Kovesdan */ 1044c66bbc91SGabor Kovesdan static inline bool 1045c66bbc91SGabor Kovesdan huge_minus(double d, int err1) 1046c66bbc91SGabor Kovesdan { 1047e5f71a07SPedro F. Giffuni 1048c66bbc91SGabor Kovesdan if (err1 == ERANGE) 1049c66bbc91SGabor Kovesdan if (d == -HUGE_VAL || d == -HUGE_VALF || d == -HUGE_VALL) 1050c66bbc91SGabor Kovesdan return (+1); 1051c66bbc91SGabor Kovesdan 1052c66bbc91SGabor Kovesdan return (0); 1053c66bbc91SGabor Kovesdan } 1054c66bbc91SGabor Kovesdan 1055c66bbc91SGabor Kovesdan /* 1056c66bbc91SGabor Kovesdan * Check for plus infinity 1057c66bbc91SGabor Kovesdan */ 1058c66bbc91SGabor Kovesdan static inline bool 1059c66bbc91SGabor Kovesdan huge_plus(double d, int err1) 1060c66bbc91SGabor Kovesdan { 1061e5f71a07SPedro F. Giffuni 1062c66bbc91SGabor Kovesdan if (err1 == ERANGE) 1063c66bbc91SGabor Kovesdan if (d == HUGE_VAL || d == HUGE_VALF || d == HUGE_VALL) 1064c66bbc91SGabor Kovesdan return (+1); 1065c66bbc91SGabor Kovesdan 1066c66bbc91SGabor Kovesdan return (0); 1067c66bbc91SGabor Kovesdan } 1068c66bbc91SGabor Kovesdan 1069c66bbc91SGabor Kovesdan /* 1070c66bbc91SGabor Kovesdan * Check whether a function is a NAN 1071c66bbc91SGabor Kovesdan */ 1072c66bbc91SGabor Kovesdan static bool 1073c66bbc91SGabor Kovesdan is_nan(double d) 1074c66bbc91SGabor Kovesdan { 1075e5f71a07SPedro F. Giffuni 1076c66bbc91SGabor Kovesdan return ((d == NAN) || (isnan(d))); 1077c66bbc91SGabor Kovesdan } 1078c66bbc91SGabor Kovesdan 1079c66bbc91SGabor Kovesdan /* 1080c66bbc91SGabor Kovesdan * Compare two NANs 1081c66bbc91SGabor Kovesdan */ 1082c66bbc91SGabor Kovesdan static int 1083c66bbc91SGabor Kovesdan cmp_nans(double d1, double d2) 1084c66bbc91SGabor Kovesdan { 1085e5f71a07SPedro F. Giffuni 1086c66bbc91SGabor Kovesdan if (d1 < d2) 1087c66bbc91SGabor Kovesdan return (-1); 1088ed7aec1eSMarius Strobl if (d1 > d2) 1089c66bbc91SGabor Kovesdan return (+1); 1090c66bbc91SGabor Kovesdan return (0); 1091c66bbc91SGabor Kovesdan } 1092c66bbc91SGabor Kovesdan 1093c66bbc91SGabor Kovesdan /* 1094c66bbc91SGabor Kovesdan * Implements general numeric sort (-g). 1095c66bbc91SGabor Kovesdan */ 1096c66bbc91SGabor Kovesdan static int 109789b7a587SGabor Kovesdan gnumcoll(struct key_value *kv1, struct key_value *kv2, 109889b7a587SGabor Kovesdan size_t offset __unused) 1099c66bbc91SGabor Kovesdan { 1100c66bbc91SGabor Kovesdan double d1, d2; 1101c66bbc91SGabor Kovesdan int err1, err2; 1102c66bbc91SGabor Kovesdan bool empty1, empty2, key1_read, key2_read; 1103c66bbc91SGabor Kovesdan 1104c66bbc91SGabor Kovesdan d1 = d2 = 0; 1105c66bbc91SGabor Kovesdan err1 = err2 = 0; 1106c66bbc91SGabor Kovesdan key1_read = key2_read = false; 1107c66bbc91SGabor Kovesdan 1108c66bbc91SGabor Kovesdan if (debug_sort) { 1109c66bbc91SGabor Kovesdan bwsprintf(stdout, kv1->k, "; k1=<", ">"); 1110c66bbc91SGabor Kovesdan bwsprintf(stdout, kv2->k, "; k2=<", ">"); 1111c66bbc91SGabor Kovesdan } 1112c66bbc91SGabor Kovesdan 1113c66bbc91SGabor Kovesdan if (kv1->hint->status == HS_UNINITIALIZED) { 1114c66bbc91SGabor Kovesdan errno = 0; 1115c66bbc91SGabor Kovesdan d1 = bwstod(kv1->k, &empty1); 1116c66bbc91SGabor Kovesdan err1 = errno; 1117c66bbc91SGabor Kovesdan 1118c66bbc91SGabor Kovesdan if (empty1) 1119c66bbc91SGabor Kovesdan kv1->hint->v.gh.notnum = true; 1120c66bbc91SGabor Kovesdan else if (err1 == 0) { 1121c66bbc91SGabor Kovesdan kv1->hint->v.gh.d = d1; 1122c66bbc91SGabor Kovesdan kv1->hint->v.gh.nan = is_nan(d1); 1123c66bbc91SGabor Kovesdan kv1->hint->status = HS_INITIALIZED; 1124c66bbc91SGabor Kovesdan } else 1125c66bbc91SGabor Kovesdan kv1->hint->status = HS_ERROR; 1126c66bbc91SGabor Kovesdan 1127c66bbc91SGabor Kovesdan key1_read = true; 1128c66bbc91SGabor Kovesdan } 1129c66bbc91SGabor Kovesdan 1130c66bbc91SGabor Kovesdan if (kv2->hint->status == HS_UNINITIALIZED) { 1131c66bbc91SGabor Kovesdan errno = 0; 1132c66bbc91SGabor Kovesdan d2 = bwstod(kv2->k, &empty2); 1133c66bbc91SGabor Kovesdan err2 = errno; 1134c66bbc91SGabor Kovesdan 1135c66bbc91SGabor Kovesdan if (empty2) 1136c66bbc91SGabor Kovesdan kv2->hint->v.gh.notnum = true; 1137c66bbc91SGabor Kovesdan else if (err2 == 0) { 1138c66bbc91SGabor Kovesdan kv2->hint->v.gh.d = d2; 1139c66bbc91SGabor Kovesdan kv2->hint->v.gh.nan = is_nan(d2); 1140c66bbc91SGabor Kovesdan kv2->hint->status = HS_INITIALIZED; 1141c66bbc91SGabor Kovesdan } else 1142c66bbc91SGabor Kovesdan kv2->hint->status = HS_ERROR; 1143c66bbc91SGabor Kovesdan 1144c66bbc91SGabor Kovesdan key2_read = true; 1145c66bbc91SGabor Kovesdan } 1146c66bbc91SGabor Kovesdan 1147c66bbc91SGabor Kovesdan if (kv1->hint->status == HS_INITIALIZED && 1148c66bbc91SGabor Kovesdan kv2->hint->status == HS_INITIALIZED) { 1149c66bbc91SGabor Kovesdan if (kv1->hint->v.gh.notnum) 1150c66bbc91SGabor Kovesdan return ((kv2->hint->v.gh.notnum) ? 0 : -1); 1151c66bbc91SGabor Kovesdan else if (kv2->hint->v.gh.notnum) 1152c66bbc91SGabor Kovesdan return (+1); 1153c66bbc91SGabor Kovesdan 1154c66bbc91SGabor Kovesdan if (kv1->hint->v.gh.nan) 1155c66bbc91SGabor Kovesdan return ((kv2->hint->v.gh.nan) ? 1156c66bbc91SGabor Kovesdan cmp_nans(kv1->hint->v.gh.d, kv2->hint->v.gh.d) : 1157c66bbc91SGabor Kovesdan -1); 1158c66bbc91SGabor Kovesdan else if (kv2->hint->v.gh.nan) 1159c66bbc91SGabor Kovesdan return (+1); 1160c66bbc91SGabor Kovesdan 1161c66bbc91SGabor Kovesdan d1 = kv1->hint->v.gh.d; 1162c66bbc91SGabor Kovesdan d2 = kv2->hint->v.gh.d; 1163c66bbc91SGabor Kovesdan 1164c66bbc91SGabor Kovesdan if (d1 < d2) 1165c66bbc91SGabor Kovesdan return (-1); 1166c66bbc91SGabor Kovesdan else if (d1 > d2) 1167c66bbc91SGabor Kovesdan return (+1); 1168c66bbc91SGabor Kovesdan else 1169c66bbc91SGabor Kovesdan return (0); 1170c66bbc91SGabor Kovesdan } 1171c66bbc91SGabor Kovesdan 1172c66bbc91SGabor Kovesdan if (!key1_read) { 1173c66bbc91SGabor Kovesdan errno = 0; 1174c66bbc91SGabor Kovesdan d1 = bwstod(kv1->k, &empty1); 1175c66bbc91SGabor Kovesdan err1 = errno; 1176c66bbc91SGabor Kovesdan } 1177c66bbc91SGabor Kovesdan 1178c66bbc91SGabor Kovesdan if (!key2_read) { 1179c66bbc91SGabor Kovesdan errno = 0; 1180c66bbc91SGabor Kovesdan d2 = bwstod(kv2->k, &empty2); 1181c66bbc91SGabor Kovesdan err2 = errno; 1182c66bbc91SGabor Kovesdan } 1183c66bbc91SGabor Kovesdan 1184c66bbc91SGabor Kovesdan /* Non-value case: */ 1185c66bbc91SGabor Kovesdan if (empty1) 1186c66bbc91SGabor Kovesdan return (empty2 ? 0 : -1); 1187c66bbc91SGabor Kovesdan else if (empty2) 1188c66bbc91SGabor Kovesdan return (+1); 1189c66bbc91SGabor Kovesdan 1190c66bbc91SGabor Kovesdan /* NAN case */ 1191c66bbc91SGabor Kovesdan if (is_nan(d1)) 1192c66bbc91SGabor Kovesdan return (is_nan(d2) ? cmp_nans(d1, d2) : -1); 1193c66bbc91SGabor Kovesdan else if (is_nan(d2)) 1194c66bbc91SGabor Kovesdan return (+1); 1195c66bbc91SGabor Kovesdan 1196c66bbc91SGabor Kovesdan /* Infinities */ 1197c66bbc91SGabor Kovesdan if (err1 == ERANGE || err2 == ERANGE) { 1198c66bbc91SGabor Kovesdan /* Minus infinity case */ 1199c66bbc91SGabor Kovesdan if (huge_minus(d1, err1)) { 1200c66bbc91SGabor Kovesdan if (huge_minus(d2, err2)) { 1201c66bbc91SGabor Kovesdan if (d1 < d2) 1202c66bbc91SGabor Kovesdan return (-1); 1203c66bbc91SGabor Kovesdan if (d1 > d2) 1204c66bbc91SGabor Kovesdan return (+1); 1205c66bbc91SGabor Kovesdan return (0); 1206c66bbc91SGabor Kovesdan } else 1207c66bbc91SGabor Kovesdan return (-1); 1208c66bbc91SGabor Kovesdan 1209c66bbc91SGabor Kovesdan } else if (huge_minus(d2, err2)) { 1210c66bbc91SGabor Kovesdan if (huge_minus(d1, err1)) { 1211c66bbc91SGabor Kovesdan if (d1 < d2) 1212c66bbc91SGabor Kovesdan return (-1); 1213c66bbc91SGabor Kovesdan if (d1 > d2) 1214c66bbc91SGabor Kovesdan return (+1); 1215c66bbc91SGabor Kovesdan return (0); 1216c66bbc91SGabor Kovesdan } else 1217c66bbc91SGabor Kovesdan return (+1); 1218c66bbc91SGabor Kovesdan } 1219c66bbc91SGabor Kovesdan 1220c66bbc91SGabor Kovesdan /* Plus infinity case */ 1221c66bbc91SGabor Kovesdan if (huge_plus(d1, err1)) { 1222c66bbc91SGabor Kovesdan if (huge_plus(d2, err2)) { 1223c66bbc91SGabor Kovesdan if (d1 < d2) 1224c66bbc91SGabor Kovesdan return (-1); 1225c66bbc91SGabor Kovesdan if (d1 > d2) 1226c66bbc91SGabor Kovesdan return (+1); 1227c66bbc91SGabor Kovesdan return (0); 1228c66bbc91SGabor Kovesdan } else 1229c66bbc91SGabor Kovesdan return (+1); 1230c66bbc91SGabor Kovesdan } else if (huge_plus(d2, err2)) { 1231c66bbc91SGabor Kovesdan if (huge_plus(d1, err1)) { 1232c66bbc91SGabor Kovesdan if (d1 < d2) 1233c66bbc91SGabor Kovesdan return (-1); 1234c66bbc91SGabor Kovesdan if (d1 > d2) 1235c66bbc91SGabor Kovesdan return (+1); 1236c66bbc91SGabor Kovesdan return (0); 1237c66bbc91SGabor Kovesdan } else 1238c66bbc91SGabor Kovesdan return (-1); 1239c66bbc91SGabor Kovesdan } 1240c66bbc91SGabor Kovesdan } 1241c66bbc91SGabor Kovesdan 1242c66bbc91SGabor Kovesdan if (d1 < d2) 1243c66bbc91SGabor Kovesdan return (-1); 1244c66bbc91SGabor Kovesdan if (d1 > d2) 1245c66bbc91SGabor Kovesdan return (+1); 1246c66bbc91SGabor Kovesdan 1247c66bbc91SGabor Kovesdan return (0); 1248c66bbc91SGabor Kovesdan } 1249c66bbc91SGabor Kovesdan 1250c66bbc91SGabor Kovesdan /* 1251c66bbc91SGabor Kovesdan * Implements month sort (-M). 1252c66bbc91SGabor Kovesdan */ 1253c66bbc91SGabor Kovesdan static int 125489b7a587SGabor Kovesdan monthcoll(struct key_value *kv1, struct key_value *kv2, size_t offset __unused) 1255c66bbc91SGabor Kovesdan { 1256c66bbc91SGabor Kovesdan int val1, val2; 1257c66bbc91SGabor Kovesdan bool key1_read, key2_read; 1258c66bbc91SGabor Kovesdan 1259c66bbc91SGabor Kovesdan val1 = val2 = 0; 1260c66bbc91SGabor Kovesdan key1_read = key2_read = false; 1261c66bbc91SGabor Kovesdan 1262c66bbc91SGabor Kovesdan if (debug_sort) { 1263c66bbc91SGabor Kovesdan bwsprintf(stdout, kv1->k, "; k1=<", ">"); 1264c66bbc91SGabor Kovesdan bwsprintf(stdout, kv2->k, "; k2=<", ">"); 1265c66bbc91SGabor Kovesdan } 1266c66bbc91SGabor Kovesdan 1267c66bbc91SGabor Kovesdan if (kv1->hint->status == HS_UNINITIALIZED) { 1268c66bbc91SGabor Kovesdan kv1->hint->v.Mh.m = bws_month_score(kv1->k); 1269c66bbc91SGabor Kovesdan key1_read = true; 1270c66bbc91SGabor Kovesdan kv1->hint->status = HS_INITIALIZED; 1271c66bbc91SGabor Kovesdan } 1272c66bbc91SGabor Kovesdan 1273c66bbc91SGabor Kovesdan if (kv2->hint->status == HS_UNINITIALIZED) { 1274c66bbc91SGabor Kovesdan kv2->hint->v.Mh.m = bws_month_score(kv2->k); 1275c66bbc91SGabor Kovesdan key2_read = true; 1276c66bbc91SGabor Kovesdan kv2->hint->status = HS_INITIALIZED; 1277c66bbc91SGabor Kovesdan } 1278c66bbc91SGabor Kovesdan 1279c66bbc91SGabor Kovesdan if (kv1->hint->status == HS_INITIALIZED) { 1280c66bbc91SGabor Kovesdan val1 = kv1->hint->v.Mh.m; 1281c66bbc91SGabor Kovesdan key1_read = true; 1282c66bbc91SGabor Kovesdan } 1283c66bbc91SGabor Kovesdan 1284c66bbc91SGabor Kovesdan if (kv2->hint->status == HS_INITIALIZED) { 1285c66bbc91SGabor Kovesdan val2 = kv2->hint->v.Mh.m; 1286c66bbc91SGabor Kovesdan key2_read = true; 1287c66bbc91SGabor Kovesdan } 1288c66bbc91SGabor Kovesdan 1289c66bbc91SGabor Kovesdan if (!key1_read) 1290c66bbc91SGabor Kovesdan val1 = bws_month_score(kv1->k); 1291c66bbc91SGabor Kovesdan if (!key2_read) 1292c66bbc91SGabor Kovesdan val2 = bws_month_score(kv2->k); 1293c66bbc91SGabor Kovesdan 1294c66bbc91SGabor Kovesdan if (val1 == val2) { 1295c66bbc91SGabor Kovesdan return (0); 1296c66bbc91SGabor Kovesdan } 1297c66bbc91SGabor Kovesdan if (val1 < val2) 1298c66bbc91SGabor Kovesdan return (-1); 1299c66bbc91SGabor Kovesdan return (+1); 1300c66bbc91SGabor Kovesdan } 1301