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/stat.h> 34c66bbc91SGabor Kovesdan #include <sys/sysctl.h> 35c66bbc91SGabor Kovesdan #include <sys/types.h> 36c66bbc91SGabor Kovesdan 37c66bbc91SGabor Kovesdan #include <err.h> 38c66bbc91SGabor Kovesdan #include <errno.h> 39*7a590a37SConrad Meyer #include <fcntl.h> 40c66bbc91SGabor Kovesdan #include <getopt.h> 41c66bbc91SGabor Kovesdan #include <limits.h> 42c66bbc91SGabor Kovesdan #include <locale.h> 43c66bbc91SGabor Kovesdan #include <md5.h> 44c66bbc91SGabor Kovesdan #include <regex.h> 45c66bbc91SGabor Kovesdan #include <signal.h> 46c66bbc91SGabor Kovesdan #include <stdbool.h> 47c66bbc91SGabor Kovesdan #include <stdio.h> 48c66bbc91SGabor Kovesdan #include <stdlib.h> 49c66bbc91SGabor Kovesdan #include <string.h> 50c66bbc91SGabor Kovesdan #include <unistd.h> 51c66bbc91SGabor Kovesdan #include <wchar.h> 52c66bbc91SGabor Kovesdan #include <wctype.h> 53c66bbc91SGabor Kovesdan 54c66bbc91SGabor Kovesdan #include "coll.h" 55c66bbc91SGabor Kovesdan #include "file.h" 56c66bbc91SGabor Kovesdan #include "sort.h" 57c66bbc91SGabor Kovesdan 58c66bbc91SGabor Kovesdan #ifndef WITHOUT_NLS 59c66bbc91SGabor Kovesdan #include <nl_types.h> 60c66bbc91SGabor Kovesdan nl_catd catalog; 61c66bbc91SGabor Kovesdan #endif 62c66bbc91SGabor Kovesdan 63c66bbc91SGabor Kovesdan #define OPTIONS "bcCdfghik:Mmno:RrsS:t:T:uVz" 64c66bbc91SGabor Kovesdan 65ce1e997fSGabor Kovesdan static bool need_random; 66c66bbc91SGabor Kovesdan 67c66bbc91SGabor Kovesdan MD5_CTX md5_ctx; 68c66bbc91SGabor Kovesdan 69c66bbc91SGabor Kovesdan /* 70c66bbc91SGabor Kovesdan * Default messages to use when NLS is disabled or no catalogue 71c66bbc91SGabor Kovesdan * is found. 72c66bbc91SGabor Kovesdan */ 73c66bbc91SGabor Kovesdan const char *nlsstr[] = { "", 748818aa39SGabor Kovesdan /* 1*/"mutually exclusive flags", 75c66bbc91SGabor Kovesdan /* 2*/"extra argument not allowed with -c", 768818aa39SGabor Kovesdan /* 3*/"Unknown feature", 77c66bbc91SGabor Kovesdan /* 4*/"Wrong memory buffer specification", 78c66bbc91SGabor Kovesdan /* 5*/"0 field in key specs", 79c66bbc91SGabor Kovesdan /* 6*/"0 column in key specs", 80c66bbc91SGabor Kovesdan /* 7*/"Wrong file mode", 81c66bbc91SGabor Kovesdan /* 8*/"Cannot open file for reading", 82c66bbc91SGabor Kovesdan /* 9*/"Radix sort cannot be used with these sort options", 83c66bbc91SGabor Kovesdan /*10*/"The chosen sort method cannot be used with stable and/or unique sort", 84c66bbc91SGabor Kovesdan /*11*/"Invalid key position", 85c66bbc91SGabor Kovesdan /*12*/"Usage: %s [-bcCdfigMmnrsuz] [-kPOS1[,POS2] ... ] " 86c66bbc91SGabor Kovesdan "[+POS1 [-POS2]] [-S memsize] [-T tmpdir] [-t separator] " 87c66bbc91SGabor Kovesdan "[-o outfile] [--batch-size size] [--files0-from file] " 88c66bbc91SGabor Kovesdan "[--heapsort] [--mergesort] [--radixsort] [--qsort] " 895ca724dcSGabor Kovesdan "[--mmap] " 90c66bbc91SGabor Kovesdan #if defined(SORT_THREADS) 915d5151aeSGabor Kovesdan "[--parallel thread_no] " 92c66bbc91SGabor Kovesdan #endif 93c66bbc91SGabor Kovesdan "[--human-numeric-sort] " 94c66bbc91SGabor Kovesdan "[--version-sort] [--random-sort [--random-source file]] " 95c66bbc91SGabor Kovesdan "[--compress-program program] [file ...]\n" }; 96c66bbc91SGabor Kovesdan 97c66bbc91SGabor Kovesdan struct sort_opts sort_opts_vals; 98c66bbc91SGabor Kovesdan 99ce1e997fSGabor Kovesdan bool debug_sort; 100ce1e997fSGabor Kovesdan bool need_hint; 101c66bbc91SGabor Kovesdan 102c66bbc91SGabor Kovesdan #if defined(SORT_THREADS) 103ab28d4d3SGabor Kovesdan unsigned int ncpu = 1; 104c66bbc91SGabor Kovesdan size_t nthreads = 1; 105c66bbc91SGabor Kovesdan #endif 106c66bbc91SGabor Kovesdan 107ce1e997fSGabor Kovesdan static bool gnusort_numeric_compatibility; 108c66bbc91SGabor Kovesdan 109c66bbc91SGabor Kovesdan static struct sort_mods default_sort_mods_object; 110c66bbc91SGabor Kovesdan struct sort_mods * const default_sort_mods = &default_sort_mods_object; 111c66bbc91SGabor Kovesdan 112ce1e997fSGabor Kovesdan static bool print_symbols_on_debug; 113c66bbc91SGabor Kovesdan 114c66bbc91SGabor Kovesdan /* 115c66bbc91SGabor Kovesdan * Arguments from file (when file0-from option is used: 116c66bbc91SGabor Kovesdan */ 117e8da8c74SGabor Kovesdan static size_t argc_from_file0 = (size_t)-1; 118ce1e997fSGabor Kovesdan static char **argv_from_file0; 119c66bbc91SGabor Kovesdan 120c66bbc91SGabor Kovesdan /* 121c66bbc91SGabor Kovesdan * Placeholder symbols for options which have no single-character equivalent 122c66bbc91SGabor Kovesdan */ 123c66bbc91SGabor Kovesdan enum 124c66bbc91SGabor Kovesdan { 125c66bbc91SGabor Kovesdan SORT_OPT = CHAR_MAX + 1, 126c66bbc91SGabor Kovesdan HELP_OPT, 127c66bbc91SGabor Kovesdan FF_OPT, 128c66bbc91SGabor Kovesdan BS_OPT, 129c66bbc91SGabor Kovesdan VERSION_OPT, 130c66bbc91SGabor Kovesdan DEBUG_OPT, 131c66bbc91SGabor Kovesdan #if defined(SORT_THREADS) 1325d5151aeSGabor Kovesdan PARALLEL_OPT, 133c66bbc91SGabor Kovesdan #endif 134c66bbc91SGabor Kovesdan RANDOMSOURCE_OPT, 135c66bbc91SGabor Kovesdan COMPRESSPROGRAM_OPT, 136c66bbc91SGabor Kovesdan QSORT_OPT, 137c66bbc91SGabor Kovesdan MERGESORT_OPT, 138c66bbc91SGabor Kovesdan HEAPSORT_OPT, 1395ca724dcSGabor Kovesdan RADIXSORT_OPT, 1405ca724dcSGabor Kovesdan MMAP_OPT 141c66bbc91SGabor Kovesdan }; 142c66bbc91SGabor Kovesdan 143c66bbc91SGabor Kovesdan #define NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS 6 144c66bbc91SGabor Kovesdan static const char mutually_exclusive_flags[NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS] = { 'M', 'n', 'g', 'R', 'h', 'V' }; 145c66bbc91SGabor Kovesdan 146bf70beceSEd Schouten static struct option long_options[] = { 147c66bbc91SGabor Kovesdan { "batch-size", required_argument, NULL, BS_OPT }, 148c66bbc91SGabor Kovesdan { "buffer-size", required_argument, NULL, 'S' }, 149c66bbc91SGabor Kovesdan { "check", optional_argument, NULL, 'c' }, 150c66bbc91SGabor Kovesdan { "check=silent|quiet", optional_argument, NULL, 'C' }, 151c66bbc91SGabor Kovesdan { "compress-program", required_argument, NULL, COMPRESSPROGRAM_OPT }, 152c66bbc91SGabor Kovesdan { "debug", no_argument, NULL, DEBUG_OPT }, 153c66bbc91SGabor Kovesdan { "dictionary-order", no_argument, NULL, 'd' }, 154c66bbc91SGabor Kovesdan { "field-separator", required_argument, NULL, 't' }, 155c66bbc91SGabor Kovesdan { "files0-from", required_argument, NULL, FF_OPT }, 156c66bbc91SGabor Kovesdan { "general-numeric-sort", no_argument, NULL, 'g' }, 157c66bbc91SGabor Kovesdan { "heapsort", no_argument, NULL, HEAPSORT_OPT }, 158c66bbc91SGabor Kovesdan { "help",no_argument, NULL, HELP_OPT }, 159c66bbc91SGabor Kovesdan { "human-numeric-sort", no_argument, NULL, 'h' }, 160c66bbc91SGabor Kovesdan { "ignore-leading-blanks", no_argument, NULL, 'b' }, 161c66bbc91SGabor Kovesdan { "ignore-case", no_argument, NULL, 'f' }, 162c66bbc91SGabor Kovesdan { "ignore-nonprinting", no_argument, NULL, 'i' }, 163c66bbc91SGabor Kovesdan { "key", required_argument, NULL, 'k' }, 164c66bbc91SGabor Kovesdan { "merge", no_argument, NULL, 'm' }, 165c66bbc91SGabor Kovesdan { "mergesort", no_argument, NULL, MERGESORT_OPT }, 1665ca724dcSGabor Kovesdan { "mmap", no_argument, NULL, MMAP_OPT }, 167c66bbc91SGabor Kovesdan { "month-sort", no_argument, NULL, 'M' }, 168c66bbc91SGabor Kovesdan { "numeric-sort", no_argument, NULL, 'n' }, 169c66bbc91SGabor Kovesdan { "output", required_argument, NULL, 'o' }, 170c66bbc91SGabor Kovesdan #if defined(SORT_THREADS) 1715d5151aeSGabor Kovesdan { "parallel", required_argument, NULL, PARALLEL_OPT }, 172c66bbc91SGabor Kovesdan #endif 173c66bbc91SGabor Kovesdan { "qsort", no_argument, NULL, QSORT_OPT }, 174c66bbc91SGabor Kovesdan { "radixsort", no_argument, NULL, RADIXSORT_OPT }, 175c66bbc91SGabor Kovesdan { "random-sort", no_argument, NULL, 'R' }, 176c66bbc91SGabor Kovesdan { "random-source", required_argument, NULL, RANDOMSOURCE_OPT }, 177c66bbc91SGabor Kovesdan { "reverse", no_argument, NULL, 'r' }, 178c66bbc91SGabor Kovesdan { "sort", required_argument, NULL, SORT_OPT }, 179c66bbc91SGabor Kovesdan { "stable", no_argument, NULL, 's' }, 180c66bbc91SGabor Kovesdan { "temporary-directory",required_argument, NULL, 'T' }, 181c66bbc91SGabor Kovesdan { "unique", no_argument, NULL, 'u' }, 182c66bbc91SGabor Kovesdan { "version", no_argument, NULL, VERSION_OPT }, 183c66bbc91SGabor Kovesdan { "version-sort",no_argument, NULL, 'V' }, 184c66bbc91SGabor Kovesdan { "zero-terminated", no_argument, NULL, 'z' }, 185c66bbc91SGabor Kovesdan { NULL, no_argument, NULL, 0 } 186c66bbc91SGabor Kovesdan }; 187c66bbc91SGabor Kovesdan 188c66bbc91SGabor Kovesdan void fix_obsolete_keys(int *argc, char **argv); 189c66bbc91SGabor Kovesdan 190c66bbc91SGabor Kovesdan /* 191c66bbc91SGabor Kovesdan * Check where sort modifier is present 192c66bbc91SGabor Kovesdan */ 193c66bbc91SGabor Kovesdan static bool 194c66bbc91SGabor Kovesdan sort_modifier_empty(struct sort_mods *sm) 195c66bbc91SGabor Kovesdan { 196e5f71a07SPedro F. Giffuni 197c66bbc91SGabor Kovesdan if (sm == NULL) 198c66bbc91SGabor Kovesdan return (true); 199c66bbc91SGabor Kovesdan return (!(sm->Mflag || sm->Vflag || sm->nflag || sm->gflag || 200c66bbc91SGabor Kovesdan sm->rflag || sm->Rflag || sm->hflag || sm->dflag || sm->fflag)); 201c66bbc91SGabor Kovesdan } 202c66bbc91SGabor Kovesdan 203c66bbc91SGabor Kovesdan /* 204c66bbc91SGabor Kovesdan * Print out usage text. 205c66bbc91SGabor Kovesdan */ 206c66bbc91SGabor Kovesdan static void 207c66bbc91SGabor Kovesdan usage(bool opt_err) 208c66bbc91SGabor Kovesdan { 209c66bbc91SGabor Kovesdan FILE *out; 210c66bbc91SGabor Kovesdan 211c514c3edSXin LI out = opt_err ? stderr : stdout; 212c66bbc91SGabor Kovesdan 213c66bbc91SGabor Kovesdan fprintf(out, getstr(12), getprogname()); 214c66bbc91SGabor Kovesdan if (opt_err) 215c66bbc91SGabor Kovesdan exit(2); 216c66bbc91SGabor Kovesdan exit(0); 217c66bbc91SGabor Kovesdan } 218c66bbc91SGabor Kovesdan 219c66bbc91SGabor Kovesdan /* 220c66bbc91SGabor Kovesdan * Read input file names from a file (file0-from option). 221c66bbc91SGabor Kovesdan */ 222c66bbc91SGabor Kovesdan static void 223c66bbc91SGabor Kovesdan read_fns_from_file0(const char *fn) 224c66bbc91SGabor Kovesdan { 225c66bbc91SGabor Kovesdan FILE *f; 2260f4b9a90SPedro F. Giffuni char *line = NULL; 2270f4b9a90SPedro F. Giffuni size_t linesize = 0; 2280f4b9a90SPedro F. Giffuni ssize_t linelen; 2290f4b9a90SPedro F. Giffuni 2300f4b9a90SPedro F. Giffuni if (fn == NULL) 2310f4b9a90SPedro F. Giffuni return; 232c66bbc91SGabor Kovesdan 233c66bbc91SGabor Kovesdan f = fopen(fn, "r"); 234c66bbc91SGabor Kovesdan if (f == NULL) 2350f4b9a90SPedro F. Giffuni err(2, "%s", fn); 236c66bbc91SGabor Kovesdan 2370f4b9a90SPedro F. Giffuni while ((linelen = getdelim(&line, &linesize, '\0', f)) != -1) { 2380f4b9a90SPedro F. Giffuni if (*line != '\0') { 239e8da8c74SGabor Kovesdan if (argc_from_file0 == (size_t) - 1) 240e8da8c74SGabor Kovesdan argc_from_file0 = 0; 241c66bbc91SGabor Kovesdan ++argc_from_file0; 242c66bbc91SGabor Kovesdan argv_from_file0 = sort_realloc(argv_from_file0, 243c66bbc91SGabor Kovesdan argc_from_file0 * sizeof(char *)); 244c66bbc91SGabor Kovesdan if (argv_from_file0 == NULL) 245c66bbc91SGabor Kovesdan err(2, NULL); 2460f4b9a90SPedro F. Giffuni argv_from_file0[argc_from_file0 - 1] = line; 2470f4b9a90SPedro F. Giffuni } else { 2480f4b9a90SPedro F. Giffuni free(line); 249c66bbc91SGabor Kovesdan } 2500f4b9a90SPedro F. Giffuni line = NULL; 2510f4b9a90SPedro F. Giffuni linesize = 0; 252c66bbc91SGabor Kovesdan } 2530f4b9a90SPedro F. Giffuni if (ferror(f)) 2540f4b9a90SPedro F. Giffuni err(2, "%s: getdelim", fn); 2550f4b9a90SPedro F. Giffuni 256c66bbc91SGabor Kovesdan closefile(f, fn); 257c66bbc91SGabor Kovesdan } 258c66bbc91SGabor Kovesdan 259c66bbc91SGabor Kovesdan /* 260c66bbc91SGabor Kovesdan * Check how much RAM is available for the sort. 261c66bbc91SGabor Kovesdan */ 262c66bbc91SGabor Kovesdan static void 263c66bbc91SGabor Kovesdan set_hw_params(void) 264c66bbc91SGabor Kovesdan { 26555444243SGabor Kovesdan long pages, psize; 266c66bbc91SGabor Kovesdan 267c66bbc91SGabor Kovesdan #if defined(SORT_THREADS) 268c66bbc91SGabor Kovesdan ncpu = 1; 269c66bbc91SGabor Kovesdan #endif 270c66bbc91SGabor Kovesdan 27155444243SGabor Kovesdan pages = sysconf(_SC_PHYS_PAGES); 27255444243SGabor Kovesdan if (pages < 1) { 27355444243SGabor Kovesdan perror("sysconf pages"); 274665d2db3SXin LI pages = 1; 275c66bbc91SGabor Kovesdan } 27655444243SGabor Kovesdan psize = sysconf(_SC_PAGESIZE); 27755444243SGabor Kovesdan if (psize < 1) { 27855444243SGabor Kovesdan perror("sysconf psize"); 27955444243SGabor Kovesdan psize = 4096; 280c66bbc91SGabor Kovesdan } 281c66bbc91SGabor Kovesdan #if defined(SORT_THREADS) 28255444243SGabor Kovesdan ncpu = (unsigned int)sysconf(_SC_NPROCESSORS_ONLN); 28355444243SGabor Kovesdan if (ncpu < 1) 284c66bbc91SGabor Kovesdan ncpu = 1; 285c66bbc91SGabor Kovesdan else if(ncpu > 32) 286c66bbc91SGabor Kovesdan ncpu = 32; 287c66bbc91SGabor Kovesdan 288c66bbc91SGabor Kovesdan nthreads = ncpu; 289c66bbc91SGabor Kovesdan #endif 290c66bbc91SGabor Kovesdan 291c66bbc91SGabor Kovesdan free_memory = (unsigned long long) pages * (unsigned long long) psize; 29255444243SGabor Kovesdan available_free_memory = free_memory / 2; 293ab28d4d3SGabor Kovesdan 294ab28d4d3SGabor Kovesdan if (available_free_memory < 1024) 295ab28d4d3SGabor Kovesdan available_free_memory = 1024; 296c66bbc91SGabor Kovesdan } 297c66bbc91SGabor Kovesdan 298c66bbc91SGabor Kovesdan /* 299c66bbc91SGabor Kovesdan * Convert "plain" symbol to wide symbol, with default value. 300c66bbc91SGabor Kovesdan */ 301c66bbc91SGabor Kovesdan static void 302c66bbc91SGabor Kovesdan conv_mbtowc(wchar_t *wc, const char *c, const wchar_t def) 303c66bbc91SGabor Kovesdan { 304e5f71a07SPedro F. Giffuni 305c66bbc91SGabor Kovesdan if (wc && c) { 306c66bbc91SGabor Kovesdan int res; 307c66bbc91SGabor Kovesdan 308c66bbc91SGabor Kovesdan res = mbtowc(wc, c, MB_CUR_MAX); 309c66bbc91SGabor Kovesdan if (res < 1) 310c66bbc91SGabor Kovesdan *wc = def; 311c66bbc91SGabor Kovesdan } 312c66bbc91SGabor Kovesdan } 313c66bbc91SGabor Kovesdan 314c66bbc91SGabor Kovesdan /* 315c66bbc91SGabor Kovesdan * Set current locale symbols. 316c66bbc91SGabor Kovesdan */ 317c66bbc91SGabor Kovesdan static void 318c66bbc91SGabor Kovesdan set_locale(void) 319c66bbc91SGabor Kovesdan { 320c66bbc91SGabor Kovesdan struct lconv *lc; 321c66bbc91SGabor Kovesdan const char *locale; 322c66bbc91SGabor Kovesdan 323c66bbc91SGabor Kovesdan setlocale(LC_ALL, ""); 324c66bbc91SGabor Kovesdan 325c66bbc91SGabor Kovesdan lc = localeconv(); 326c66bbc91SGabor Kovesdan 327c66bbc91SGabor Kovesdan if (lc) { 328c66bbc91SGabor Kovesdan /* obtain LC_NUMERIC info */ 329c66bbc91SGabor Kovesdan /* Convert to wide char form */ 330c66bbc91SGabor Kovesdan conv_mbtowc(&symbol_decimal_point, lc->decimal_point, 331c66bbc91SGabor Kovesdan symbol_decimal_point); 332c66bbc91SGabor Kovesdan conv_mbtowc(&symbol_thousands_sep, lc->thousands_sep, 333c66bbc91SGabor Kovesdan symbol_thousands_sep); 334c66bbc91SGabor Kovesdan conv_mbtowc(&symbol_positive_sign, lc->positive_sign, 335c66bbc91SGabor Kovesdan symbol_positive_sign); 336c66bbc91SGabor Kovesdan conv_mbtowc(&symbol_negative_sign, lc->negative_sign, 337c66bbc91SGabor Kovesdan symbol_negative_sign); 338c66bbc91SGabor Kovesdan } 339c66bbc91SGabor Kovesdan 340c66bbc91SGabor Kovesdan if (getenv("GNUSORT_NUMERIC_COMPATIBILITY")) 341c66bbc91SGabor Kovesdan gnusort_numeric_compatibility = true; 342c66bbc91SGabor Kovesdan 343c66bbc91SGabor Kovesdan locale = setlocale(LC_COLLATE, NULL); 344c66bbc91SGabor Kovesdan 345c66bbc91SGabor Kovesdan if (locale) { 346c66bbc91SGabor Kovesdan char *tmpl; 347c66bbc91SGabor Kovesdan const char *cclocale; 348c66bbc91SGabor Kovesdan 349c66bbc91SGabor Kovesdan tmpl = sort_strdup(locale); 350c66bbc91SGabor Kovesdan cclocale = setlocale(LC_COLLATE, "C"); 351c66bbc91SGabor Kovesdan if (cclocale && !strcmp(cclocale, tmpl)) 352c66bbc91SGabor Kovesdan byte_sort = true; 353c66bbc91SGabor Kovesdan else { 354c66bbc91SGabor Kovesdan const char *pclocale; 355c66bbc91SGabor Kovesdan 356c66bbc91SGabor Kovesdan pclocale = setlocale(LC_COLLATE, "POSIX"); 357c66bbc91SGabor Kovesdan if (pclocale && !strcmp(pclocale, tmpl)) 358c66bbc91SGabor Kovesdan byte_sort = true; 359c66bbc91SGabor Kovesdan } 360c66bbc91SGabor Kovesdan setlocale(LC_COLLATE, tmpl); 361c66bbc91SGabor Kovesdan sort_free(tmpl); 362c66bbc91SGabor Kovesdan } 363c66bbc91SGabor Kovesdan } 364c66bbc91SGabor Kovesdan 365c66bbc91SGabor Kovesdan /* 366c66bbc91SGabor Kovesdan * Set directory temporary files. 367c66bbc91SGabor Kovesdan */ 368c66bbc91SGabor Kovesdan static void 369c66bbc91SGabor Kovesdan set_tmpdir(void) 370c66bbc91SGabor Kovesdan { 371c66bbc91SGabor Kovesdan char *td; 372c66bbc91SGabor Kovesdan 373c66bbc91SGabor Kovesdan td = getenv("TMPDIR"); 374c66bbc91SGabor Kovesdan if (td != NULL) 375c66bbc91SGabor Kovesdan tmpdir = sort_strdup(td); 376c66bbc91SGabor Kovesdan } 377c66bbc91SGabor Kovesdan 378c66bbc91SGabor Kovesdan /* 379c66bbc91SGabor Kovesdan * Parse -S option. 380c66bbc91SGabor Kovesdan */ 381c66bbc91SGabor Kovesdan static unsigned long long 382c66bbc91SGabor Kovesdan parse_memory_buffer_value(const char *value) 383c66bbc91SGabor Kovesdan { 384e5f71a07SPedro F. Giffuni 385c66bbc91SGabor Kovesdan if (value == NULL) 386c66bbc91SGabor Kovesdan return (available_free_memory); 387c66bbc91SGabor Kovesdan else { 388c66bbc91SGabor Kovesdan char *endptr; 389c66bbc91SGabor Kovesdan unsigned long long membuf; 390c66bbc91SGabor Kovesdan 391c66bbc91SGabor Kovesdan endptr = NULL; 392c66bbc91SGabor Kovesdan errno = 0; 393c66bbc91SGabor Kovesdan membuf = strtoll(value, &endptr, 10); 394c66bbc91SGabor Kovesdan 395c66bbc91SGabor Kovesdan if (errno != 0) { 3968818aa39SGabor Kovesdan warn("%s",getstr(4)); 397c66bbc91SGabor Kovesdan membuf = available_free_memory; 398c66bbc91SGabor Kovesdan } else { 399c66bbc91SGabor Kovesdan switch (*endptr){ 400c66bbc91SGabor Kovesdan case 'Y': 401c66bbc91SGabor Kovesdan membuf *= 1024; 402c66bbc91SGabor Kovesdan /* FALLTHROUGH */ 403c66bbc91SGabor Kovesdan case 'Z': 404c66bbc91SGabor Kovesdan membuf *= 1024; 405c66bbc91SGabor Kovesdan /* FALLTHROUGH */ 406c66bbc91SGabor Kovesdan case 'E': 407c66bbc91SGabor Kovesdan membuf *= 1024; 408c66bbc91SGabor Kovesdan /* FALLTHROUGH */ 409c66bbc91SGabor Kovesdan case 'P': 410c66bbc91SGabor Kovesdan membuf *= 1024; 411c66bbc91SGabor Kovesdan /* FALLTHROUGH */ 412c66bbc91SGabor Kovesdan case 'T': 413c66bbc91SGabor Kovesdan membuf *= 1024; 414c66bbc91SGabor Kovesdan /* FALLTHROUGH */ 415c66bbc91SGabor Kovesdan case 'G': 416c66bbc91SGabor Kovesdan membuf *= 1024; 417c66bbc91SGabor Kovesdan /* FALLTHROUGH */ 418c66bbc91SGabor Kovesdan case 'M': 419c66bbc91SGabor Kovesdan membuf *= 1024; 420c66bbc91SGabor Kovesdan /* FALLTHROUGH */ 421c66bbc91SGabor Kovesdan case '\0': 422c66bbc91SGabor Kovesdan case 'K': 423c66bbc91SGabor Kovesdan membuf *= 1024; 424c66bbc91SGabor Kovesdan /* FALLTHROUGH */ 425c66bbc91SGabor Kovesdan case 'b': 426c66bbc91SGabor Kovesdan break; 427c66bbc91SGabor Kovesdan case '%': 428c66bbc91SGabor Kovesdan membuf = (available_free_memory * membuf) / 429c66bbc91SGabor Kovesdan 100; 430c66bbc91SGabor Kovesdan break; 431c66bbc91SGabor Kovesdan default: 432f187ff08SGabor Kovesdan warnc(EINVAL, "%s", optarg); 433c66bbc91SGabor Kovesdan membuf = available_free_memory; 434c66bbc91SGabor Kovesdan } 435c66bbc91SGabor Kovesdan } 436c66bbc91SGabor Kovesdan return (membuf); 437c66bbc91SGabor Kovesdan } 438c66bbc91SGabor Kovesdan } 439c66bbc91SGabor Kovesdan 440c66bbc91SGabor Kovesdan /* 441c66bbc91SGabor Kovesdan * Signal handler that clears the temporary files. 442c66bbc91SGabor Kovesdan */ 443c66bbc91SGabor Kovesdan static void 4448818aa39SGabor Kovesdan sig_handler(int sig __unused, siginfo_t *siginfo __unused, 4458818aa39SGabor Kovesdan void *context __unused) 446c66bbc91SGabor Kovesdan { 447e5f71a07SPedro F. Giffuni 448c66bbc91SGabor Kovesdan clear_tmp_files(); 449c66bbc91SGabor Kovesdan exit(-1); 450c66bbc91SGabor Kovesdan } 451c66bbc91SGabor Kovesdan 452c66bbc91SGabor Kovesdan /* 453c66bbc91SGabor Kovesdan * Set signal handler on panic signals. 454c66bbc91SGabor Kovesdan */ 455c66bbc91SGabor Kovesdan static void 456c66bbc91SGabor Kovesdan set_signal_handler(void) 457c66bbc91SGabor Kovesdan { 458c66bbc91SGabor Kovesdan struct sigaction sa; 459c66bbc91SGabor Kovesdan 460c66bbc91SGabor Kovesdan memset(&sa, 0, sizeof(sa)); 461c66bbc91SGabor Kovesdan sa.sa_sigaction = &sig_handler; 462c66bbc91SGabor Kovesdan sa.sa_flags = SA_SIGINFO; 463c66bbc91SGabor Kovesdan 464c66bbc91SGabor Kovesdan if (sigaction(SIGTERM, &sa, NULL) < 0) { 465c66bbc91SGabor Kovesdan perror("sigaction"); 466c66bbc91SGabor Kovesdan return; 467c66bbc91SGabor Kovesdan } 468c66bbc91SGabor Kovesdan if (sigaction(SIGHUP, &sa, NULL) < 0) { 469c66bbc91SGabor Kovesdan perror("sigaction"); 470c66bbc91SGabor Kovesdan return; 471c66bbc91SGabor Kovesdan } 472c66bbc91SGabor Kovesdan if (sigaction(SIGINT, &sa, NULL) < 0) { 473c66bbc91SGabor Kovesdan perror("sigaction"); 474c66bbc91SGabor Kovesdan return; 475c66bbc91SGabor Kovesdan } 476c66bbc91SGabor Kovesdan if (sigaction(SIGQUIT, &sa, NULL) < 0) { 477c66bbc91SGabor Kovesdan perror("sigaction"); 478c66bbc91SGabor Kovesdan return; 479c66bbc91SGabor Kovesdan } 480c66bbc91SGabor Kovesdan if (sigaction(SIGABRT, &sa, NULL) < 0) { 481c66bbc91SGabor Kovesdan perror("sigaction"); 482c66bbc91SGabor Kovesdan return; 483c66bbc91SGabor Kovesdan } 484c66bbc91SGabor Kovesdan if (sigaction(SIGBUS, &sa, NULL) < 0) { 485c66bbc91SGabor Kovesdan perror("sigaction"); 486c66bbc91SGabor Kovesdan return; 487c66bbc91SGabor Kovesdan } 488c66bbc91SGabor Kovesdan if (sigaction(SIGSEGV, &sa, NULL) < 0) { 489c66bbc91SGabor Kovesdan perror("sigaction"); 490c66bbc91SGabor Kovesdan return; 491c66bbc91SGabor Kovesdan } 492c66bbc91SGabor Kovesdan if (sigaction(SIGUSR1, &sa, NULL) < 0) { 493c66bbc91SGabor Kovesdan perror("sigaction"); 494c66bbc91SGabor Kovesdan return; 495c66bbc91SGabor Kovesdan } 496c66bbc91SGabor Kovesdan if (sigaction(SIGUSR2, &sa, NULL) < 0) { 497c66bbc91SGabor Kovesdan perror("sigaction"); 498c66bbc91SGabor Kovesdan return; 499c66bbc91SGabor Kovesdan } 500c66bbc91SGabor Kovesdan } 501c66bbc91SGabor Kovesdan 502c66bbc91SGabor Kovesdan /* 503c66bbc91SGabor Kovesdan * Print "unknown" message and exit with status 2. 504c66bbc91SGabor Kovesdan */ 505c66bbc91SGabor Kovesdan static void 506c66bbc91SGabor Kovesdan unknown(const char *what) 507c66bbc91SGabor Kovesdan { 508e5f71a07SPedro F. Giffuni 5098818aa39SGabor Kovesdan errx(2, "%s: %s", getstr(3), what); 510c66bbc91SGabor Kovesdan } 511c66bbc91SGabor Kovesdan 512c66bbc91SGabor Kovesdan /* 513c66bbc91SGabor Kovesdan * Check whether contradictory input options are used. 514c66bbc91SGabor Kovesdan */ 515c66bbc91SGabor Kovesdan static void 516c66bbc91SGabor Kovesdan check_mutually_exclusive_flags(char c, bool *mef_flags) 517c66bbc91SGabor Kovesdan { 518c66bbc91SGabor Kovesdan int fo_index, mec; 519c66bbc91SGabor Kovesdan bool found_others, found_this; 520c66bbc91SGabor Kovesdan 521c66bbc91SGabor Kovesdan found_others = found_this = false; 522c66bbc91SGabor Kovesdan fo_index = 0; 523c66bbc91SGabor Kovesdan 524c66bbc91SGabor Kovesdan for (int i = 0; i < NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS; i++) { 525c66bbc91SGabor Kovesdan mec = mutually_exclusive_flags[i]; 526c66bbc91SGabor Kovesdan 527c66bbc91SGabor Kovesdan if (mec != c) { 528c66bbc91SGabor Kovesdan if (mef_flags[i]) { 529c66bbc91SGabor Kovesdan if (found_this) 5308818aa39SGabor Kovesdan errx(1, "%c:%c: %s", c, mec, getstr(1)); 531c66bbc91SGabor Kovesdan found_others = true; 532c66bbc91SGabor Kovesdan fo_index = i; 533c66bbc91SGabor Kovesdan } 534c66bbc91SGabor Kovesdan } else { 535c66bbc91SGabor Kovesdan if (found_others) 5368818aa39SGabor Kovesdan errx(1, "%c:%c: %s", c, mutually_exclusive_flags[fo_index], getstr(1)); 537c66bbc91SGabor Kovesdan mef_flags[i] = true; 538c66bbc91SGabor Kovesdan found_this = true; 539c66bbc91SGabor Kovesdan } 540c66bbc91SGabor Kovesdan } 541c66bbc91SGabor Kovesdan } 542c66bbc91SGabor Kovesdan 543c66bbc91SGabor Kovesdan /* 544c66bbc91SGabor Kovesdan * Initialise sort opts data. 545c66bbc91SGabor Kovesdan */ 546c66bbc91SGabor Kovesdan static void 547c66bbc91SGabor Kovesdan set_sort_opts(void) 548c66bbc91SGabor Kovesdan { 549e5f71a07SPedro F. Giffuni 550c66bbc91SGabor Kovesdan memset(&default_sort_mods_object, 0, 551c66bbc91SGabor Kovesdan sizeof(default_sort_mods_object)); 552c66bbc91SGabor Kovesdan memset(&sort_opts_vals, 0, sizeof(sort_opts_vals)); 553c66bbc91SGabor Kovesdan default_sort_mods_object.func = 554c66bbc91SGabor Kovesdan get_sort_func(&default_sort_mods_object); 555c66bbc91SGabor Kovesdan } 556c66bbc91SGabor Kovesdan 557c66bbc91SGabor Kovesdan /* 558c66bbc91SGabor Kovesdan * Set a sort modifier on a sort modifiers object. 559c66bbc91SGabor Kovesdan */ 560c66bbc91SGabor Kovesdan static bool 561c66bbc91SGabor Kovesdan set_sort_modifier(struct sort_mods *sm, int c) 562c66bbc91SGabor Kovesdan { 563e5f71a07SPedro F. Giffuni 56474504eefSConrad Meyer if (sm == NULL) 56574504eefSConrad Meyer return (true); 56674504eefSConrad Meyer 567c66bbc91SGabor Kovesdan switch (c){ 568c66bbc91SGabor Kovesdan case 'b': 569c66bbc91SGabor Kovesdan sm->bflag = true; 570c66bbc91SGabor Kovesdan break; 571c66bbc91SGabor Kovesdan case 'd': 572c66bbc91SGabor Kovesdan sm->dflag = true; 573c66bbc91SGabor Kovesdan break; 574c66bbc91SGabor Kovesdan case 'f': 575c66bbc91SGabor Kovesdan sm->fflag = true; 576c66bbc91SGabor Kovesdan break; 577c66bbc91SGabor Kovesdan case 'g': 578c66bbc91SGabor Kovesdan sm->gflag = true; 579c66bbc91SGabor Kovesdan need_hint = true; 580c66bbc91SGabor Kovesdan break; 581c66bbc91SGabor Kovesdan case 'i': 582c66bbc91SGabor Kovesdan sm->iflag = true; 583c66bbc91SGabor Kovesdan break; 584c66bbc91SGabor Kovesdan case 'R': 585c66bbc91SGabor Kovesdan sm->Rflag = true; 586c66bbc91SGabor Kovesdan need_random = true; 587c66bbc91SGabor Kovesdan break; 588c66bbc91SGabor Kovesdan case 'M': 589c66bbc91SGabor Kovesdan initialise_months(); 590c66bbc91SGabor Kovesdan sm->Mflag = true; 591c66bbc91SGabor Kovesdan need_hint = true; 592c66bbc91SGabor Kovesdan break; 593c66bbc91SGabor Kovesdan case 'n': 594c66bbc91SGabor Kovesdan sm->nflag = true; 595c66bbc91SGabor Kovesdan need_hint = true; 596c66bbc91SGabor Kovesdan print_symbols_on_debug = true; 597c66bbc91SGabor Kovesdan break; 598c66bbc91SGabor Kovesdan case 'r': 599c66bbc91SGabor Kovesdan sm->rflag = true; 600c66bbc91SGabor Kovesdan break; 601c66bbc91SGabor Kovesdan case 'V': 602c66bbc91SGabor Kovesdan sm->Vflag = true; 603c66bbc91SGabor Kovesdan break; 604c66bbc91SGabor Kovesdan case 'h': 605c66bbc91SGabor Kovesdan sm->hflag = true; 606c66bbc91SGabor Kovesdan need_hint = true; 607c66bbc91SGabor Kovesdan print_symbols_on_debug = true; 608c66bbc91SGabor Kovesdan break; 609c66bbc91SGabor Kovesdan default: 61074504eefSConrad Meyer return (false); 611c66bbc91SGabor Kovesdan } 61274504eefSConrad Meyer 613c66bbc91SGabor Kovesdan sort_opts_vals.complex_sort = true; 614c66bbc91SGabor Kovesdan sm->func = get_sort_func(sm); 615c66bbc91SGabor Kovesdan return (true); 616c66bbc91SGabor Kovesdan } 617c66bbc91SGabor Kovesdan 618c66bbc91SGabor Kovesdan /* 619c66bbc91SGabor Kovesdan * Parse POS in -k option. 620c66bbc91SGabor Kovesdan */ 621c66bbc91SGabor Kovesdan static int 622c66bbc91SGabor Kovesdan parse_pos(const char *s, struct key_specs *ks, bool *mef_flags, bool second) 623c66bbc91SGabor Kovesdan { 624c66bbc91SGabor Kovesdan regmatch_t pmatch[4]; 625c66bbc91SGabor Kovesdan regex_t re; 626c66bbc91SGabor Kovesdan char *c, *f; 627c66bbc91SGabor Kovesdan const char *sregexp = "^([0-9]+)(\\.[0-9]+)?([bdfirMngRhV]+)?$"; 628c66bbc91SGabor Kovesdan size_t len, nmatch; 629c66bbc91SGabor Kovesdan int ret; 630c66bbc91SGabor Kovesdan 631c66bbc91SGabor Kovesdan ret = -1; 632c66bbc91SGabor Kovesdan nmatch = 4; 633c66bbc91SGabor Kovesdan c = f = NULL; 634c66bbc91SGabor Kovesdan 635c66bbc91SGabor Kovesdan if (regcomp(&re, sregexp, REG_EXTENDED) != 0) 636c66bbc91SGabor Kovesdan return (-1); 637c66bbc91SGabor Kovesdan 638c66bbc91SGabor Kovesdan if (regexec(&re, s, nmatch, pmatch, 0) != 0) 639c66bbc91SGabor Kovesdan goto end; 640c66bbc91SGabor Kovesdan 641c66bbc91SGabor Kovesdan if (pmatch[0].rm_eo <= pmatch[0].rm_so) 642c66bbc91SGabor Kovesdan goto end; 643c66bbc91SGabor Kovesdan 644c66bbc91SGabor Kovesdan if (pmatch[1].rm_eo <= pmatch[1].rm_so) 645c66bbc91SGabor Kovesdan goto end; 646c66bbc91SGabor Kovesdan 647c66bbc91SGabor Kovesdan len = pmatch[1].rm_eo - pmatch[1].rm_so; 648c66bbc91SGabor Kovesdan f = sort_malloc((len + 1) * sizeof(char)); 649c66bbc91SGabor Kovesdan 650c66bbc91SGabor Kovesdan strncpy(f, s + pmatch[1].rm_so, len); 651c66bbc91SGabor Kovesdan f[len] = '\0'; 652c66bbc91SGabor Kovesdan 653c66bbc91SGabor Kovesdan if (second) { 654c66bbc91SGabor Kovesdan errno = 0; 655c66bbc91SGabor Kovesdan ks->f2 = (size_t) strtoul(f, NULL, 10); 656c66bbc91SGabor Kovesdan if (errno != 0) 657f187ff08SGabor Kovesdan err(2, "-k"); 658c66bbc91SGabor Kovesdan if (ks->f2 == 0) { 6598818aa39SGabor Kovesdan warn("%s",getstr(5)); 660c66bbc91SGabor Kovesdan goto end; 661c66bbc91SGabor Kovesdan } 662c66bbc91SGabor Kovesdan } else { 663c66bbc91SGabor Kovesdan errno = 0; 664c66bbc91SGabor Kovesdan ks->f1 = (size_t) strtoul(f, NULL, 10); 665c66bbc91SGabor Kovesdan if (errno != 0) 666f187ff08SGabor Kovesdan err(2, "-k"); 667c66bbc91SGabor Kovesdan if (ks->f1 == 0) { 6688818aa39SGabor Kovesdan warn("%s",getstr(5)); 669c66bbc91SGabor Kovesdan goto end; 670c66bbc91SGabor Kovesdan } 671c66bbc91SGabor Kovesdan } 672c66bbc91SGabor Kovesdan 673c66bbc91SGabor Kovesdan if (pmatch[2].rm_eo > pmatch[2].rm_so) { 674c66bbc91SGabor Kovesdan len = pmatch[2].rm_eo - pmatch[2].rm_so - 1; 675c66bbc91SGabor Kovesdan c = sort_malloc((len + 1) * sizeof(char)); 676c66bbc91SGabor Kovesdan 677c66bbc91SGabor Kovesdan strncpy(c, s + pmatch[2].rm_so + 1, len); 678c66bbc91SGabor Kovesdan c[len] = '\0'; 679c66bbc91SGabor Kovesdan 680c66bbc91SGabor Kovesdan if (second) { 681c66bbc91SGabor Kovesdan errno = 0; 682c66bbc91SGabor Kovesdan ks->c2 = (size_t) strtoul(c, NULL, 10); 683c66bbc91SGabor Kovesdan if (errno != 0) 684f187ff08SGabor Kovesdan err(2, "-k"); 685c66bbc91SGabor Kovesdan } else { 686c66bbc91SGabor Kovesdan errno = 0; 687c66bbc91SGabor Kovesdan ks->c1 = (size_t) strtoul(c, NULL, 10); 688c66bbc91SGabor Kovesdan if (errno != 0) 689f187ff08SGabor Kovesdan err(2, "-k"); 690c66bbc91SGabor Kovesdan if (ks->c1 == 0) { 6918818aa39SGabor Kovesdan warn("%s",getstr(6)); 692c66bbc91SGabor Kovesdan goto end; 693c66bbc91SGabor Kovesdan } 694c66bbc91SGabor Kovesdan } 695c66bbc91SGabor Kovesdan } else { 696c66bbc91SGabor Kovesdan if (second) 697c66bbc91SGabor Kovesdan ks->c2 = 0; 698c66bbc91SGabor Kovesdan else 699c66bbc91SGabor Kovesdan ks->c1 = 1; 700c66bbc91SGabor Kovesdan } 701c66bbc91SGabor Kovesdan 702c66bbc91SGabor Kovesdan if (pmatch[3].rm_eo > pmatch[3].rm_so) { 703c66bbc91SGabor Kovesdan regoff_t i = 0; 704c66bbc91SGabor Kovesdan 705c66bbc91SGabor Kovesdan for (i = pmatch[3].rm_so; i < pmatch[3].rm_eo; i++) { 706c66bbc91SGabor Kovesdan check_mutually_exclusive_flags(s[i], mef_flags); 707c66bbc91SGabor Kovesdan if (s[i] == 'b') { 708c66bbc91SGabor Kovesdan if (second) 709c66bbc91SGabor Kovesdan ks->pos2b = true; 710c66bbc91SGabor Kovesdan else 711c66bbc91SGabor Kovesdan ks->pos1b = true; 712c66bbc91SGabor Kovesdan } else if (!set_sort_modifier(&(ks->sm), s[i])) 713c66bbc91SGabor Kovesdan goto end; 714c66bbc91SGabor Kovesdan } 715c66bbc91SGabor Kovesdan } 716c66bbc91SGabor Kovesdan 717c66bbc91SGabor Kovesdan ret = 0; 718c66bbc91SGabor Kovesdan 719c66bbc91SGabor Kovesdan end: 720c66bbc91SGabor Kovesdan 721c66bbc91SGabor Kovesdan if (c) 722c66bbc91SGabor Kovesdan sort_free(c); 723c66bbc91SGabor Kovesdan if (f) 724c66bbc91SGabor Kovesdan sort_free(f); 725c66bbc91SGabor Kovesdan regfree(&re); 726c66bbc91SGabor Kovesdan 727c66bbc91SGabor Kovesdan return (ret); 728c66bbc91SGabor Kovesdan } 729c66bbc91SGabor Kovesdan 730c66bbc91SGabor Kovesdan /* 731c66bbc91SGabor Kovesdan * Parse -k option value. 732c66bbc91SGabor Kovesdan */ 733c66bbc91SGabor Kovesdan static int 734c66bbc91SGabor Kovesdan parse_k(const char *s, struct key_specs *ks) 735c66bbc91SGabor Kovesdan { 736c66bbc91SGabor Kovesdan int ret = -1; 737c66bbc91SGabor Kovesdan bool mef_flags[NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS] = 738c66bbc91SGabor Kovesdan { false, false, false, false, false, false }; 739c66bbc91SGabor Kovesdan 740c66bbc91SGabor Kovesdan if (s && *s) { 741c66bbc91SGabor Kovesdan char *sptr; 742c66bbc91SGabor Kovesdan 743c66bbc91SGabor Kovesdan sptr = strchr(s, ','); 744c66bbc91SGabor Kovesdan if (sptr) { 745c66bbc91SGabor Kovesdan size_t size1; 746c66bbc91SGabor Kovesdan char *pos1, *pos2; 747c66bbc91SGabor Kovesdan 748c66bbc91SGabor Kovesdan size1 = sptr - s; 749c66bbc91SGabor Kovesdan 750c66bbc91SGabor Kovesdan if (size1 < 1) 751c66bbc91SGabor Kovesdan return (-1); 752c66bbc91SGabor Kovesdan pos1 = sort_malloc((size1 + 1) * sizeof(char)); 753c66bbc91SGabor Kovesdan 754c66bbc91SGabor Kovesdan strncpy(pos1, s, size1); 755c66bbc91SGabor Kovesdan pos1[size1] = '\0'; 756c66bbc91SGabor Kovesdan 757c66bbc91SGabor Kovesdan ret = parse_pos(pos1, ks, mef_flags, false); 758c66bbc91SGabor Kovesdan 759c66bbc91SGabor Kovesdan sort_free(pos1); 760c66bbc91SGabor Kovesdan if (ret < 0) 761c66bbc91SGabor Kovesdan return (ret); 762c66bbc91SGabor Kovesdan 763c66bbc91SGabor Kovesdan pos2 = sort_strdup(sptr + 1); 764c66bbc91SGabor Kovesdan ret = parse_pos(pos2, ks, mef_flags, true); 765c66bbc91SGabor Kovesdan sort_free(pos2); 766c66bbc91SGabor Kovesdan } else 767c66bbc91SGabor Kovesdan ret = parse_pos(s, ks, mef_flags, false); 768c66bbc91SGabor Kovesdan } 769c66bbc91SGabor Kovesdan 770c66bbc91SGabor Kovesdan return (ret); 771c66bbc91SGabor Kovesdan } 772c66bbc91SGabor Kovesdan 773c66bbc91SGabor Kovesdan /* 774c66bbc91SGabor Kovesdan * Parse POS in +POS -POS option. 775c66bbc91SGabor Kovesdan */ 776c66bbc91SGabor Kovesdan static int 777c66bbc91SGabor Kovesdan parse_pos_obs(const char *s, int *nf, int *nc, char* sopts) 778c66bbc91SGabor Kovesdan { 779c66bbc91SGabor Kovesdan regex_t re; 780c66bbc91SGabor Kovesdan regmatch_t pmatch[4]; 781c66bbc91SGabor Kovesdan char *c, *f; 782c66bbc91SGabor Kovesdan const char *sregexp = "^([0-9]+)(\\.[0-9]+)?([A-Za-z]+)?$"; 783c66bbc91SGabor Kovesdan int ret; 784c66bbc91SGabor Kovesdan size_t len, nmatch; 785c66bbc91SGabor Kovesdan 786c66bbc91SGabor Kovesdan ret = -1; 787c66bbc91SGabor Kovesdan nmatch = 4; 788c66bbc91SGabor Kovesdan c = f = NULL; 789c66bbc91SGabor Kovesdan *nc = *nf = 0; 790c66bbc91SGabor Kovesdan 791c66bbc91SGabor Kovesdan if (regcomp(&re, sregexp, REG_EXTENDED) != 0) 792c66bbc91SGabor Kovesdan return (-1); 793c66bbc91SGabor Kovesdan 794c66bbc91SGabor Kovesdan if (regexec(&re, s, nmatch, pmatch, 0) != 0) 795c66bbc91SGabor Kovesdan goto end; 796c66bbc91SGabor Kovesdan 797c66bbc91SGabor Kovesdan if (pmatch[0].rm_eo <= pmatch[0].rm_so) 798c66bbc91SGabor Kovesdan goto end; 799c66bbc91SGabor Kovesdan 800c66bbc91SGabor Kovesdan if (pmatch[1].rm_eo <= pmatch[1].rm_so) 801c66bbc91SGabor Kovesdan goto end; 802c66bbc91SGabor Kovesdan 803c66bbc91SGabor Kovesdan len = pmatch[1].rm_eo - pmatch[1].rm_so; 804c66bbc91SGabor Kovesdan f = sort_malloc((len + 1) * sizeof(char)); 805c66bbc91SGabor Kovesdan 806c66bbc91SGabor Kovesdan strncpy(f, s + pmatch[1].rm_so, len); 807c66bbc91SGabor Kovesdan f[len] = '\0'; 808c66bbc91SGabor Kovesdan 809c66bbc91SGabor Kovesdan errno = 0; 810c66bbc91SGabor Kovesdan *nf = (size_t) strtoul(f, NULL, 10); 811c66bbc91SGabor Kovesdan if (errno != 0) 8128818aa39SGabor Kovesdan errx(2, "%s", getstr(11)); 813c66bbc91SGabor Kovesdan 814c66bbc91SGabor Kovesdan if (pmatch[2].rm_eo > pmatch[2].rm_so) { 815c66bbc91SGabor Kovesdan len = pmatch[2].rm_eo - pmatch[2].rm_so - 1; 816c66bbc91SGabor Kovesdan c = sort_malloc((len + 1) * sizeof(char)); 817c66bbc91SGabor Kovesdan 818c66bbc91SGabor Kovesdan strncpy(c, s + pmatch[2].rm_so + 1, len); 819c66bbc91SGabor Kovesdan c[len] = '\0'; 820c66bbc91SGabor Kovesdan 821c66bbc91SGabor Kovesdan errno = 0; 822c66bbc91SGabor Kovesdan *nc = (size_t) strtoul(c, NULL, 10); 823c66bbc91SGabor Kovesdan if (errno != 0) 8248818aa39SGabor Kovesdan errx(2, "%s", getstr(11)); 825c66bbc91SGabor Kovesdan } 826c66bbc91SGabor Kovesdan 827c66bbc91SGabor Kovesdan if (pmatch[3].rm_eo > pmatch[3].rm_so) { 828c66bbc91SGabor Kovesdan 829c66bbc91SGabor Kovesdan len = pmatch[3].rm_eo - pmatch[3].rm_so; 830c66bbc91SGabor Kovesdan 831c66bbc91SGabor Kovesdan strncpy(sopts, s + pmatch[3].rm_so, len); 832c66bbc91SGabor Kovesdan sopts[len] = '\0'; 833c66bbc91SGabor Kovesdan } 834c66bbc91SGabor Kovesdan 835c66bbc91SGabor Kovesdan ret = 0; 836c66bbc91SGabor Kovesdan 837c66bbc91SGabor Kovesdan end: 838c66bbc91SGabor Kovesdan if (c) 839c66bbc91SGabor Kovesdan sort_free(c); 840c66bbc91SGabor Kovesdan if (f) 841c66bbc91SGabor Kovesdan sort_free(f); 842c66bbc91SGabor Kovesdan regfree(&re); 843c66bbc91SGabor Kovesdan 844c66bbc91SGabor Kovesdan return (ret); 845c66bbc91SGabor Kovesdan } 846c66bbc91SGabor Kovesdan 847c66bbc91SGabor Kovesdan /* 848c66bbc91SGabor Kovesdan * "Translate" obsolete +POS1 -POS2 syntax into new -kPOS1,POS2 syntax 849c66bbc91SGabor Kovesdan */ 850c66bbc91SGabor Kovesdan void 851c66bbc91SGabor Kovesdan fix_obsolete_keys(int *argc, char **argv) 852c66bbc91SGabor Kovesdan { 853c66bbc91SGabor Kovesdan char sopt[129]; 854c66bbc91SGabor Kovesdan 855c66bbc91SGabor Kovesdan for (int i = 1; i < *argc; i++) { 856c66bbc91SGabor Kovesdan char *arg1; 857c66bbc91SGabor Kovesdan 858c66bbc91SGabor Kovesdan arg1 = argv[i]; 859c66bbc91SGabor Kovesdan 860c66bbc91SGabor Kovesdan if (strlen(arg1) > 1 && arg1[0] == '+') { 861c66bbc91SGabor Kovesdan int c1, f1; 862c66bbc91SGabor Kovesdan char sopts1[128]; 863c66bbc91SGabor Kovesdan 864c66bbc91SGabor Kovesdan sopts1[0] = 0; 865c66bbc91SGabor Kovesdan c1 = f1 = 0; 866c66bbc91SGabor Kovesdan 867c66bbc91SGabor Kovesdan if (parse_pos_obs(arg1 + 1, &f1, &c1, sopts1) < 0) 868c66bbc91SGabor Kovesdan continue; 869c66bbc91SGabor Kovesdan else { 870c66bbc91SGabor Kovesdan f1 += 1; 871c66bbc91SGabor Kovesdan c1 += 1; 872c66bbc91SGabor Kovesdan if (i + 1 < *argc) { 873c66bbc91SGabor Kovesdan char *arg2 = argv[i + 1]; 874c66bbc91SGabor Kovesdan 875c66bbc91SGabor Kovesdan if (strlen(arg2) > 1 && 876c66bbc91SGabor Kovesdan arg2[0] == '-') { 877c66bbc91SGabor Kovesdan int c2, f2; 878c66bbc91SGabor Kovesdan char sopts2[128]; 879c66bbc91SGabor Kovesdan 880c66bbc91SGabor Kovesdan sopts2[0] = 0; 881c66bbc91SGabor Kovesdan c2 = f2 = 0; 882c66bbc91SGabor Kovesdan 883c66bbc91SGabor Kovesdan if (parse_pos_obs(arg2 + 1, 884c66bbc91SGabor Kovesdan &f2, &c2, sopts2) >= 0) { 885c66bbc91SGabor Kovesdan if (c2 > 0) 886c66bbc91SGabor Kovesdan f2 += 1; 887c66bbc91SGabor Kovesdan sprintf(sopt, "-k%d.%d%s,%d.%d%s", 888c66bbc91SGabor Kovesdan f1, c1, sopts1, f2, c2, sopts2); 889c66bbc91SGabor Kovesdan argv[i] = sort_strdup(sopt); 890c66bbc91SGabor Kovesdan for (int j = i + 1; j + 1 < *argc; j++) 891c66bbc91SGabor Kovesdan argv[j] = argv[j + 1]; 892c66bbc91SGabor Kovesdan *argc -= 1; 893c66bbc91SGabor Kovesdan continue; 894c66bbc91SGabor Kovesdan } 895c66bbc91SGabor Kovesdan } 896c66bbc91SGabor Kovesdan } 8973e16491dSBaptiste Daroussin sprintf(sopt, "-k%d.%d%s", f1, c1, sopts1); 898c66bbc91SGabor Kovesdan argv[i] = sort_strdup(sopt); 899c66bbc91SGabor Kovesdan } 900c66bbc91SGabor Kovesdan } 901c66bbc91SGabor Kovesdan } 902c66bbc91SGabor Kovesdan } 903c66bbc91SGabor Kovesdan 904c66bbc91SGabor Kovesdan /* 905*7a590a37SConrad Meyer * Seed random sort 906c66bbc91SGabor Kovesdan */ 907c66bbc91SGabor Kovesdan static void 908*7a590a37SConrad Meyer get_random_seed(const char *random_source) 909c66bbc91SGabor Kovesdan { 910*7a590a37SConrad Meyer char randseed[32]; 911*7a590a37SConrad Meyer struct stat fsb, rsb; 912*7a590a37SConrad Meyer ssize_t rd; 913*7a590a37SConrad Meyer int rsfd; 914c66bbc91SGabor Kovesdan 915*7a590a37SConrad Meyer rsfd = -1; 916*7a590a37SConrad Meyer rd = sizeof(randseed); 917c66bbc91SGabor Kovesdan 918*7a590a37SConrad Meyer if (random_source == NULL) { 919*7a590a37SConrad Meyer if (getentropy(randseed, sizeof(randseed)) < 0) 920*7a590a37SConrad Meyer err(EX_SOFTWARE, "getentropy"); 921*7a590a37SConrad Meyer goto out; 922c66bbc91SGabor Kovesdan } 923c66bbc91SGabor Kovesdan 924*7a590a37SConrad Meyer rsfd = open(random_source, O_RDONLY | O_CLOEXEC); 925*7a590a37SConrad Meyer if (rsfd < 0) 926*7a590a37SConrad Meyer err(EX_NOINPUT, "open: %s", random_source); 927c66bbc91SGabor Kovesdan 928*7a590a37SConrad Meyer if (fstat(rsfd, &fsb) != 0) 929*7a590a37SConrad Meyer err(EX_SOFTWARE, "fstat"); 930c66bbc91SGabor Kovesdan 931*7a590a37SConrad Meyer if (!S_ISREG(fsb.st_mode) && !S_ISCHR(fsb.st_mode)) 932*7a590a37SConrad Meyer err(EX_USAGE, 933*7a590a37SConrad Meyer "random seed isn't a regular file or /dev/random"); 934c66bbc91SGabor Kovesdan 935*7a590a37SConrad Meyer /* 936*7a590a37SConrad Meyer * Regular files: read up to maximum seed size and explicitly 937*7a590a37SConrad Meyer * reject longer files. 938*7a590a37SConrad Meyer */ 939*7a590a37SConrad Meyer if (S_ISREG(fsb.st_mode)) { 940*7a590a37SConrad Meyer if (fsb.st_size > (off_t)sizeof(randseed)) 941*7a590a37SConrad Meyer errx(EX_USAGE, "random seed is too large (%jd >" 942*7a590a37SConrad Meyer " %zu)!", (intmax_t)fsb.st_size, 943*7a590a37SConrad Meyer sizeof(randseed)); 944*7a590a37SConrad Meyer else if (fsb.st_size < 1) 945*7a590a37SConrad Meyer errx(EX_USAGE, "random seed is too small (" 946*7a590a37SConrad Meyer "0 bytes)"); 947c66bbc91SGabor Kovesdan 948*7a590a37SConrad Meyer memset(randseed, 0, sizeof(randseed)); 949c66bbc91SGabor Kovesdan 950*7a590a37SConrad Meyer rd = read(rsfd, randseed, fsb.st_size); 951*7a590a37SConrad Meyer if (rd < 0) 952*7a590a37SConrad Meyer err(EX_SOFTWARE, "reading random seed file %s", 953*7a590a37SConrad Meyer random_source); 954*7a590a37SConrad Meyer if (rd < (ssize_t)fsb.st_size) 955*7a590a37SConrad Meyer errx(EX_SOFTWARE, "short read from %s", random_source); 956*7a590a37SConrad Meyer } else if (S_ISCHR(fsb.st_mode)) { 957*7a590a37SConrad Meyer if (stat("/dev/random", &rsb) < 0) 958*7a590a37SConrad Meyer err(EX_SOFTWARE, "stat"); 959*7a590a37SConrad Meyer 960*7a590a37SConrad Meyer if (fsb.st_dev != rsb.st_dev || 961*7a590a37SConrad Meyer fsb.st_ino != rsb.st_ino) 962*7a590a37SConrad Meyer errx(EX_USAGE, "random seed is a character " 963*7a590a37SConrad Meyer "device other than /dev/random"); 964*7a590a37SConrad Meyer 965*7a590a37SConrad Meyer if (getentropy(randseed, sizeof(randseed)) < 0) 966*7a590a37SConrad Meyer err(EX_SOFTWARE, "getentropy"); 967c66bbc91SGabor Kovesdan } 968*7a590a37SConrad Meyer 969*7a590a37SConrad Meyer out: 970*7a590a37SConrad Meyer if (rsfd >= 0) 971*7a590a37SConrad Meyer close(rsfd); 972*7a590a37SConrad Meyer 973c66bbc91SGabor Kovesdan MD5Init(&md5_ctx); 974*7a590a37SConrad Meyer MD5Update(&md5_ctx, randseed, rd); 975c66bbc91SGabor Kovesdan } 976c66bbc91SGabor Kovesdan 977c66bbc91SGabor Kovesdan /* 978c66bbc91SGabor Kovesdan * Main function. 979c66bbc91SGabor Kovesdan */ 980c66bbc91SGabor Kovesdan int 981c66bbc91SGabor Kovesdan main(int argc, char **argv) 982c66bbc91SGabor Kovesdan { 983c66bbc91SGabor Kovesdan char *outfile, *real_outfile; 984*7a590a37SConrad Meyer char *random_source = NULL; 985c66bbc91SGabor Kovesdan int c, result; 986c66bbc91SGabor Kovesdan bool mef_flags[NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS] = 987c66bbc91SGabor Kovesdan { false, false, false, false, false, false }; 988c66bbc91SGabor Kovesdan 989c66bbc91SGabor Kovesdan result = 0; 990c66bbc91SGabor Kovesdan outfile = sort_strdup("-"); 991c66bbc91SGabor Kovesdan real_outfile = NULL; 992c66bbc91SGabor Kovesdan 993c66bbc91SGabor Kovesdan struct sort_mods *sm = &default_sort_mods_object; 994c66bbc91SGabor Kovesdan 995c66bbc91SGabor Kovesdan init_tmp_files(); 996c66bbc91SGabor Kovesdan 997c66bbc91SGabor Kovesdan set_signal_handler(); 998c66bbc91SGabor Kovesdan 999c66bbc91SGabor Kovesdan set_hw_params(); 1000c66bbc91SGabor Kovesdan set_locale(); 1001c66bbc91SGabor Kovesdan set_tmpdir(); 1002c66bbc91SGabor Kovesdan set_sort_opts(); 1003c66bbc91SGabor Kovesdan 1004c66bbc91SGabor Kovesdan fix_obsolete_keys(&argc, argv); 1005c66bbc91SGabor Kovesdan 1006c66bbc91SGabor Kovesdan while (((c = getopt_long(argc, argv, OPTIONS, long_options, NULL)) 1007c66bbc91SGabor Kovesdan != -1)) { 1008c66bbc91SGabor Kovesdan 1009c66bbc91SGabor Kovesdan check_mutually_exclusive_flags(c, mef_flags); 1010c66bbc91SGabor Kovesdan 1011c66bbc91SGabor Kovesdan if (!set_sort_modifier(sm, c)) { 1012c66bbc91SGabor Kovesdan 1013c66bbc91SGabor Kovesdan switch (c) { 1014c66bbc91SGabor Kovesdan case 'c': 1015c66bbc91SGabor Kovesdan sort_opts_vals.cflag = true; 1016c66bbc91SGabor Kovesdan if (optarg) { 1017c66bbc91SGabor Kovesdan if (!strcmp(optarg, "diagnose-first")) 1018c66bbc91SGabor Kovesdan ; 1019c66bbc91SGabor Kovesdan else if (!strcmp(optarg, "silent") || 1020c66bbc91SGabor Kovesdan !strcmp(optarg, "quiet")) 1021c66bbc91SGabor Kovesdan sort_opts_vals.csilentflag = true; 1022c66bbc91SGabor Kovesdan else if (*optarg) 1023c66bbc91SGabor Kovesdan unknown(optarg); 1024c66bbc91SGabor Kovesdan } 1025c66bbc91SGabor Kovesdan break; 1026c66bbc91SGabor Kovesdan case 'C': 1027c66bbc91SGabor Kovesdan sort_opts_vals.cflag = true; 1028c66bbc91SGabor Kovesdan sort_opts_vals.csilentflag = true; 1029c66bbc91SGabor Kovesdan break; 1030c66bbc91SGabor Kovesdan case 'k': 1031c66bbc91SGabor Kovesdan { 1032c66bbc91SGabor Kovesdan sort_opts_vals.complex_sort = true; 1033c66bbc91SGabor Kovesdan sort_opts_vals.kflag = true; 1034c66bbc91SGabor Kovesdan 1035c66bbc91SGabor Kovesdan keys_num++; 1036c66bbc91SGabor Kovesdan keys = sort_realloc(keys, keys_num * 1037c66bbc91SGabor Kovesdan sizeof(struct key_specs)); 1038c66bbc91SGabor Kovesdan memset(&(keys[keys_num - 1]), 0, 1039c66bbc91SGabor Kovesdan sizeof(struct key_specs)); 1040c66bbc91SGabor Kovesdan 1041c66bbc91SGabor Kovesdan if (parse_k(optarg, &(keys[keys_num - 1])) 1042c66bbc91SGabor Kovesdan < 0) { 1043f187ff08SGabor Kovesdan errc(2, EINVAL, "-k %s", optarg); 1044c66bbc91SGabor Kovesdan } 1045c66bbc91SGabor Kovesdan 1046c66bbc91SGabor Kovesdan break; 1047c66bbc91SGabor Kovesdan } 1048c66bbc91SGabor Kovesdan case 'm': 1049c66bbc91SGabor Kovesdan sort_opts_vals.mflag = true; 1050c66bbc91SGabor Kovesdan break; 1051c66bbc91SGabor Kovesdan case 'o': 1052f50d9b2fSGabor Kovesdan outfile = sort_realloc(outfile, (strlen(optarg) + 1)); 1053f50d9b2fSGabor Kovesdan strcpy(outfile, optarg); 1054c66bbc91SGabor Kovesdan break; 1055c66bbc91SGabor Kovesdan case 's': 1056c66bbc91SGabor Kovesdan sort_opts_vals.sflag = true; 1057c66bbc91SGabor Kovesdan break; 1058c66bbc91SGabor Kovesdan case 'S': 1059c66bbc91SGabor Kovesdan available_free_memory = 1060c66bbc91SGabor Kovesdan parse_memory_buffer_value(optarg); 1061c66bbc91SGabor Kovesdan break; 1062c66bbc91SGabor Kovesdan case 'T': 1063c66bbc91SGabor Kovesdan tmpdir = sort_strdup(optarg); 1064c66bbc91SGabor Kovesdan break; 1065c66bbc91SGabor Kovesdan case 't': 10665ca724dcSGabor Kovesdan while (strlen(optarg) > 1) { 10675ca724dcSGabor Kovesdan if (optarg[0] != '\\') { 1068f187ff08SGabor Kovesdan errc(2, EINVAL, "%s", optarg); 1069c66bbc91SGabor Kovesdan } 10705ca724dcSGabor Kovesdan optarg += 1; 10715ca724dcSGabor Kovesdan if (*optarg == '0') { 1072c66bbc91SGabor Kovesdan *optarg = 0; 10735ca724dcSGabor Kovesdan break; 10745ca724dcSGabor Kovesdan } 1075c66bbc91SGabor Kovesdan } 1076c66bbc91SGabor Kovesdan sort_opts_vals.tflag = true; 1077c66bbc91SGabor Kovesdan sort_opts_vals.field_sep = btowc(optarg[0]); 1078c66bbc91SGabor Kovesdan if (sort_opts_vals.field_sep == WEOF) { 1079c66bbc91SGabor Kovesdan errno = EINVAL; 1080c66bbc91SGabor Kovesdan err(2, NULL); 1081c66bbc91SGabor Kovesdan } 1082c66bbc91SGabor Kovesdan if (!gnusort_numeric_compatibility) { 1083c66bbc91SGabor Kovesdan if (symbol_decimal_point == sort_opts_vals.field_sep) 1084c66bbc91SGabor Kovesdan symbol_decimal_point = WEOF; 1085c66bbc91SGabor Kovesdan if (symbol_thousands_sep == sort_opts_vals.field_sep) 1086c66bbc91SGabor Kovesdan symbol_thousands_sep = WEOF; 1087c66bbc91SGabor Kovesdan if (symbol_negative_sign == sort_opts_vals.field_sep) 1088c66bbc91SGabor Kovesdan symbol_negative_sign = WEOF; 1089c66bbc91SGabor Kovesdan if (symbol_positive_sign == sort_opts_vals.field_sep) 1090c66bbc91SGabor Kovesdan symbol_positive_sign = WEOF; 1091c66bbc91SGabor Kovesdan } 1092c66bbc91SGabor Kovesdan break; 1093c66bbc91SGabor Kovesdan case 'u': 1094c66bbc91SGabor Kovesdan sort_opts_vals.uflag = true; 1095c66bbc91SGabor Kovesdan /* stable sort for the correct unique val */ 1096c66bbc91SGabor Kovesdan sort_opts_vals.sflag = true; 1097c66bbc91SGabor Kovesdan break; 1098c66bbc91SGabor Kovesdan case 'z': 1099c66bbc91SGabor Kovesdan sort_opts_vals.zflag = true; 1100c66bbc91SGabor Kovesdan break; 1101c66bbc91SGabor Kovesdan case SORT_OPT: 1102c66bbc91SGabor Kovesdan if (optarg) { 1103c66bbc91SGabor Kovesdan if (!strcmp(optarg, "general-numeric")) 1104c66bbc91SGabor Kovesdan set_sort_modifier(sm, 'g'); 1105c66bbc91SGabor Kovesdan else if (!strcmp(optarg, "human-numeric")) 1106c66bbc91SGabor Kovesdan set_sort_modifier(sm, 'h'); 1107c66bbc91SGabor Kovesdan else if (!strcmp(optarg, "numeric")) 1108c66bbc91SGabor Kovesdan set_sort_modifier(sm, 'n'); 1109c66bbc91SGabor Kovesdan else if (!strcmp(optarg, "month")) 1110c66bbc91SGabor Kovesdan set_sort_modifier(sm, 'M'); 1111c66bbc91SGabor Kovesdan else if (!strcmp(optarg, "random")) 1112c66bbc91SGabor Kovesdan set_sort_modifier(sm, 'R'); 1113c66bbc91SGabor Kovesdan else 1114c66bbc91SGabor Kovesdan unknown(optarg); 1115c66bbc91SGabor Kovesdan } 1116c66bbc91SGabor Kovesdan break; 1117c66bbc91SGabor Kovesdan #if defined(SORT_THREADS) 11185d5151aeSGabor Kovesdan case PARALLEL_OPT: 1119c66bbc91SGabor Kovesdan nthreads = (size_t)(atoi(optarg)); 1120c66bbc91SGabor Kovesdan if (nthreads < 1) 1121c66bbc91SGabor Kovesdan nthreads = 1; 1122c66bbc91SGabor Kovesdan if (nthreads > 1024) 1123c66bbc91SGabor Kovesdan nthreads = 1024; 1124c66bbc91SGabor Kovesdan break; 1125c66bbc91SGabor Kovesdan #endif 1126c66bbc91SGabor Kovesdan case QSORT_OPT: 1127c66bbc91SGabor Kovesdan sort_opts_vals.sort_method = SORT_QSORT; 1128c66bbc91SGabor Kovesdan break; 1129c66bbc91SGabor Kovesdan case MERGESORT_OPT: 1130c66bbc91SGabor Kovesdan sort_opts_vals.sort_method = SORT_MERGESORT; 1131c66bbc91SGabor Kovesdan break; 11325ca724dcSGabor Kovesdan case MMAP_OPT: 11335ca724dcSGabor Kovesdan use_mmap = true; 11345ca724dcSGabor Kovesdan break; 1135c66bbc91SGabor Kovesdan case HEAPSORT_OPT: 1136c66bbc91SGabor Kovesdan sort_opts_vals.sort_method = SORT_HEAPSORT; 1137c66bbc91SGabor Kovesdan break; 1138c66bbc91SGabor Kovesdan case RADIXSORT_OPT: 1139c66bbc91SGabor Kovesdan sort_opts_vals.sort_method = SORT_RADIXSORT; 1140c66bbc91SGabor Kovesdan break; 1141c66bbc91SGabor Kovesdan case RANDOMSOURCE_OPT: 1142c66bbc91SGabor Kovesdan random_source = strdup(optarg); 1143c66bbc91SGabor Kovesdan break; 1144c66bbc91SGabor Kovesdan case COMPRESSPROGRAM_OPT: 1145c66bbc91SGabor Kovesdan compress_program = strdup(optarg); 1146c66bbc91SGabor Kovesdan break; 1147c66bbc91SGabor Kovesdan case FF_OPT: 1148c66bbc91SGabor Kovesdan read_fns_from_file0(optarg); 1149c66bbc91SGabor Kovesdan break; 1150c66bbc91SGabor Kovesdan case BS_OPT: 1151c66bbc91SGabor Kovesdan { 1152c66bbc91SGabor Kovesdan errno = 0; 1153c66bbc91SGabor Kovesdan long mof = strtol(optarg, NULL, 10); 1154c66bbc91SGabor Kovesdan if (errno != 0) 1155f187ff08SGabor Kovesdan err(2, "--batch-size"); 1156c66bbc91SGabor Kovesdan if (mof >= 2) 1157c66bbc91SGabor Kovesdan max_open_files = (size_t) mof + 1; 1158c66bbc91SGabor Kovesdan } 1159c66bbc91SGabor Kovesdan break; 1160c66bbc91SGabor Kovesdan case VERSION_OPT: 1161c66bbc91SGabor Kovesdan printf("%s\n", VERSION); 1162c66bbc91SGabor Kovesdan exit(EXIT_SUCCESS); 1163c66bbc91SGabor Kovesdan /* NOTREACHED */ 1164c66bbc91SGabor Kovesdan break; 1165c66bbc91SGabor Kovesdan case DEBUG_OPT: 1166c66bbc91SGabor Kovesdan debug_sort = true; 1167c66bbc91SGabor Kovesdan break; 1168c66bbc91SGabor Kovesdan case HELP_OPT: 1169c66bbc91SGabor Kovesdan usage(false); 1170c66bbc91SGabor Kovesdan /* NOTREACHED */ 1171c66bbc91SGabor Kovesdan break; 1172c66bbc91SGabor Kovesdan default: 1173c66bbc91SGabor Kovesdan usage(true); 1174c66bbc91SGabor Kovesdan /* NOTREACHED */ 1175c66bbc91SGabor Kovesdan } 1176c66bbc91SGabor Kovesdan } 1177c66bbc91SGabor Kovesdan } 1178c66bbc91SGabor Kovesdan 1179c66bbc91SGabor Kovesdan argc -= optind; 1180c66bbc91SGabor Kovesdan argv += optind; 1181c66bbc91SGabor Kovesdan 1182a7bc1892SGabor Kovesdan if (argv_from_file0) { 1183a7bc1892SGabor Kovesdan argc = argc_from_file0; 1184a7bc1892SGabor Kovesdan argv = argv_from_file0; 1185a7bc1892SGabor Kovesdan } 1186a7bc1892SGabor Kovesdan 1187c66bbc91SGabor Kovesdan #ifndef WITHOUT_NLS 1188c66bbc91SGabor Kovesdan catalog = catopen("sort", NL_CAT_LOCALE); 1189c66bbc91SGabor Kovesdan #endif 1190c66bbc91SGabor Kovesdan 1191c66bbc91SGabor Kovesdan if (sort_opts_vals.cflag && sort_opts_vals.mflag) 11928818aa39SGabor Kovesdan errx(1, "%c:%c: %s", 'm', 'c', getstr(1)); 1193c66bbc91SGabor Kovesdan 1194c66bbc91SGabor Kovesdan #ifndef WITHOUT_NLS 1195c66bbc91SGabor Kovesdan catclose(catalog); 1196c66bbc91SGabor Kovesdan #endif 1197c66bbc91SGabor Kovesdan 1198c66bbc91SGabor Kovesdan if (keys_num == 0) { 1199c66bbc91SGabor Kovesdan keys_num = 1; 1200c66bbc91SGabor Kovesdan keys = sort_realloc(keys, sizeof(struct key_specs)); 1201c66bbc91SGabor Kovesdan memset(&(keys[0]), 0, sizeof(struct key_specs)); 1202c66bbc91SGabor Kovesdan keys[0].c1 = 1; 1203c66bbc91SGabor Kovesdan keys[0].pos1b = default_sort_mods->bflag; 1204c66bbc91SGabor Kovesdan keys[0].pos2b = default_sort_mods->bflag; 1205c66bbc91SGabor Kovesdan memcpy(&(keys[0].sm), default_sort_mods, 1206c66bbc91SGabor Kovesdan sizeof(struct sort_mods)); 1207c66bbc91SGabor Kovesdan } 1208c66bbc91SGabor Kovesdan 1209c66bbc91SGabor Kovesdan for (size_t i = 0; i < keys_num; i++) { 1210c66bbc91SGabor Kovesdan struct key_specs *ks; 1211c66bbc91SGabor Kovesdan 1212c66bbc91SGabor Kovesdan ks = &(keys[i]); 1213c66bbc91SGabor Kovesdan 1214c66bbc91SGabor Kovesdan if (sort_modifier_empty(&(ks->sm)) && !(ks->pos1b) && 1215c66bbc91SGabor Kovesdan !(ks->pos2b)) { 1216c66bbc91SGabor Kovesdan ks->pos1b = sm->bflag; 1217c66bbc91SGabor Kovesdan ks->pos2b = sm->bflag; 1218c66bbc91SGabor Kovesdan memcpy(&(ks->sm), sm, sizeof(struct sort_mods)); 1219c66bbc91SGabor Kovesdan } 1220c66bbc91SGabor Kovesdan 1221c66bbc91SGabor Kovesdan ks->sm.func = get_sort_func(&(ks->sm)); 1222c66bbc91SGabor Kovesdan } 1223c66bbc91SGabor Kovesdan 1224c66bbc91SGabor Kovesdan if (debug_sort) { 122555444243SGabor Kovesdan printf("Memory to be used for sorting: %llu\n",available_free_memory); 1226c66bbc91SGabor Kovesdan #if defined(SORT_THREADS) 122755444243SGabor Kovesdan printf("Number of CPUs: %d\n",(int)ncpu); 1228c66bbc91SGabor Kovesdan nthreads = 1; 1229c66bbc91SGabor Kovesdan #endif 1230c66bbc91SGabor Kovesdan printf("Using collate rules of %s locale\n", 1231c66bbc91SGabor Kovesdan setlocale(LC_COLLATE, NULL)); 1232c66bbc91SGabor Kovesdan if (byte_sort) 1233c66bbc91SGabor Kovesdan printf("Byte sort is used\n"); 1234c66bbc91SGabor Kovesdan if (print_symbols_on_debug) { 1235c66bbc91SGabor Kovesdan printf("Decimal Point: <%lc>\n", symbol_decimal_point); 1236c66bbc91SGabor Kovesdan if (symbol_thousands_sep) 1237c66bbc91SGabor Kovesdan printf("Thousands separator: <%lc>\n", 1238c66bbc91SGabor Kovesdan symbol_thousands_sep); 1239c66bbc91SGabor Kovesdan printf("Positive sign: <%lc>\n", symbol_positive_sign); 1240c66bbc91SGabor Kovesdan printf("Negative sign: <%lc>\n", symbol_negative_sign); 1241c66bbc91SGabor Kovesdan } 1242c66bbc91SGabor Kovesdan } 1243c66bbc91SGabor Kovesdan 124474504eefSConrad Meyer if (need_random) 1245*7a590a37SConrad Meyer get_random_seed(random_source); 1246c66bbc91SGabor Kovesdan 1247c66bbc91SGabor Kovesdan /* Case when the outfile equals one of the input files: */ 1248c66bbc91SGabor Kovesdan if (strcmp(outfile, "-")) { 1249c66bbc91SGabor Kovesdan 1250c66bbc91SGabor Kovesdan for(int i = 0; i < argc; ++i) { 1251c66bbc91SGabor Kovesdan if (strcmp(argv[i], outfile) == 0) { 1252c66bbc91SGabor Kovesdan real_outfile = sort_strdup(outfile); 1253c66bbc91SGabor Kovesdan for(;;) { 1254c66bbc91SGabor Kovesdan char* tmp = sort_malloc(strlen(outfile) + 1255c66bbc91SGabor Kovesdan strlen(".tmp") + 1); 1256c66bbc91SGabor Kovesdan 1257c66bbc91SGabor Kovesdan strcpy(tmp, outfile); 1258c66bbc91SGabor Kovesdan strcpy(tmp + strlen(tmp), ".tmp"); 1259c66bbc91SGabor Kovesdan sort_free(outfile); 1260c66bbc91SGabor Kovesdan outfile = tmp; 1261c66bbc91SGabor Kovesdan if (access(outfile, F_OK) < 0) 1262c66bbc91SGabor Kovesdan break; 1263c66bbc91SGabor Kovesdan } 1264c66bbc91SGabor Kovesdan tmp_file_atexit(outfile); 1265c66bbc91SGabor Kovesdan } 1266c66bbc91SGabor Kovesdan } 1267c66bbc91SGabor Kovesdan } 1268c66bbc91SGabor Kovesdan 12695ca724dcSGabor Kovesdan #if defined(SORT_THREADS) 12705ca724dcSGabor Kovesdan if ((argc < 1) || (strcmp(outfile, "-") == 0) || (*outfile == 0)) 12715ca724dcSGabor Kovesdan nthreads = 1; 12725ca724dcSGabor Kovesdan #endif 12735ca724dcSGabor Kovesdan 1274c66bbc91SGabor Kovesdan if (!sort_opts_vals.cflag && !sort_opts_vals.mflag) { 1275c66bbc91SGabor Kovesdan struct file_list fl; 1276c66bbc91SGabor Kovesdan struct sort_list list; 1277c66bbc91SGabor Kovesdan 1278c66bbc91SGabor Kovesdan sort_list_init(&list); 1279c66bbc91SGabor Kovesdan file_list_init(&fl, true); 1280c66bbc91SGabor Kovesdan 1281c66bbc91SGabor Kovesdan if (argc < 1) 1282c66bbc91SGabor Kovesdan procfile("-", &list, &fl); 1283c66bbc91SGabor Kovesdan else { 1284c66bbc91SGabor Kovesdan while (argc > 0) { 1285c66bbc91SGabor Kovesdan procfile(*argv, &list, &fl); 1286c66bbc91SGabor Kovesdan --argc; 1287c66bbc91SGabor Kovesdan ++argv; 1288c66bbc91SGabor Kovesdan } 1289c66bbc91SGabor Kovesdan } 1290c66bbc91SGabor Kovesdan 1291c66bbc91SGabor Kovesdan if (fl.count < 1) 1292c66bbc91SGabor Kovesdan sort_list_to_file(&list, outfile); 1293c66bbc91SGabor Kovesdan else { 1294c66bbc91SGabor Kovesdan if (list.count > 0) { 1295c66bbc91SGabor Kovesdan char *flast = new_tmp_file_name(); 1296c66bbc91SGabor Kovesdan 1297c66bbc91SGabor Kovesdan sort_list_to_file(&list, flast); 1298c66bbc91SGabor Kovesdan file_list_add(&fl, flast, false); 1299c66bbc91SGabor Kovesdan } 1300c66bbc91SGabor Kovesdan merge_files(&fl, outfile); 1301c66bbc91SGabor Kovesdan } 1302c66bbc91SGabor Kovesdan 1303c66bbc91SGabor Kovesdan file_list_clean(&fl); 1304c66bbc91SGabor Kovesdan 1305c66bbc91SGabor Kovesdan /* 1306c66bbc91SGabor Kovesdan * We are about to exit the program, so we can ignore 1307c66bbc91SGabor Kovesdan * the clean-up for speed 1308c66bbc91SGabor Kovesdan * 1309c66bbc91SGabor Kovesdan * sort_list_clean(&list); 1310c66bbc91SGabor Kovesdan */ 1311c66bbc91SGabor Kovesdan 1312c66bbc91SGabor Kovesdan } else if (sort_opts_vals.cflag) { 1313c66bbc91SGabor Kovesdan result = (argc == 0) ? (check("-")) : (check(*argv)); 1314c66bbc91SGabor Kovesdan } else if (sort_opts_vals.mflag) { 1315c66bbc91SGabor Kovesdan struct file_list fl; 1316c66bbc91SGabor Kovesdan 1317c66bbc91SGabor Kovesdan file_list_init(&fl, false); 13187137597eSKyle Evans /* No file arguments remaining means "read from stdin." */ 13197137597eSKyle Evans if (argc == 0) 13207137597eSKyle Evans file_list_add(&fl, "-", true); 13217137597eSKyle Evans else 1322c66bbc91SGabor Kovesdan file_list_populate(&fl, argc, argv, true); 1323c66bbc91SGabor Kovesdan merge_files(&fl, outfile); 1324c66bbc91SGabor Kovesdan file_list_clean(&fl); 1325c66bbc91SGabor Kovesdan } 1326c66bbc91SGabor Kovesdan 1327c66bbc91SGabor Kovesdan if (real_outfile) { 1328c66bbc91SGabor Kovesdan unlink(real_outfile); 1329c66bbc91SGabor Kovesdan if (rename(outfile, real_outfile) < 0) 1330c66bbc91SGabor Kovesdan err(2, NULL); 1331c66bbc91SGabor Kovesdan sort_free(real_outfile); 1332c66bbc91SGabor Kovesdan } 1333c66bbc91SGabor Kovesdan 1334c66bbc91SGabor Kovesdan sort_free(outfile); 1335c66bbc91SGabor Kovesdan 1336c66bbc91SGabor Kovesdan return (result); 1337c66bbc91SGabor Kovesdan } 1338