1235267Sgabor/*- 2235267Sgabor * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org> 3251245Sgabor * Copyright (C) 2012 Oleg Moskalenko <mom040267@gmail.com> 4235267Sgabor * All rights reserved. 5235267Sgabor * 6235267Sgabor * Redistribution and use in source and binary forms, with or without 7235267Sgabor * modification, are permitted provided that the following conditions 8235267Sgabor * are met: 9235267Sgabor * 1. Redistributions of source code must retain the above copyright 10235267Sgabor * notice, this list of conditions and the following disclaimer. 11235267Sgabor * 2. Redistributions in binary form must reproduce the above copyright 12235267Sgabor * notice, this list of conditions and the following disclaimer in the 13235267Sgabor * documentation and/or other materials provided with the distribution. 14235267Sgabor * 15235267Sgabor * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16235267Sgabor * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17235267Sgabor * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18235267Sgabor * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19235267Sgabor * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20235267Sgabor * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21235267Sgabor * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22235267Sgabor * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23235267Sgabor * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24235267Sgabor * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25235267Sgabor * SUCH DAMAGE. 26235267Sgabor */ 27235267Sgabor 28235267Sgabor#include <sys/cdefs.h> 29235267Sgabor__FBSDID("$FreeBSD: stable/10/usr.bin/sort/sort.c 309862 2016-12-12 00:47:12Z delphij $"); 30235267Sgabor 31235267Sgabor#include <sys/stat.h> 32235267Sgabor#include <sys/sysctl.h> 33235267Sgabor#include <sys/types.h> 34235267Sgabor 35235267Sgabor#include <err.h> 36235267Sgabor#include <errno.h> 37235267Sgabor#include <getopt.h> 38235267Sgabor#include <limits.h> 39235267Sgabor#include <locale.h> 40235267Sgabor#include <md5.h> 41235267Sgabor#include <regex.h> 42235267Sgabor#include <signal.h> 43235267Sgabor#include <stdbool.h> 44235267Sgabor#include <stdio.h> 45235267Sgabor#include <stdlib.h> 46235267Sgabor#include <string.h> 47235267Sgabor#include <unistd.h> 48235267Sgabor#include <wchar.h> 49235267Sgabor#include <wctype.h> 50235267Sgabor 51235267Sgabor#include "coll.h" 52235267Sgabor#include "file.h" 53235267Sgabor#include "sort.h" 54235267Sgabor 55235267Sgabor#ifndef WITHOUT_NLS 56235267Sgabor#include <nl_types.h> 57235267Sgabornl_catd catalog; 58235267Sgabor#endif 59235267Sgabor 60235267Sgabor#define OPTIONS "bcCdfghik:Mmno:RrsS:t:T:uVz" 61235267Sgabor 62235267Sgabor#define DEFAULT_RANDOM_SORT_SEED_FILE ("/dev/random") 63235267Sgabor#define MAX_DEFAULT_RANDOM_SEED_DATA_SIZE (1024) 64235267Sgabor 65235435Sgaborstatic bool need_random; 66235435Sgaborstatic const char *random_source = DEFAULT_RANDOM_SORT_SEED_FILE; 67235435Sgaborstatic const void *random_seed; 68235435Sgaborstatic size_t random_seed_size; 69235267Sgabor 70235267SgaborMD5_CTX md5_ctx; 71235267Sgabor 72235267Sgabor/* 73235267Sgabor * Default messages to use when NLS is disabled or no catalogue 74235267Sgabor * is found. 75235267Sgabor */ 76235267Sgaborconst char *nlsstr[] = { "", 77235432Sgabor/* 1*/"mutually exclusive flags", 78235267Sgabor/* 2*/"extra argument not allowed with -c", 79235432Sgabor/* 3*/"Unknown feature", 80235267Sgabor/* 4*/"Wrong memory buffer specification", 81235267Sgabor/* 5*/"0 field in key specs", 82235267Sgabor/* 6*/"0 column in key specs", 83235267Sgabor/* 7*/"Wrong file mode", 84235267Sgabor/* 8*/"Cannot open file for reading", 85235267Sgabor/* 9*/"Radix sort cannot be used with these sort options", 86235267Sgabor/*10*/"The chosen sort method cannot be used with stable and/or unique sort", 87235267Sgabor/*11*/"Invalid key position", 88235267Sgabor/*12*/"Usage: %s [-bcCdfigMmnrsuz] [-kPOS1[,POS2] ... ] " 89235267Sgabor "[+POS1 [-POS2]] [-S memsize] [-T tmpdir] [-t separator] " 90235267Sgabor "[-o outfile] [--batch-size size] [--files0-from file] " 91235267Sgabor "[--heapsort] [--mergesort] [--radixsort] [--qsort] " 92235987Sgabor "[--mmap] " 93235267Sgabor#if defined(SORT_THREADS) 94238108Sgabor "[--parallel thread_no] " 95235267Sgabor#endif 96235267Sgabor "[--human-numeric-sort] " 97235267Sgabor "[--version-sort] [--random-sort [--random-source file]] " 98235267Sgabor "[--compress-program program] [file ...]\n" }; 99235267Sgabor 100235267Sgaborstruct sort_opts sort_opts_vals; 101235267Sgabor 102235435Sgaborbool debug_sort; 103235435Sgaborbool need_hint; 104235267Sgabor 105235267Sgabor#if defined(SORT_THREADS) 106244346Sgaborunsigned int ncpu = 1; 107235267Sgaborsize_t nthreads = 1; 108235267Sgabor#endif 109235267Sgabor 110235435Sgaborstatic bool gnusort_numeric_compatibility; 111235267Sgabor 112235267Sgaborstatic struct sort_mods default_sort_mods_object; 113235267Sgaborstruct sort_mods * const default_sort_mods = &default_sort_mods_object; 114235267Sgabor 115235435Sgaborstatic bool print_symbols_on_debug; 116235267Sgabor 117235267Sgabor/* 118235267Sgabor * Arguments from file (when file0-from option is used: 119235267Sgabor */ 120242430Sgaborstatic size_t argc_from_file0 = (size_t)-1; 121235435Sgaborstatic char **argv_from_file0; 122235267Sgabor 123235267Sgabor/* 124235267Sgabor * Placeholder symbols for options which have no single-character equivalent 125235267Sgabor */ 126235267Sgaborenum 127235267Sgabor{ 128235267Sgabor SORT_OPT = CHAR_MAX + 1, 129235267Sgabor HELP_OPT, 130235267Sgabor FF_OPT, 131235267Sgabor BS_OPT, 132235267Sgabor VERSION_OPT, 133235267Sgabor DEBUG_OPT, 134235267Sgabor#if defined(SORT_THREADS) 135238108Sgabor PARALLEL_OPT, 136235267Sgabor#endif 137235267Sgabor RANDOMSOURCE_OPT, 138235267Sgabor COMPRESSPROGRAM_OPT, 139235267Sgabor QSORT_OPT, 140235267Sgabor MERGESORT_OPT, 141235267Sgabor HEAPSORT_OPT, 142235987Sgabor RADIXSORT_OPT, 143235987Sgabor MMAP_OPT 144235267Sgabor}; 145235267Sgabor 146235267Sgabor#define NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS 6 147235267Sgaborstatic const char mutually_exclusive_flags[NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS] = { 'M', 'n', 'g', 'R', 'h', 'V' }; 148235267Sgabor 149241737Sedstatic struct option long_options[] = { 150235267Sgabor { "batch-size", required_argument, NULL, BS_OPT }, 151235267Sgabor { "buffer-size", required_argument, NULL, 'S' }, 152235267Sgabor { "check", optional_argument, NULL, 'c' }, 153235267Sgabor { "check=silent|quiet", optional_argument, NULL, 'C' }, 154235267Sgabor { "compress-program", required_argument, NULL, COMPRESSPROGRAM_OPT }, 155235267Sgabor { "debug", no_argument, NULL, DEBUG_OPT }, 156235267Sgabor { "dictionary-order", no_argument, NULL, 'd' }, 157235267Sgabor { "field-separator", required_argument, NULL, 't' }, 158235267Sgabor { "files0-from", required_argument, NULL, FF_OPT }, 159235267Sgabor { "general-numeric-sort", no_argument, NULL, 'g' }, 160235267Sgabor { "heapsort", no_argument, NULL, HEAPSORT_OPT }, 161235267Sgabor { "help",no_argument, NULL, HELP_OPT }, 162235267Sgabor { "human-numeric-sort", no_argument, NULL, 'h' }, 163235267Sgabor { "ignore-leading-blanks", no_argument, NULL, 'b' }, 164235267Sgabor { "ignore-case", no_argument, NULL, 'f' }, 165235267Sgabor { "ignore-nonprinting", no_argument, NULL, 'i' }, 166235267Sgabor { "key", required_argument, NULL, 'k' }, 167235267Sgabor { "merge", no_argument, NULL, 'm' }, 168235267Sgabor { "mergesort", no_argument, NULL, MERGESORT_OPT }, 169235987Sgabor { "mmap", no_argument, NULL, MMAP_OPT }, 170235267Sgabor { "month-sort", no_argument, NULL, 'M' }, 171235267Sgabor { "numeric-sort", no_argument, NULL, 'n' }, 172235267Sgabor { "output", required_argument, NULL, 'o' }, 173235267Sgabor#if defined(SORT_THREADS) 174238108Sgabor { "parallel", required_argument, NULL, PARALLEL_OPT }, 175235267Sgabor#endif 176235267Sgabor { "qsort", no_argument, NULL, QSORT_OPT }, 177235267Sgabor { "radixsort", no_argument, NULL, RADIXSORT_OPT }, 178235267Sgabor { "random-sort", no_argument, NULL, 'R' }, 179235267Sgabor { "random-source", required_argument, NULL, RANDOMSOURCE_OPT }, 180235267Sgabor { "reverse", no_argument, NULL, 'r' }, 181235267Sgabor { "sort", required_argument, NULL, SORT_OPT }, 182235267Sgabor { "stable", no_argument, NULL, 's' }, 183235267Sgabor { "temporary-directory",required_argument, NULL, 'T' }, 184235267Sgabor { "unique", no_argument, NULL, 'u' }, 185235267Sgabor { "version", no_argument, NULL, VERSION_OPT }, 186235267Sgabor { "version-sort",no_argument, NULL, 'V' }, 187235267Sgabor { "zero-terminated", no_argument, NULL, 'z' }, 188235267Sgabor { NULL, no_argument, NULL, 0 } 189235267Sgabor}; 190235267Sgabor 191235267Sgaborvoid fix_obsolete_keys(int *argc, char **argv); 192235267Sgabor 193235267Sgabor/* 194235267Sgabor * Check where sort modifier is present 195235267Sgabor */ 196235267Sgaborstatic bool 197235267Sgaborsort_modifier_empty(struct sort_mods *sm) 198235267Sgabor{ 199235267Sgabor 200235267Sgabor if (sm == NULL) 201235267Sgabor return (true); 202235267Sgabor return (!(sm->Mflag || sm->Vflag || sm->nflag || sm->gflag || 203235267Sgabor sm->rflag || sm->Rflag || sm->hflag || sm->dflag || sm->fflag)); 204235267Sgabor} 205235267Sgabor 206235267Sgabor/* 207235267Sgabor * Print out usage text. 208235267Sgabor */ 209235267Sgaborstatic void 210235267Sgaborusage(bool opt_err) 211235267Sgabor{ 212235267Sgabor FILE *out; 213235267Sgabor 214309862Sdelphij out = opt_err ? stderr : stdout; 215235267Sgabor 216235267Sgabor fprintf(out, getstr(12), getprogname()); 217235267Sgabor if (opt_err) 218235267Sgabor exit(2); 219235267Sgabor exit(0); 220235267Sgabor} 221235267Sgabor 222235267Sgabor/* 223235267Sgabor * Read input file names from a file (file0-from option). 224235267Sgabor */ 225235267Sgaborstatic void 226235267Sgaborread_fns_from_file0(const char *fn) 227235267Sgabor{ 228281535Spfg FILE *f; 229281535Spfg char *line = NULL; 230281535Spfg size_t linesize = 0; 231281535Spfg ssize_t linelen; 232235267Sgabor 233281535Spfg if (fn == NULL) 234281535Spfg return; 235235267Sgabor 236281535Spfg f = fopen(fn, "r"); 237281535Spfg if (f == NULL) 238281535Spfg err(2, "%s", fn); 239235267Sgabor 240281535Spfg while ((linelen = getdelim(&line, &linesize, '\0', f)) != -1) { 241281535Spfg if (*line != '\0') { 242281535Spfg if (argc_from_file0 == (size_t) - 1) 243281535Spfg argc_from_file0 = 0; 244281535Spfg ++argc_from_file0; 245281535Spfg argv_from_file0 = sort_realloc(argv_from_file0, 246281535Spfg argc_from_file0 * sizeof(char *)); 247281535Spfg if (argv_from_file0 == NULL) 248281535Spfg err(2, NULL); 249281535Spfg argv_from_file0[argc_from_file0 - 1] = line; 250281535Spfg } else { 251281535Spfg free(line); 252235267Sgabor } 253281535Spfg line = NULL; 254281535Spfg linesize = 0; 255235267Sgabor } 256281535Spfg if (ferror(f)) 257281535Spfg err(2, "%s: getdelim", fn); 258281535Spfg 259281535Spfg closefile(f, fn); 260235267Sgabor} 261235267Sgabor 262235267Sgabor/* 263235267Sgabor * Check how much RAM is available for the sort. 264235267Sgabor */ 265235267Sgaborstatic void 266235267Sgaborset_hw_params(void) 267235267Sgabor{ 268244515Sgabor long pages, psize; 269235267Sgabor 270235267Sgabor#if defined(SORT_THREADS) 271235267Sgabor ncpu = 1; 272235267Sgabor#endif 273235267Sgabor 274244515Sgabor pages = sysconf(_SC_PHYS_PAGES); 275244515Sgabor if (pages < 1) { 276244515Sgabor perror("sysconf pages"); 277309862Sdelphij pages = 1; 278235267Sgabor } 279244515Sgabor psize = sysconf(_SC_PAGESIZE); 280244515Sgabor if (psize < 1) { 281244515Sgabor perror("sysconf psize"); 282244515Sgabor psize = 4096; 283235267Sgabor } 284235267Sgabor#if defined(SORT_THREADS) 285244515Sgabor ncpu = (unsigned int)sysconf(_SC_NPROCESSORS_ONLN); 286244515Sgabor if (ncpu < 1) 287235267Sgabor ncpu = 1; 288235267Sgabor else if(ncpu > 32) 289235267Sgabor ncpu = 32; 290235267Sgabor 291235267Sgabor nthreads = ncpu; 292235267Sgabor#endif 293235267Sgabor 294235267Sgabor free_memory = (unsigned long long) pages * (unsigned long long) psize; 295244515Sgabor available_free_memory = free_memory / 2; 296244346Sgabor 297244346Sgabor if (available_free_memory < 1024) 298244346Sgabor available_free_memory = 1024; 299235267Sgabor} 300235267Sgabor 301235267Sgabor/* 302235267Sgabor * Convert "plain" symbol to wide symbol, with default value. 303235267Sgabor */ 304235267Sgaborstatic void 305235267Sgaborconv_mbtowc(wchar_t *wc, const char *c, const wchar_t def) 306235267Sgabor{ 307235267Sgabor 308235267Sgabor if (wc && c) { 309235267Sgabor int res; 310235267Sgabor 311235267Sgabor res = mbtowc(wc, c, MB_CUR_MAX); 312235267Sgabor if (res < 1) 313235267Sgabor *wc = def; 314235267Sgabor } 315235267Sgabor} 316235267Sgabor 317235267Sgabor/* 318235267Sgabor * Set current locale symbols. 319235267Sgabor */ 320235267Sgaborstatic void 321235267Sgaborset_locale(void) 322235267Sgabor{ 323235267Sgabor struct lconv *lc; 324235267Sgabor const char *locale; 325235267Sgabor 326235267Sgabor setlocale(LC_ALL, ""); 327235267Sgabor 328235267Sgabor lc = localeconv(); 329235267Sgabor 330235267Sgabor if (lc) { 331235267Sgabor /* obtain LC_NUMERIC info */ 332235267Sgabor /* Convert to wide char form */ 333235267Sgabor conv_mbtowc(&symbol_decimal_point, lc->decimal_point, 334235267Sgabor symbol_decimal_point); 335235267Sgabor conv_mbtowc(&symbol_thousands_sep, lc->thousands_sep, 336235267Sgabor symbol_thousands_sep); 337235267Sgabor conv_mbtowc(&symbol_positive_sign, lc->positive_sign, 338235267Sgabor symbol_positive_sign); 339235267Sgabor conv_mbtowc(&symbol_negative_sign, lc->negative_sign, 340235267Sgabor symbol_negative_sign); 341235267Sgabor } 342235267Sgabor 343235267Sgabor if (getenv("GNUSORT_NUMERIC_COMPATIBILITY")) 344235267Sgabor gnusort_numeric_compatibility = true; 345235267Sgabor 346235267Sgabor locale = setlocale(LC_COLLATE, NULL); 347235267Sgabor 348235267Sgabor if (locale) { 349235267Sgabor char *tmpl; 350235267Sgabor const char *cclocale; 351235267Sgabor 352235267Sgabor tmpl = sort_strdup(locale); 353235267Sgabor cclocale = setlocale(LC_COLLATE, "C"); 354235267Sgabor if (cclocale && !strcmp(cclocale, tmpl)) 355235267Sgabor byte_sort = true; 356235267Sgabor else { 357235267Sgabor const char *pclocale; 358235267Sgabor 359235267Sgabor pclocale = setlocale(LC_COLLATE, "POSIX"); 360235267Sgabor if (pclocale && !strcmp(pclocale, tmpl)) 361235267Sgabor byte_sort = true; 362235267Sgabor } 363235267Sgabor setlocale(LC_COLLATE, tmpl); 364235267Sgabor sort_free(tmpl); 365235267Sgabor } 366235267Sgabor} 367235267Sgabor 368235267Sgabor/* 369235267Sgabor * Set directory temporary files. 370235267Sgabor */ 371235267Sgaborstatic void 372235267Sgaborset_tmpdir(void) 373235267Sgabor{ 374235267Sgabor char *td; 375235267Sgabor 376235267Sgabor td = getenv("TMPDIR"); 377235267Sgabor if (td != NULL) 378235267Sgabor tmpdir = sort_strdup(td); 379235267Sgabor} 380235267Sgabor 381235267Sgabor/* 382235267Sgabor * Parse -S option. 383235267Sgabor */ 384235267Sgaborstatic unsigned long long 385235267Sgaborparse_memory_buffer_value(const char *value) 386235267Sgabor{ 387235267Sgabor 388235267Sgabor if (value == NULL) 389235267Sgabor return (available_free_memory); 390235267Sgabor else { 391235267Sgabor char *endptr; 392235267Sgabor unsigned long long membuf; 393235267Sgabor 394235267Sgabor endptr = NULL; 395235267Sgabor errno = 0; 396235267Sgabor membuf = strtoll(value, &endptr, 10); 397235267Sgabor 398235267Sgabor if (errno != 0) { 399235432Sgabor warn("%s",getstr(4)); 400235267Sgabor membuf = available_free_memory; 401235267Sgabor } else { 402235267Sgabor switch (*endptr){ 403235267Sgabor case 'Y': 404235267Sgabor membuf *= 1024; 405235267Sgabor /* FALLTHROUGH */ 406235267Sgabor case 'Z': 407235267Sgabor membuf *= 1024; 408235267Sgabor /* FALLTHROUGH */ 409235267Sgabor case 'E': 410235267Sgabor membuf *= 1024; 411235267Sgabor /* FALLTHROUGH */ 412235267Sgabor case 'P': 413235267Sgabor membuf *= 1024; 414235267Sgabor /* FALLTHROUGH */ 415235267Sgabor case 'T': 416235267Sgabor membuf *= 1024; 417235267Sgabor /* FALLTHROUGH */ 418235267Sgabor case 'G': 419235267Sgabor membuf *= 1024; 420235267Sgabor /* FALLTHROUGH */ 421235267Sgabor case 'M': 422235267Sgabor membuf *= 1024; 423235267Sgabor /* FALLTHROUGH */ 424235267Sgabor case '\0': 425235267Sgabor case 'K': 426235267Sgabor membuf *= 1024; 427235267Sgabor /* FALLTHROUGH */ 428235267Sgabor case 'b': 429235267Sgabor break; 430235267Sgabor case '%': 431235267Sgabor membuf = (available_free_memory * membuf) / 432235267Sgabor 100; 433235267Sgabor break; 434235267Sgabor default: 435245997Sgabor warnc(EINVAL, "%s", optarg); 436235267Sgabor membuf = available_free_memory; 437235267Sgabor } 438235267Sgabor } 439235267Sgabor return (membuf); 440235267Sgabor } 441235267Sgabor} 442235267Sgabor 443235267Sgabor/* 444235267Sgabor * Signal handler that clears the temporary files. 445235267Sgabor */ 446235267Sgaborstatic void 447235432Sgaborsig_handler(int sig __unused, siginfo_t *siginfo __unused, 448235432Sgabor void *context __unused) 449235267Sgabor{ 450235267Sgabor 451235267Sgabor clear_tmp_files(); 452235267Sgabor exit(-1); 453235267Sgabor} 454235267Sgabor 455235267Sgabor/* 456235267Sgabor * Set signal handler on panic signals. 457235267Sgabor */ 458235267Sgaborstatic void 459235267Sgaborset_signal_handler(void) 460235267Sgabor{ 461235267Sgabor struct sigaction sa; 462235267Sgabor 463235267Sgabor memset(&sa, 0, sizeof(sa)); 464235267Sgabor sa.sa_sigaction = &sig_handler; 465235267Sgabor sa.sa_flags = SA_SIGINFO; 466235267Sgabor 467235267Sgabor if (sigaction(SIGTERM, &sa, NULL) < 0) { 468235267Sgabor perror("sigaction"); 469235267Sgabor return; 470235267Sgabor } 471235267Sgabor if (sigaction(SIGHUP, &sa, NULL) < 0) { 472235267Sgabor perror("sigaction"); 473235267Sgabor return; 474235267Sgabor } 475235267Sgabor if (sigaction(SIGINT, &sa, NULL) < 0) { 476235267Sgabor perror("sigaction"); 477235267Sgabor return; 478235267Sgabor } 479235267Sgabor if (sigaction(SIGQUIT, &sa, NULL) < 0) { 480235267Sgabor perror("sigaction"); 481235267Sgabor return; 482235267Sgabor } 483235267Sgabor if (sigaction(SIGABRT, &sa, NULL) < 0) { 484235267Sgabor perror("sigaction"); 485235267Sgabor return; 486235267Sgabor } 487235267Sgabor if (sigaction(SIGBUS, &sa, NULL) < 0) { 488235267Sgabor perror("sigaction"); 489235267Sgabor return; 490235267Sgabor } 491235267Sgabor if (sigaction(SIGSEGV, &sa, NULL) < 0) { 492235267Sgabor perror("sigaction"); 493235267Sgabor return; 494235267Sgabor } 495235267Sgabor if (sigaction(SIGUSR1, &sa, NULL) < 0) { 496235267Sgabor perror("sigaction"); 497235267Sgabor return; 498235267Sgabor } 499235267Sgabor if (sigaction(SIGUSR2, &sa, NULL) < 0) { 500235267Sgabor perror("sigaction"); 501235267Sgabor return; 502235267Sgabor } 503235267Sgabor} 504235267Sgabor 505235267Sgabor/* 506235267Sgabor * Print "unknown" message and exit with status 2. 507235267Sgabor */ 508235267Sgaborstatic void 509235267Sgaborunknown(const char *what) 510235267Sgabor{ 511235267Sgabor 512235432Sgabor errx(2, "%s: %s", getstr(3), what); 513235267Sgabor} 514235267Sgabor 515235267Sgabor/* 516235267Sgabor * Check whether contradictory input options are used. 517235267Sgabor */ 518235267Sgaborstatic void 519235267Sgaborcheck_mutually_exclusive_flags(char c, bool *mef_flags) 520235267Sgabor{ 521235267Sgabor int fo_index, mec; 522235267Sgabor bool found_others, found_this; 523235267Sgabor 524235267Sgabor found_others = found_this =false; 525235267Sgabor fo_index = 0; 526235267Sgabor 527235267Sgabor for (int i = 0; i < NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS; i++) { 528235267Sgabor mec = mutually_exclusive_flags[i]; 529235267Sgabor 530235267Sgabor if (mec != c) { 531235267Sgabor if (mef_flags[i]) { 532235267Sgabor if (found_this) 533235432Sgabor errx(1, "%c:%c: %s", c, mec, getstr(1)); 534235267Sgabor found_others = true; 535235267Sgabor fo_index = i; 536235267Sgabor } 537235267Sgabor } else { 538235267Sgabor if (found_others) 539235432Sgabor errx(1, "%c:%c: %s", c, mutually_exclusive_flags[fo_index], getstr(1)); 540235267Sgabor mef_flags[i] = true; 541235267Sgabor found_this = true; 542235267Sgabor } 543235267Sgabor } 544235267Sgabor} 545235267Sgabor 546235267Sgabor/* 547235267Sgabor * Initialise sort opts data. 548235267Sgabor */ 549235267Sgaborstatic void 550235267Sgaborset_sort_opts(void) 551235267Sgabor{ 552235267Sgabor 553235267Sgabor memset(&default_sort_mods_object, 0, 554235267Sgabor sizeof(default_sort_mods_object)); 555235267Sgabor memset(&sort_opts_vals, 0, sizeof(sort_opts_vals)); 556235267Sgabor default_sort_mods_object.func = 557235267Sgabor get_sort_func(&default_sort_mods_object); 558235267Sgabor} 559235267Sgabor 560235267Sgabor/* 561235267Sgabor * Set a sort modifier on a sort modifiers object. 562235267Sgabor */ 563235267Sgaborstatic bool 564235267Sgaborset_sort_modifier(struct sort_mods *sm, int c) 565235267Sgabor{ 566235267Sgabor 567235267Sgabor if (sm) { 568235267Sgabor switch (c){ 569235267Sgabor case 'b': 570235267Sgabor sm->bflag = true; 571235267Sgabor break; 572235267Sgabor case 'd': 573235267Sgabor sm->dflag = true; 574235267Sgabor break; 575235267Sgabor case 'f': 576235267Sgabor sm->fflag = true; 577235267Sgabor break; 578235267Sgabor case 'g': 579235267Sgabor sm->gflag = true; 580235267Sgabor need_hint = true; 581235267Sgabor break; 582235267Sgabor case 'i': 583235267Sgabor sm->iflag = true; 584235267Sgabor break; 585235267Sgabor case 'R': 586235267Sgabor sm->Rflag = true; 587235267Sgabor need_random = true; 588235267Sgabor break; 589235267Sgabor case 'M': 590235267Sgabor initialise_months(); 591235267Sgabor sm->Mflag = true; 592235267Sgabor need_hint = true; 593235267Sgabor break; 594235267Sgabor case 'n': 595235267Sgabor sm->nflag = true; 596235267Sgabor need_hint = true; 597235267Sgabor print_symbols_on_debug = true; 598235267Sgabor break; 599235267Sgabor case 'r': 600235267Sgabor sm->rflag = true; 601235267Sgabor break; 602235267Sgabor case 'V': 603235267Sgabor sm->Vflag = true; 604235267Sgabor break; 605235267Sgabor case 'h': 606235267Sgabor sm->hflag = true; 607235267Sgabor need_hint = true; 608235267Sgabor print_symbols_on_debug = true; 609235267Sgabor break; 610235267Sgabor default: 611235267Sgabor return false; 612235267Sgabor } 613235267Sgabor sort_opts_vals.complex_sort = true; 614235267Sgabor sm->func = get_sort_func(sm); 615235267Sgabor } 616235267Sgabor return (true); 617235267Sgabor} 618235267Sgabor 619235267Sgabor/* 620235267Sgabor * Parse POS in -k option. 621235267Sgabor */ 622235267Sgaborstatic int 623235267Sgaborparse_pos(const char *s, struct key_specs *ks, bool *mef_flags, bool second) 624235267Sgabor{ 625235267Sgabor regmatch_t pmatch[4]; 626235267Sgabor regex_t re; 627235267Sgabor char *c, *f; 628235267Sgabor const char *sregexp = "^([0-9]+)(\\.[0-9]+)?([bdfirMngRhV]+)?$"; 629235267Sgabor size_t len, nmatch; 630235267Sgabor int ret; 631235267Sgabor 632235267Sgabor ret = -1; 633235267Sgabor nmatch = 4; 634235267Sgabor c = f = NULL; 635235267Sgabor 636235267Sgabor if (regcomp(&re, sregexp, REG_EXTENDED) != 0) 637235267Sgabor return (-1); 638235267Sgabor 639235267Sgabor if (regexec(&re, s, nmatch, pmatch, 0) != 0) 640235267Sgabor goto end; 641235267Sgabor 642235267Sgabor if (pmatch[0].rm_eo <= pmatch[0].rm_so) 643235267Sgabor goto end; 644235267Sgabor 645235267Sgabor if (pmatch[1].rm_eo <= pmatch[1].rm_so) 646235267Sgabor goto end; 647235267Sgabor 648235267Sgabor len = pmatch[1].rm_eo - pmatch[1].rm_so; 649235267Sgabor f = sort_malloc((len + 1) * sizeof(char)); 650235267Sgabor 651235267Sgabor strncpy(f, s + pmatch[1].rm_so, len); 652235267Sgabor f[len] = '\0'; 653235267Sgabor 654235267Sgabor if (second) { 655235267Sgabor errno = 0; 656235267Sgabor ks->f2 = (size_t) strtoul(f, NULL, 10); 657235267Sgabor if (errno != 0) 658245997Sgabor err(2, "-k"); 659235267Sgabor if (ks->f2 == 0) { 660235432Sgabor warn("%s",getstr(5)); 661235267Sgabor goto end; 662235267Sgabor } 663235267Sgabor } else { 664235267Sgabor errno = 0; 665235267Sgabor ks->f1 = (size_t) strtoul(f, NULL, 10); 666235267Sgabor if (errno != 0) 667245997Sgabor err(2, "-k"); 668235267Sgabor if (ks->f1 == 0) { 669235432Sgabor warn("%s",getstr(5)); 670235267Sgabor goto end; 671235267Sgabor } 672235267Sgabor } 673235267Sgabor 674235267Sgabor if (pmatch[2].rm_eo > pmatch[2].rm_so) { 675235267Sgabor len = pmatch[2].rm_eo - pmatch[2].rm_so - 1; 676235267Sgabor c = sort_malloc((len + 1) * sizeof(char)); 677235267Sgabor 678235267Sgabor strncpy(c, s + pmatch[2].rm_so + 1, len); 679235267Sgabor c[len] = '\0'; 680235267Sgabor 681235267Sgabor if (second) { 682235267Sgabor errno = 0; 683235267Sgabor ks->c2 = (size_t) strtoul(c, NULL, 10); 684235267Sgabor if (errno != 0) 685245997Sgabor err(2, "-k"); 686235267Sgabor } else { 687235267Sgabor errno = 0; 688235267Sgabor ks->c1 = (size_t) strtoul(c, NULL, 10); 689235267Sgabor if (errno != 0) 690245997Sgabor err(2, "-k"); 691235267Sgabor if (ks->c1 == 0) { 692235432Sgabor warn("%s",getstr(6)); 693235267Sgabor goto end; 694235267Sgabor } 695235267Sgabor } 696235267Sgabor } else { 697235267Sgabor if (second) 698235267Sgabor ks->c2 = 0; 699235267Sgabor else 700235267Sgabor ks->c1 = 1; 701235267Sgabor } 702235267Sgabor 703235267Sgabor if (pmatch[3].rm_eo > pmatch[3].rm_so) { 704235267Sgabor regoff_t i = 0; 705235267Sgabor 706235267Sgabor for (i = pmatch[3].rm_so; i < pmatch[3].rm_eo; i++) { 707235267Sgabor check_mutually_exclusive_flags(s[i], mef_flags); 708235267Sgabor if (s[i] == 'b') { 709235267Sgabor if (second) 710235267Sgabor ks->pos2b = true; 711235267Sgabor else 712235267Sgabor ks->pos1b = true; 713235267Sgabor } else if (!set_sort_modifier(&(ks->sm), s[i])) 714235267Sgabor goto end; 715235267Sgabor } 716235267Sgabor } 717235267Sgabor 718235267Sgabor ret = 0; 719235267Sgabor 720235267Sgaborend: 721235267Sgabor 722235267Sgabor if (c) 723235267Sgabor sort_free(c); 724235267Sgabor if (f) 725235267Sgabor sort_free(f); 726235267Sgabor regfree(&re); 727235267Sgabor 728235267Sgabor return (ret); 729235267Sgabor} 730235267Sgabor 731235267Sgabor/* 732235267Sgabor * Parse -k option value. 733235267Sgabor */ 734235267Sgaborstatic int 735235267Sgaborparse_k(const char *s, struct key_specs *ks) 736235267Sgabor{ 737235267Sgabor int ret = -1; 738235267Sgabor bool mef_flags[NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS] = 739235267Sgabor { false, false, false, false, false, false }; 740235267Sgabor 741235267Sgabor if (s && *s) { 742235267Sgabor char *sptr; 743235267Sgabor 744235267Sgabor sptr = strchr(s, ','); 745235267Sgabor if (sptr) { 746235267Sgabor size_t size1; 747235267Sgabor char *pos1, *pos2; 748235267Sgabor 749235267Sgabor size1 = sptr - s; 750235267Sgabor 751235267Sgabor if (size1 < 1) 752235267Sgabor return (-1); 753235267Sgabor pos1 = sort_malloc((size1 + 1) * sizeof(char)); 754235267Sgabor 755235267Sgabor strncpy(pos1, s, size1); 756235267Sgabor pos1[size1] = '\0'; 757235267Sgabor 758235267Sgabor ret = parse_pos(pos1, ks, mef_flags, false); 759235267Sgabor 760235267Sgabor sort_free(pos1); 761235267Sgabor if (ret < 0) 762235267Sgabor return (ret); 763235267Sgabor 764235267Sgabor pos2 = sort_strdup(sptr + 1); 765235267Sgabor ret = parse_pos(pos2, ks, mef_flags, true); 766235267Sgabor sort_free(pos2); 767235267Sgabor } else 768235267Sgabor ret = parse_pos(s, ks, mef_flags, false); 769235267Sgabor } 770235267Sgabor 771235267Sgabor return (ret); 772235267Sgabor} 773235267Sgabor 774235267Sgabor/* 775235267Sgabor * Parse POS in +POS -POS option. 776235267Sgabor */ 777235267Sgaborstatic int 778235267Sgaborparse_pos_obs(const char *s, int *nf, int *nc, char* sopts) 779235267Sgabor{ 780235267Sgabor regex_t re; 781235267Sgabor regmatch_t pmatch[4]; 782235267Sgabor char *c, *f; 783235267Sgabor const char *sregexp = "^([0-9]+)(\\.[0-9]+)?([A-Za-z]+)?$"; 784235267Sgabor int ret; 785235267Sgabor size_t len, nmatch; 786235267Sgabor 787235267Sgabor ret = -1; 788235267Sgabor nmatch = 4; 789235267Sgabor c = f = NULL; 790235267Sgabor *nc = *nf = 0; 791235267Sgabor 792235267Sgabor if (regcomp(&re, sregexp, REG_EXTENDED) != 0) 793235267Sgabor return (-1); 794235267Sgabor 795235267Sgabor if (regexec(&re, s, nmatch, pmatch, 0) != 0) 796235267Sgabor goto end; 797235267Sgabor 798235267Sgabor if (pmatch[0].rm_eo <= pmatch[0].rm_so) 799235267Sgabor goto end; 800235267Sgabor 801235267Sgabor if (pmatch[1].rm_eo <= pmatch[1].rm_so) 802235267Sgabor goto end; 803235267Sgabor 804235267Sgabor len = pmatch[1].rm_eo - pmatch[1].rm_so; 805235267Sgabor f = sort_malloc((len + 1) * sizeof(char)); 806235267Sgabor 807235267Sgabor strncpy(f, s + pmatch[1].rm_so, len); 808235267Sgabor f[len] = '\0'; 809235267Sgabor 810235267Sgabor errno = 0; 811235267Sgabor *nf = (size_t) strtoul(f, NULL, 10); 812235267Sgabor if (errno != 0) 813235432Sgabor errx(2, "%s", getstr(11)); 814235267Sgabor 815235267Sgabor if (pmatch[2].rm_eo > pmatch[2].rm_so) { 816235267Sgabor len = pmatch[2].rm_eo - pmatch[2].rm_so - 1; 817235267Sgabor c = sort_malloc((len + 1) * sizeof(char)); 818235267Sgabor 819235267Sgabor strncpy(c, s + pmatch[2].rm_so + 1, len); 820235267Sgabor c[len] = '\0'; 821235267Sgabor 822235267Sgabor errno = 0; 823235267Sgabor *nc = (size_t) strtoul(c, NULL, 10); 824235267Sgabor if (errno != 0) 825235432Sgabor errx(2, "%s", getstr(11)); 826235267Sgabor } 827235267Sgabor 828235267Sgabor if (pmatch[3].rm_eo > pmatch[3].rm_so) { 829235267Sgabor 830235267Sgabor len = pmatch[3].rm_eo - pmatch[3].rm_so; 831235267Sgabor 832235267Sgabor strncpy(sopts, s + pmatch[3].rm_so, len); 833235267Sgabor sopts[len] = '\0'; 834235267Sgabor } 835235267Sgabor 836235267Sgabor ret = 0; 837235267Sgabor 838235267Sgaborend: 839235267Sgabor if (c) 840235267Sgabor sort_free(c); 841235267Sgabor if (f) 842235267Sgabor sort_free(f); 843235267Sgabor regfree(&re); 844235267Sgabor 845235267Sgabor return (ret); 846235267Sgabor} 847235267Sgabor 848235267Sgabor/* 849235267Sgabor * "Translate" obsolete +POS1 -POS2 syntax into new -kPOS1,POS2 syntax 850235267Sgabor */ 851235267Sgaborvoid 852235267Sgaborfix_obsolete_keys(int *argc, char **argv) 853235267Sgabor{ 854235267Sgabor char sopt[129]; 855235267Sgabor 856235267Sgabor for (int i = 1; i < *argc; i++) { 857235267Sgabor char *arg1; 858235267Sgabor 859235267Sgabor arg1 = argv[i]; 860235267Sgabor 861235267Sgabor if (strlen(arg1) > 1 && arg1[0] == '+') { 862235267Sgabor int c1, f1; 863235267Sgabor char sopts1[128]; 864235267Sgabor 865235267Sgabor sopts1[0] = 0; 866235267Sgabor c1 = f1 = 0; 867235267Sgabor 868235267Sgabor if (parse_pos_obs(arg1 + 1, &f1, &c1, sopts1) < 0) 869235267Sgabor continue; 870235267Sgabor else { 871235267Sgabor f1 += 1; 872235267Sgabor c1 += 1; 873235267Sgabor if (i + 1 < *argc) { 874235267Sgabor char *arg2 = argv[i + 1]; 875235267Sgabor 876235267Sgabor if (strlen(arg2) > 1 && 877235267Sgabor arg2[0] == '-') { 878235267Sgabor int c2, f2; 879235267Sgabor char sopts2[128]; 880235267Sgabor 881235267Sgabor sopts2[0] = 0; 882235267Sgabor c2 = f2 = 0; 883235267Sgabor 884235267Sgabor if (parse_pos_obs(arg2 + 1, 885235267Sgabor &f2, &c2, sopts2) >= 0) { 886235267Sgabor if (c2 > 0) 887235267Sgabor f2 += 1; 888235267Sgabor sprintf(sopt, "-k%d.%d%s,%d.%d%s", 889235267Sgabor f1, c1, sopts1, f2, c2, sopts2); 890235267Sgabor argv[i] = sort_strdup(sopt); 891235267Sgabor for (int j = i + 1; j + 1 < *argc; j++) 892235267Sgabor argv[j] = argv[j + 1]; 893235267Sgabor *argc -= 1; 894235267Sgabor continue; 895235267Sgabor } 896235267Sgabor } 897235267Sgabor } 898272603Sbapt sprintf(sopt, "-k%d.%d%s", f1, c1, sopts1); 899235267Sgabor argv[i] = sort_strdup(sopt); 900235267Sgabor } 901235267Sgabor } 902235267Sgabor } 903235267Sgabor} 904235267Sgabor 905235267Sgabor/* 906235267Sgabor * Set random seed 907235267Sgabor */ 908235267Sgaborstatic void 909235267Sgaborset_random_seed(void) 910235267Sgabor{ 911235267Sgabor if (need_random) { 912235267Sgabor 913235267Sgabor if (strcmp(random_source, DEFAULT_RANDOM_SORT_SEED_FILE) == 0) { 914235267Sgabor FILE* fseed; 915235267Sgabor MD5_CTX ctx; 916235267Sgabor char rsd[MAX_DEFAULT_RANDOM_SEED_DATA_SIZE]; 917235267Sgabor size_t sz = 0; 918235267Sgabor 919235267Sgabor fseed = openfile(random_source, "r"); 920235267Sgabor while (!feof(fseed)) { 921235267Sgabor int cr; 922235267Sgabor 923235267Sgabor cr = fgetc(fseed); 924235267Sgabor if (cr == EOF) 925235267Sgabor break; 926235267Sgabor 927235267Sgabor rsd[sz++] = (char) cr; 928235267Sgabor 929235267Sgabor if (sz >= MAX_DEFAULT_RANDOM_SEED_DATA_SIZE) 930235267Sgabor break; 931235267Sgabor } 932235267Sgabor 933235267Sgabor closefile(fseed, random_source); 934235267Sgabor 935235267Sgabor MD5Init(&ctx); 936235267Sgabor MD5Update(&ctx, rsd, sz); 937235267Sgabor 938235267Sgabor random_seed = MD5End(&ctx, NULL); 939235267Sgabor random_seed_size = strlen(random_seed); 940235267Sgabor 941235267Sgabor } else { 942235267Sgabor MD5_CTX ctx; 943235267Sgabor char *b; 944235267Sgabor 945235267Sgabor MD5Init(&ctx); 946235267Sgabor b = MD5File(random_source, NULL); 947235267Sgabor if (b == NULL) 948235267Sgabor err(2, NULL); 949235267Sgabor 950235267Sgabor random_seed = b; 951235267Sgabor random_seed_size = strlen(b); 952235267Sgabor } 953235267Sgabor 954235267Sgabor MD5Init(&md5_ctx); 955235267Sgabor if(random_seed_size>0) { 956235267Sgabor MD5Update(&md5_ctx, random_seed, random_seed_size); 957235267Sgabor } 958235267Sgabor } 959235267Sgabor} 960235267Sgabor 961235267Sgabor/* 962235267Sgabor * Main function. 963235267Sgabor */ 964235267Sgaborint 965235267Sgabormain(int argc, char **argv) 966235267Sgabor{ 967235267Sgabor char *outfile, *real_outfile; 968235267Sgabor int c, result; 969235267Sgabor bool mef_flags[NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS] = 970235267Sgabor { false, false, false, false, false, false }; 971235267Sgabor 972235267Sgabor result = 0; 973235267Sgabor outfile = sort_strdup("-"); 974235267Sgabor real_outfile = NULL; 975235267Sgabor 976235267Sgabor struct sort_mods *sm = &default_sort_mods_object; 977235267Sgabor 978235267Sgabor init_tmp_files(); 979235267Sgabor 980235267Sgabor set_signal_handler(); 981235267Sgabor 982235267Sgabor set_hw_params(); 983235267Sgabor set_locale(); 984235267Sgabor set_tmpdir(); 985235267Sgabor set_sort_opts(); 986235267Sgabor 987235267Sgabor fix_obsolete_keys(&argc, argv); 988235267Sgabor 989235267Sgabor while (((c = getopt_long(argc, argv, OPTIONS, long_options, NULL)) 990235267Sgabor != -1)) { 991235267Sgabor 992235267Sgabor check_mutually_exclusive_flags(c, mef_flags); 993235267Sgabor 994235267Sgabor if (!set_sort_modifier(sm, c)) { 995235267Sgabor 996235267Sgabor switch (c) { 997235267Sgabor case 'c': 998235267Sgabor sort_opts_vals.cflag = true; 999235267Sgabor if (optarg) { 1000235267Sgabor if (!strcmp(optarg, "diagnose-first")) 1001235267Sgabor ; 1002235267Sgabor else if (!strcmp(optarg, "silent") || 1003235267Sgabor !strcmp(optarg, "quiet")) 1004235267Sgabor sort_opts_vals.csilentflag = true; 1005235267Sgabor else if (*optarg) 1006235267Sgabor unknown(optarg); 1007235267Sgabor } 1008235267Sgabor break; 1009235267Sgabor case 'C': 1010235267Sgabor sort_opts_vals.cflag = true; 1011235267Sgabor sort_opts_vals.csilentflag = true; 1012235267Sgabor break; 1013235267Sgabor case 'k': 1014235267Sgabor { 1015235267Sgabor sort_opts_vals.complex_sort = true; 1016235267Sgabor sort_opts_vals.kflag = true; 1017235267Sgabor 1018235267Sgabor keys_num++; 1019235267Sgabor keys = sort_realloc(keys, keys_num * 1020235267Sgabor sizeof(struct key_specs)); 1021235267Sgabor memset(&(keys[keys_num - 1]), 0, 1022235267Sgabor sizeof(struct key_specs)); 1023235267Sgabor 1024235267Sgabor if (parse_k(optarg, &(keys[keys_num - 1])) 1025235267Sgabor < 0) { 1026245997Sgabor errc(2, EINVAL, "-k %s", optarg); 1027235267Sgabor } 1028235267Sgabor 1029235267Sgabor break; 1030235267Sgabor } 1031235267Sgabor case 'm': 1032235267Sgabor sort_opts_vals.mflag = true; 1033235267Sgabor break; 1034235267Sgabor case 'o': 1035235546Sgabor outfile = sort_realloc(outfile, (strlen(optarg) + 1)); 1036235546Sgabor strcpy(outfile, optarg); 1037235267Sgabor break; 1038235267Sgabor case 's': 1039235267Sgabor sort_opts_vals.sflag = true; 1040235267Sgabor break; 1041235267Sgabor case 'S': 1042235267Sgabor available_free_memory = 1043235267Sgabor parse_memory_buffer_value(optarg); 1044235267Sgabor break; 1045235267Sgabor case 'T': 1046235267Sgabor tmpdir = sort_strdup(optarg); 1047235267Sgabor break; 1048235267Sgabor case 't': 1049235987Sgabor while (strlen(optarg) > 1) { 1050235987Sgabor if (optarg[0] != '\\') { 1051245997Sgabor errc(2, EINVAL, "%s", optarg); 1052235267Sgabor } 1053235987Sgabor optarg += 1; 1054235987Sgabor if (*optarg == '0') { 1055235987Sgabor *optarg = 0; 1056235987Sgabor break; 1057235987Sgabor } 1058235267Sgabor } 1059235267Sgabor sort_opts_vals.tflag = true; 1060235267Sgabor sort_opts_vals.field_sep = btowc(optarg[0]); 1061235267Sgabor if (sort_opts_vals.field_sep == WEOF) { 1062235267Sgabor errno = EINVAL; 1063235267Sgabor err(2, NULL); 1064235267Sgabor } 1065235267Sgabor if (!gnusort_numeric_compatibility) { 1066235267Sgabor if (symbol_decimal_point == sort_opts_vals.field_sep) 1067235267Sgabor symbol_decimal_point = WEOF; 1068235267Sgabor if (symbol_thousands_sep == sort_opts_vals.field_sep) 1069235267Sgabor symbol_thousands_sep = WEOF; 1070235267Sgabor if (symbol_negative_sign == sort_opts_vals.field_sep) 1071235267Sgabor symbol_negative_sign = WEOF; 1072235267Sgabor if (symbol_positive_sign == sort_opts_vals.field_sep) 1073235267Sgabor symbol_positive_sign = WEOF; 1074235267Sgabor } 1075235267Sgabor break; 1076235267Sgabor case 'u': 1077235267Sgabor sort_opts_vals.uflag = true; 1078235267Sgabor /* stable sort for the correct unique val */ 1079235267Sgabor sort_opts_vals.sflag = true; 1080235267Sgabor break; 1081235267Sgabor case 'z': 1082235267Sgabor sort_opts_vals.zflag = true; 1083235267Sgabor break; 1084235267Sgabor case SORT_OPT: 1085235267Sgabor if (optarg) { 1086235267Sgabor if (!strcmp(optarg, "general-numeric")) 1087235267Sgabor set_sort_modifier(sm, 'g'); 1088235267Sgabor else if (!strcmp(optarg, "human-numeric")) 1089235267Sgabor set_sort_modifier(sm, 'h'); 1090235267Sgabor else if (!strcmp(optarg, "numeric")) 1091235267Sgabor set_sort_modifier(sm, 'n'); 1092235267Sgabor else if (!strcmp(optarg, "month")) 1093235267Sgabor set_sort_modifier(sm, 'M'); 1094235267Sgabor else if (!strcmp(optarg, "random")) 1095235267Sgabor set_sort_modifier(sm, 'R'); 1096235267Sgabor else 1097235267Sgabor unknown(optarg); 1098235267Sgabor } 1099235267Sgabor break; 1100235267Sgabor#if defined(SORT_THREADS) 1101238108Sgabor case PARALLEL_OPT: 1102235267Sgabor nthreads = (size_t)(atoi(optarg)); 1103235267Sgabor if (nthreads < 1) 1104235267Sgabor nthreads = 1; 1105235267Sgabor if (nthreads > 1024) 1106235267Sgabor nthreads = 1024; 1107235267Sgabor break; 1108235267Sgabor#endif 1109235267Sgabor case QSORT_OPT: 1110235267Sgabor sort_opts_vals.sort_method = SORT_QSORT; 1111235267Sgabor break; 1112235267Sgabor case MERGESORT_OPT: 1113235267Sgabor sort_opts_vals.sort_method = SORT_MERGESORT; 1114235267Sgabor break; 1115235987Sgabor case MMAP_OPT: 1116235987Sgabor use_mmap = true; 1117235987Sgabor break; 1118235267Sgabor case HEAPSORT_OPT: 1119235267Sgabor sort_opts_vals.sort_method = SORT_HEAPSORT; 1120235267Sgabor break; 1121235267Sgabor case RADIXSORT_OPT: 1122235267Sgabor sort_opts_vals.sort_method = SORT_RADIXSORT; 1123235267Sgabor break; 1124235267Sgabor case RANDOMSOURCE_OPT: 1125235267Sgabor random_source = strdup(optarg); 1126235267Sgabor break; 1127235267Sgabor case COMPRESSPROGRAM_OPT: 1128235267Sgabor compress_program = strdup(optarg); 1129235267Sgabor break; 1130235267Sgabor case FF_OPT: 1131235267Sgabor read_fns_from_file0(optarg); 1132235267Sgabor break; 1133235267Sgabor case BS_OPT: 1134235267Sgabor { 1135235267Sgabor errno = 0; 1136235267Sgabor long mof = strtol(optarg, NULL, 10); 1137235267Sgabor if (errno != 0) 1138245997Sgabor err(2, "--batch-size"); 1139235267Sgabor if (mof >= 2) 1140235267Sgabor max_open_files = (size_t) mof + 1; 1141235267Sgabor } 1142235267Sgabor break; 1143235267Sgabor case VERSION_OPT: 1144235267Sgabor printf("%s\n", VERSION); 1145235267Sgabor exit(EXIT_SUCCESS); 1146235267Sgabor /* NOTREACHED */ 1147235267Sgabor break; 1148235267Sgabor case DEBUG_OPT: 1149235267Sgabor debug_sort = true; 1150235267Sgabor break; 1151235267Sgabor case HELP_OPT: 1152235267Sgabor usage(false); 1153235267Sgabor /* NOTREACHED */ 1154235267Sgabor break; 1155235267Sgabor default: 1156235267Sgabor usage(true); 1157235267Sgabor /* NOTREACHED */ 1158235267Sgabor } 1159235267Sgabor } 1160235267Sgabor } 1161235267Sgabor 1162235267Sgabor argc -= optind; 1163235267Sgabor argv += optind; 1164235267Sgabor 1165235267Sgabor#ifndef WITHOUT_NLS 1166235267Sgabor catalog = catopen("sort", NL_CAT_LOCALE); 1167235267Sgabor#endif 1168235267Sgabor 1169235267Sgabor if (sort_opts_vals.cflag && sort_opts_vals.mflag) 1170235432Sgabor errx(1, "%c:%c: %s", 'm', 'c', getstr(1)); 1171235267Sgabor 1172235267Sgabor#ifndef WITHOUT_NLS 1173235267Sgabor catclose(catalog); 1174235267Sgabor#endif 1175235267Sgabor 1176235267Sgabor if (keys_num == 0) { 1177235267Sgabor keys_num = 1; 1178235267Sgabor keys = sort_realloc(keys, sizeof(struct key_specs)); 1179235267Sgabor memset(&(keys[0]), 0, sizeof(struct key_specs)); 1180235267Sgabor keys[0].c1 = 1; 1181235267Sgabor keys[0].pos1b = default_sort_mods->bflag; 1182235267Sgabor keys[0].pos2b = default_sort_mods->bflag; 1183235267Sgabor memcpy(&(keys[0].sm), default_sort_mods, 1184235267Sgabor sizeof(struct sort_mods)); 1185235267Sgabor } 1186235267Sgabor 1187235267Sgabor for (size_t i = 0; i < keys_num; i++) { 1188235267Sgabor struct key_specs *ks; 1189235267Sgabor 1190235267Sgabor ks = &(keys[i]); 1191235267Sgabor 1192235267Sgabor if (sort_modifier_empty(&(ks->sm)) && !(ks->pos1b) && 1193235267Sgabor !(ks->pos2b)) { 1194235267Sgabor ks->pos1b = sm->bflag; 1195235267Sgabor ks->pos2b = sm->bflag; 1196235267Sgabor memcpy(&(ks->sm), sm, sizeof(struct sort_mods)); 1197235267Sgabor } 1198235267Sgabor 1199235267Sgabor ks->sm.func = get_sort_func(&(ks->sm)); 1200235267Sgabor } 1201235267Sgabor 1202242430Sgabor if (argv_from_file0) { 1203235267Sgabor argc = argc_from_file0; 1204235267Sgabor argv = argv_from_file0; 1205235267Sgabor } 1206235267Sgabor 1207235267Sgabor if (debug_sort) { 1208244515Sgabor printf("Memory to be used for sorting: %llu\n",available_free_memory); 1209235267Sgabor#if defined(SORT_THREADS) 1210244515Sgabor printf("Number of CPUs: %d\n",(int)ncpu); 1211235267Sgabor nthreads = 1; 1212235267Sgabor#endif 1213235267Sgabor printf("Using collate rules of %s locale\n", 1214235267Sgabor setlocale(LC_COLLATE, NULL)); 1215235267Sgabor if (byte_sort) 1216235267Sgabor printf("Byte sort is used\n"); 1217235267Sgabor if (print_symbols_on_debug) { 1218235267Sgabor printf("Decimal Point: <%lc>\n", symbol_decimal_point); 1219235267Sgabor if (symbol_thousands_sep) 1220235267Sgabor printf("Thousands separator: <%lc>\n", 1221235267Sgabor symbol_thousands_sep); 1222235267Sgabor printf("Positive sign: <%lc>\n", symbol_positive_sign); 1223235267Sgabor printf("Negative sign: <%lc>\n", symbol_negative_sign); 1224235267Sgabor } 1225235267Sgabor } 1226235267Sgabor 1227235267Sgabor set_random_seed(); 1228235267Sgabor 1229235267Sgabor /* Case when the outfile equals one of the input files: */ 1230235267Sgabor if (strcmp(outfile, "-")) { 1231235267Sgabor 1232235267Sgabor for(int i = 0; i < argc; ++i) { 1233235267Sgabor if (strcmp(argv[i], outfile) == 0) { 1234235267Sgabor real_outfile = sort_strdup(outfile); 1235235267Sgabor for(;;) { 1236235267Sgabor char* tmp = sort_malloc(strlen(outfile) + 1237235267Sgabor strlen(".tmp") + 1); 1238235267Sgabor 1239235267Sgabor strcpy(tmp, outfile); 1240235267Sgabor strcpy(tmp + strlen(tmp), ".tmp"); 1241235267Sgabor sort_free(outfile); 1242235267Sgabor outfile = tmp; 1243235267Sgabor if (access(outfile, F_OK) < 0) 1244235267Sgabor break; 1245235267Sgabor } 1246235267Sgabor tmp_file_atexit(outfile); 1247235267Sgabor } 1248235267Sgabor } 1249235267Sgabor } 1250235267Sgabor 1251235987Sgabor#if defined(SORT_THREADS) 1252235987Sgabor if ((argc < 1) || (strcmp(outfile, "-") == 0) || (*outfile == 0)) 1253235987Sgabor nthreads = 1; 1254235987Sgabor#endif 1255235987Sgabor 1256235267Sgabor if (!sort_opts_vals.cflag && !sort_opts_vals.mflag) { 1257235267Sgabor struct file_list fl; 1258235267Sgabor struct sort_list list; 1259235267Sgabor 1260235267Sgabor sort_list_init(&list); 1261235267Sgabor file_list_init(&fl, true); 1262235267Sgabor 1263235267Sgabor if (argc < 1) 1264235267Sgabor procfile("-", &list, &fl); 1265235267Sgabor else { 1266235267Sgabor while (argc > 0) { 1267235267Sgabor procfile(*argv, &list, &fl); 1268235267Sgabor --argc; 1269235267Sgabor ++argv; 1270235267Sgabor } 1271235267Sgabor } 1272235267Sgabor 1273235267Sgabor if (fl.count < 1) 1274235267Sgabor sort_list_to_file(&list, outfile); 1275235267Sgabor else { 1276235267Sgabor if (list.count > 0) { 1277235267Sgabor char *flast = new_tmp_file_name(); 1278235267Sgabor 1279235267Sgabor sort_list_to_file(&list, flast); 1280235267Sgabor file_list_add(&fl, flast, false); 1281235267Sgabor } 1282235267Sgabor merge_files(&fl, outfile); 1283235267Sgabor } 1284235267Sgabor 1285235267Sgabor file_list_clean(&fl); 1286235267Sgabor 1287235267Sgabor /* 1288235267Sgabor * We are about to exit the program, so we can ignore 1289235267Sgabor * the clean-up for speed 1290235267Sgabor * 1291235267Sgabor * sort_list_clean(&list); 1292235267Sgabor */ 1293235267Sgabor 1294235267Sgabor } else if (sort_opts_vals.cflag) { 1295235267Sgabor result = (argc == 0) ? (check("-")) : (check(*argv)); 1296235267Sgabor } else if (sort_opts_vals.mflag) { 1297235267Sgabor struct file_list fl; 1298235267Sgabor 1299235267Sgabor file_list_init(&fl, false); 1300235267Sgabor file_list_populate(&fl, argc, argv, true); 1301235267Sgabor merge_files(&fl, outfile); 1302235267Sgabor file_list_clean(&fl); 1303235267Sgabor } 1304235267Sgabor 1305235267Sgabor if (real_outfile) { 1306235267Sgabor unlink(real_outfile); 1307235267Sgabor if (rename(outfile, real_outfile) < 0) 1308235267Sgabor err(2, NULL); 1309235267Sgabor sort_free(real_outfile); 1310235267Sgabor } 1311235267Sgabor 1312235267Sgabor sort_free(outfile); 1313235267Sgabor 1314235267Sgabor return (result); 1315235267Sgabor} 1316