xref: /dflybsd-src/usr.bin/sort/sort.c (revision a98f7024a73d3aaccc56d8f7c0082a60a274a0a5)
17572dc55SJohn Marino /*-
250fc853eSJohn Marino  * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
350fc853eSJohn Marino  * Copyright (C) 2012 Oleg Moskalenko <mom040267@gmail.com>
47572dc55SJohn Marino  * All rights reserved.
57572dc55SJohn Marino  *
67572dc55SJohn Marino  * Redistribution and use in source and binary forms, with or without
77572dc55SJohn Marino  * modification, are permitted provided that the following conditions
87572dc55SJohn Marino  * are met:
97572dc55SJohn Marino  * 1. Redistributions of source code must retain the above copyright
107572dc55SJohn Marino  *    notice, this list of conditions and the following disclaimer.
117572dc55SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
127572dc55SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
137572dc55SJohn Marino  *    documentation and/or other materials provided with the distribution.
147572dc55SJohn Marino  *
1550fc853eSJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
167572dc55SJohn Marino  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
177572dc55SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1850fc853eSJohn Marino  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
197572dc55SJohn Marino  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
207572dc55SJohn Marino  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
217572dc55SJohn Marino  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
227572dc55SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
237572dc55SJohn Marino  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
247572dc55SJohn Marino  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
257572dc55SJohn Marino  * SUCH DAMAGE.
2650fc853eSJohn Marino  *
2750fc853eSJohn Marino  * $FreeBSD: head/usr.bin/sort/sort.c 281182 2015-04-07 01:17:49Z pfg $
287572dc55SJohn Marino  */
297572dc55SJohn Marino 
307572dc55SJohn Marino 
3157b30760SJohn Marino #include <sys/stat.h>
3250fc853eSJohn Marino #include <sys/sysctl.h>
337572dc55SJohn Marino #include <sys/types.h>
347572dc55SJohn Marino 
3550fc853eSJohn Marino #include <err.h>
3650fc853eSJohn Marino #include <errno.h>
3750fc853eSJohn Marino #include <getopt.h>
3850fc853eSJohn Marino #include <limits.h>
3950fc853eSJohn Marino #include <locale.h>
4050fc853eSJohn Marino #include <regex.h>
417572dc55SJohn Marino #include <signal.h>
4250fc853eSJohn Marino #include <stdbool.h>
4350fc853eSJohn Marino #include <stdio.h>
447572dc55SJohn Marino #include <stdlib.h>
457572dc55SJohn Marino #include <string.h>
467572dc55SJohn Marino #include <unistd.h>
4750fc853eSJohn Marino #include <wchar.h>
4850fc853eSJohn Marino #include <wctype.h>
49*a98f7024Szrj #if defined(SORT_RANDOM)
50*a98f7024Szrj #include <openssl/md5.h>
51*a98f7024Szrj #endif
527572dc55SJohn Marino 
5350fc853eSJohn Marino #include "coll.h"
5450fc853eSJohn Marino #include "file.h"
5550fc853eSJohn Marino #include "sort.h"
5650fc853eSJohn Marino 
5750fc853eSJohn Marino #ifndef WITHOUT_NLS
5850fc853eSJohn Marino #include <nl_types.h>
5950fc853eSJohn Marino nl_catd catalog;
6050fc853eSJohn Marino #endif
6150fc853eSJohn Marino 
626d7e22ecSzrj #if defined(SORT_RANDOM)
6350fc853eSJohn Marino #define	OPTIONS	"bcCdfghik:Mmno:RrsS:t:T:uVz"
646d7e22ecSzrj #else
656d7e22ecSzrj #define	OPTIONS	"bcCdfghik:Mmno:rsS:t:T:uVz"
666d7e22ecSzrj #endif
6750fc853eSJohn Marino 
686d7e22ecSzrj #if defined(SORT_RANDOM)
6950fc853eSJohn Marino #define DEFAULT_RANDOM_SORT_SEED_FILE ("/dev/random")
7050fc853eSJohn Marino #define MAX_DEFAULT_RANDOM_SEED_DATA_SIZE (1024)
7150fc853eSJohn Marino 
7250fc853eSJohn Marino static bool need_random;
7350fc853eSJohn Marino static const char *random_source = DEFAULT_RANDOM_SORT_SEED_FILE;
7450fc853eSJohn Marino static const void *random_seed;
7550fc853eSJohn Marino static size_t random_seed_size;
7650fc853eSJohn Marino 
7750fc853eSJohn Marino MD5_CTX md5_ctx;
786d7e22ecSzrj #endif
797572dc55SJohn Marino 
807572dc55SJohn Marino /*
8150fc853eSJohn Marino  * Default messages to use when NLS is disabled or no catalogue
8250fc853eSJohn Marino  * is found.
837572dc55SJohn Marino  */
8450fc853eSJohn Marino const char *nlsstr[] = { "",
8550fc853eSJohn Marino /* 1*/"mutually exclusive flags",
8650fc853eSJohn Marino /* 2*/"extra argument not allowed with -c",
8750fc853eSJohn Marino /* 3*/"Unknown feature",
8850fc853eSJohn Marino /* 4*/"Wrong memory buffer specification",
8950fc853eSJohn Marino /* 5*/"0 field in key specs",
9050fc853eSJohn Marino /* 6*/"0 column in key specs",
9150fc853eSJohn Marino /* 7*/"Wrong file mode",
9250fc853eSJohn Marino /* 8*/"Cannot open file for reading",
9350fc853eSJohn Marino /* 9*/"Radix sort cannot be used with these sort options",
9450fc853eSJohn Marino /*10*/"The chosen sort method cannot be used with stable and/or unique sort",
9550fc853eSJohn Marino /*11*/"Invalid key position",
9650fc853eSJohn Marino /*12*/"Usage: %s [-bcCdfigMmnrsuz] [-kPOS1[,POS2] ... ] "
9750fc853eSJohn Marino       "[+POS1 [-POS2]] [-S memsize] [-T tmpdir] [-t separator] "
9850fc853eSJohn Marino       "[-o outfile] [--batch-size size] [--files0-from file] "
9950fc853eSJohn Marino       "[--heapsort] [--mergesort] [--radixsort] [--qsort] "
10050fc853eSJohn Marino       "[--mmap] "
10150fc853eSJohn Marino #if defined(SORT_THREADS)
10250fc853eSJohn Marino       "[--parallel thread_no] "
10350fc853eSJohn Marino #endif
10450fc853eSJohn Marino       "[--human-numeric-sort] "
1056d7e22ecSzrj #if defined(SORT_RANDOM)
10650fc853eSJohn Marino       "[--version-sort] [--random-sort [--random-source file]] "
1076d7e22ecSzrj #else
1086d7e22ecSzrj       "[--version-sort] "
1096d7e22ecSzrj #endif
11050fc853eSJohn Marino       "[--compress-program program] [file ...]\n" };
1117572dc55SJohn Marino 
11250fc853eSJohn Marino struct sort_opts sort_opts_vals;
1137572dc55SJohn Marino 
11450fc853eSJohn Marino bool debug_sort;
11550fc853eSJohn Marino bool need_hint;
1167572dc55SJohn Marino 
11750fc853eSJohn Marino #if defined(SORT_THREADS)
11850fc853eSJohn Marino unsigned int ncpu = 1;
11950fc853eSJohn Marino size_t nthreads = 1;
12050fc853eSJohn Marino #endif
1217572dc55SJohn Marino 
12250fc853eSJohn Marino static bool gnusort_numeric_compatibility;
1237572dc55SJohn Marino 
12450fc853eSJohn Marino static struct sort_mods default_sort_mods_object;
12550fc853eSJohn Marino struct sort_mods * const default_sort_mods = &default_sort_mods_object;
1267572dc55SJohn Marino 
12750fc853eSJohn Marino static bool print_symbols_on_debug;
12850fc853eSJohn Marino 
12950fc853eSJohn Marino /*
13050fc853eSJohn Marino  * Arguments from file (when file0-from option is used:
13150fc853eSJohn Marino  */
13250fc853eSJohn Marino static size_t argc_from_file0 = (size_t)-1;
13350fc853eSJohn Marino static char **argv_from_file0;
13450fc853eSJohn Marino 
13550fc853eSJohn Marino /*
13650fc853eSJohn Marino  * Placeholder symbols for options which have no single-character equivalent
13750fc853eSJohn Marino  */
13850fc853eSJohn Marino enum
1397572dc55SJohn Marino {
14050fc853eSJohn Marino 	SORT_OPT = CHAR_MAX + 1,
14150fc853eSJohn Marino 	HELP_OPT,
14250fc853eSJohn Marino 	FF_OPT,
14350fc853eSJohn Marino 	BS_OPT,
14450fc853eSJohn Marino 	VERSION_OPT,
14550fc853eSJohn Marino 	DEBUG_OPT,
14650fc853eSJohn Marino #if defined(SORT_THREADS)
14750fc853eSJohn Marino 	PARALLEL_OPT,
14850fc853eSJohn Marino #endif
1496d7e22ecSzrj #if defined(SORT_RANDOM)
15050fc853eSJohn Marino 	RANDOMSOURCE_OPT,
1516d7e22ecSzrj #endif
15250fc853eSJohn Marino 	COMPRESSPROGRAM_OPT,
15350fc853eSJohn Marino 	QSORT_OPT,
15450fc853eSJohn Marino 	MERGESORT_OPT,
15550fc853eSJohn Marino 	HEAPSORT_OPT,
15650fc853eSJohn Marino 	RADIXSORT_OPT,
15750fc853eSJohn Marino 	MMAP_OPT
15850fc853eSJohn Marino };
1597572dc55SJohn Marino 
16050fc853eSJohn Marino #define	NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS 6
16150fc853eSJohn Marino static const char mutually_exclusive_flags[NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS] = { 'M', 'n', 'g', 'R', 'h', 'V' };
1627572dc55SJohn Marino 
16350fc853eSJohn Marino static struct option long_options[] = {
16450fc853eSJohn Marino 				{ "batch-size", required_argument, NULL, BS_OPT },
16550fc853eSJohn Marino 				{ "buffer-size", required_argument, NULL, 'S' },
16650fc853eSJohn Marino 				{ "check", optional_argument, NULL, 'c' },
16750fc853eSJohn Marino 				{ "check=silent|quiet", optional_argument, NULL, 'C' },
16850fc853eSJohn Marino 				{ "compress-program", required_argument, NULL, COMPRESSPROGRAM_OPT },
16950fc853eSJohn Marino 				{ "debug", no_argument, NULL, DEBUG_OPT },
17050fc853eSJohn Marino 				{ "dictionary-order", no_argument, NULL, 'd' },
17150fc853eSJohn Marino 				{ "field-separator", required_argument, NULL, 't' },
17250fc853eSJohn Marino 				{ "files0-from", required_argument, NULL, FF_OPT },
17350fc853eSJohn Marino 				{ "general-numeric-sort", no_argument, NULL, 'g' },
17450fc853eSJohn Marino 				{ "heapsort", no_argument, NULL, HEAPSORT_OPT },
17550fc853eSJohn Marino 				{ "help",no_argument, NULL, HELP_OPT },
17650fc853eSJohn Marino 				{ "human-numeric-sort", no_argument, NULL, 'h' },
17750fc853eSJohn Marino 				{ "ignore-leading-blanks", no_argument, NULL, 'b' },
17850fc853eSJohn Marino 				{ "ignore-case", no_argument, NULL, 'f' },
17950fc853eSJohn Marino 				{ "ignore-nonprinting", no_argument, NULL, 'i' },
18050fc853eSJohn Marino 				{ "key", required_argument, NULL, 'k' },
18150fc853eSJohn Marino 				{ "merge", no_argument, NULL, 'm' },
18250fc853eSJohn Marino 				{ "mergesort", no_argument, NULL, MERGESORT_OPT },
18350fc853eSJohn Marino 				{ "mmap", no_argument, NULL, MMAP_OPT },
18450fc853eSJohn Marino 				{ "month-sort", no_argument, NULL, 'M' },
18550fc853eSJohn Marino 				{ "numeric-sort", no_argument, NULL, 'n' },
18650fc853eSJohn Marino 				{ "output", required_argument, NULL, 'o' },
18750fc853eSJohn Marino #if defined(SORT_THREADS)
18850fc853eSJohn Marino 				{ "parallel", required_argument, NULL, PARALLEL_OPT },
18950fc853eSJohn Marino #endif
19050fc853eSJohn Marino 				{ "qsort", no_argument, NULL, QSORT_OPT },
19150fc853eSJohn Marino 				{ "radixsort", no_argument, NULL, RADIXSORT_OPT },
1926d7e22ecSzrj #if defined(SORT_RANDOM)
19350fc853eSJohn Marino 				{ "random-sort", no_argument, NULL, 'R' },
19450fc853eSJohn Marino 				{ "random-source", required_argument, NULL, RANDOMSOURCE_OPT },
1956d7e22ecSzrj #endif
19650fc853eSJohn Marino 				{ "reverse", no_argument, NULL, 'r' },
19750fc853eSJohn Marino 				{ "sort", required_argument, NULL, SORT_OPT },
19850fc853eSJohn Marino 				{ "stable", no_argument, NULL, 's' },
19950fc853eSJohn Marino 				{ "temporary-directory",required_argument, NULL, 'T' },
20050fc853eSJohn Marino 				{ "unique", no_argument, NULL, 'u' },
20150fc853eSJohn Marino 				{ "version", no_argument, NULL, VERSION_OPT },
20250fc853eSJohn Marino 				{ "version-sort",no_argument, NULL, 'V' },
20350fc853eSJohn Marino 				{ "zero-terminated", no_argument, NULL, 'z' },
20450fc853eSJohn Marino 				{ NULL, no_argument, NULL, 0 }
20550fc853eSJohn Marino };
2067572dc55SJohn Marino 
207aa348a5cSzrj static void fix_obsolete_keys(int *argc, char **argv);
2087572dc55SJohn Marino 
2097572dc55SJohn Marino /*
21050fc853eSJohn Marino  * Check where sort modifier is present
2117572dc55SJohn Marino  */
21250fc853eSJohn Marino static bool
sort_modifier_empty(struct sort_mods * sm)21350fc853eSJohn Marino sort_modifier_empty(struct sort_mods *sm)
21450fc853eSJohn Marino {
21550fc853eSJohn Marino 
21650fc853eSJohn Marino 	if (sm == NULL)
21750fc853eSJohn Marino 		return (true);
21850fc853eSJohn Marino 	return (!(sm->Mflag || sm->Vflag || sm->nflag || sm->gflag ||
2196d7e22ecSzrj #ifdef SORT_RANDOM
2206d7e22ecSzrj 	    sm->Rflag ||
2216d7e22ecSzrj #endif
2226d7e22ecSzrj 	    sm->rflag || sm->hflag || sm->dflag || sm->fflag));
2237572dc55SJohn Marino }
2247572dc55SJohn Marino 
22550fc853eSJohn Marino /*
22650fc853eSJohn Marino  * Print out usage text.
22750fc853eSJohn Marino  */
22850fc853eSJohn Marino static void
usage(bool opt_err)22950fc853eSJohn Marino usage(bool opt_err)
23050fc853eSJohn Marino {
23150fc853eSJohn Marino 	FILE *out;
23250fc853eSJohn Marino 
233aa348a5cSzrj 	out = opt_err ? stderr : stdout;
23450fc853eSJohn Marino 
23550fc853eSJohn Marino 	fprintf(out, getstr(12), getprogname());
23650fc853eSJohn Marino 	if (opt_err)
23750fc853eSJohn Marino 		exit(2);
2387572dc55SJohn Marino 	exit(0);
2397572dc55SJohn Marino }
2407572dc55SJohn Marino 
24150fc853eSJohn Marino /*
24250fc853eSJohn Marino  * Read input file names from a file (file0-from option).
24350fc853eSJohn Marino  */
2447572dc55SJohn Marino static void
read_fns_from_file0(const char * fn)24550fc853eSJohn Marino read_fns_from_file0(const char *fn)
2467572dc55SJohn Marino {
24750fc853eSJohn Marino 	FILE *f;
24850fc853eSJohn Marino 	char *line = NULL;
24950fc853eSJohn Marino 	size_t linesize = 0;
25050fc853eSJohn Marino 	ssize_t linelen;
25150fc853eSJohn Marino 
25250fc853eSJohn Marino 	if (fn == NULL)
25350fc853eSJohn Marino 		return;
25450fc853eSJohn Marino 
25550fc853eSJohn Marino 	f = fopen(fn, "r");
25650fc853eSJohn Marino 	if (f == NULL)
25750fc853eSJohn Marino 		err(2, "%s", fn);
25850fc853eSJohn Marino 
25950fc853eSJohn Marino 	while ((linelen = getdelim(&line, &linesize, '\0', f)) != -1) {
26050fc853eSJohn Marino 		if (*line != '\0') {
26150fc853eSJohn Marino 			if (argc_from_file0 == (size_t) - 1)
26250fc853eSJohn Marino 				argc_from_file0 = 0;
26350fc853eSJohn Marino 			++argc_from_file0;
26450fc853eSJohn Marino 			argv_from_file0 = sort_realloc(argv_from_file0,
26550fc853eSJohn Marino 			    argc_from_file0 * sizeof(char *));
26650fc853eSJohn Marino 			if (argv_from_file0 == NULL)
26750fc853eSJohn Marino 				err(2, NULL);
26850fc853eSJohn Marino 			argv_from_file0[argc_from_file0 - 1] = line;
26950fc853eSJohn Marino 		} else {
27050fc853eSJohn Marino 			free(line);
27150fc853eSJohn Marino 		}
27250fc853eSJohn Marino 		line = NULL;
27350fc853eSJohn Marino 		linesize = 0;
27450fc853eSJohn Marino 	}
27550fc853eSJohn Marino 	if (ferror(f))
27650fc853eSJohn Marino 		err(2, "%s: getdelim", fn);
27750fc853eSJohn Marino 
27850fc853eSJohn Marino 	closefile(f, fn);
2797572dc55SJohn Marino }
2807572dc55SJohn Marino 
28150fc853eSJohn Marino /*
28250fc853eSJohn Marino  * Check how much RAM is available for the sort.
28350fc853eSJohn Marino  */
2847572dc55SJohn Marino static void
set_hw_params(void)28550fc853eSJohn Marino set_hw_params(void)
2867572dc55SJohn Marino {
28750fc853eSJohn Marino 	long pages, psize;
28850fc853eSJohn Marino 
28950fc853eSJohn Marino 	pages = psize = 0;
29050fc853eSJohn Marino 
29150fc853eSJohn Marino #if defined(SORT_THREADS)
29250fc853eSJohn Marino 	ncpu = 1;
29350fc853eSJohn Marino #endif
29450fc853eSJohn Marino 
29550fc853eSJohn Marino 	pages = sysconf(_SC_PHYS_PAGES);
29650fc853eSJohn Marino 	if (pages < 1) {
29750fc853eSJohn Marino 		perror("sysconf pages");
29894400e62SJohn Marino 		pages = 1;
29950fc853eSJohn Marino 	}
30050fc853eSJohn Marino 	psize = sysconf(_SC_PAGESIZE);
30150fc853eSJohn Marino 	if (psize < 1) {
30250fc853eSJohn Marino 		perror("sysconf psize");
30350fc853eSJohn Marino 		psize = 4096;
30450fc853eSJohn Marino 	}
30550fc853eSJohn Marino #if defined(SORT_THREADS)
30650fc853eSJohn Marino 	ncpu = (unsigned int)sysconf(_SC_NPROCESSORS_ONLN);
30750fc853eSJohn Marino 	if (ncpu < 1)
30850fc853eSJohn Marino 		ncpu = 1;
30950fc853eSJohn Marino 	else if(ncpu > 32)
31050fc853eSJohn Marino 		ncpu = 32;
31150fc853eSJohn Marino 
31250fc853eSJohn Marino 	nthreads = ncpu;
31350fc853eSJohn Marino #endif
31450fc853eSJohn Marino 
31550fc853eSJohn Marino 	free_memory = (unsigned long long) pages * (unsigned long long) psize;
31650fc853eSJohn Marino 	available_free_memory = free_memory / 2;
31750fc853eSJohn Marino 
31850fc853eSJohn Marino 	if (available_free_memory < 1024)
31950fc853eSJohn Marino 		available_free_memory = 1024;
3207572dc55SJohn Marino }
3217572dc55SJohn Marino 
32250fc853eSJohn Marino /*
32350fc853eSJohn Marino  * Convert "plain" symbol to wide symbol, with default value.
32450fc853eSJohn Marino  */
3257572dc55SJohn Marino static void
conv_mbtowc(wchar_t * wc,const char * c,const wchar_t def)32650fc853eSJohn Marino conv_mbtowc(wchar_t *wc, const char *c, const wchar_t def)
3277572dc55SJohn Marino {
32850fc853eSJohn Marino 
32950fc853eSJohn Marino 	if (wc && c) {
33050fc853eSJohn Marino 		int res;
33150fc853eSJohn Marino 
33250fc853eSJohn Marino 		res = mbtowc(wc, c, MB_CUR_MAX);
33350fc853eSJohn Marino 		if (res < 1)
33450fc853eSJohn Marino 			*wc = def;
33550fc853eSJohn Marino 	}
3367572dc55SJohn Marino }
3377572dc55SJohn Marino 
33850fc853eSJohn Marino /*
33950fc853eSJohn Marino  * Set current locale symbols.
34050fc853eSJohn Marino  */
34150fc853eSJohn Marino static void
set_locale(void)34250fc853eSJohn Marino set_locale(void)
3437572dc55SJohn Marino {
34450fc853eSJohn Marino 	struct lconv *lc;
34550fc853eSJohn Marino 	const char *locale;
34650fc853eSJohn Marino 
34750fc853eSJohn Marino 	setlocale(LC_ALL, "");
34850fc853eSJohn Marino 
34950fc853eSJohn Marino 	lc = localeconv();
35050fc853eSJohn Marino 
35150fc853eSJohn Marino 	if (lc) {
35250fc853eSJohn Marino 		/* obtain LC_NUMERIC info */
35350fc853eSJohn Marino 		/* Convert to wide char form */
35450fc853eSJohn Marino 		conv_mbtowc(&symbol_decimal_point, lc->decimal_point,
35550fc853eSJohn Marino 		    symbol_decimal_point);
35650fc853eSJohn Marino 		conv_mbtowc(&symbol_thousands_sep, lc->thousands_sep,
35750fc853eSJohn Marino 		    symbol_thousands_sep);
35850fc853eSJohn Marino 		conv_mbtowc(&symbol_positive_sign, lc->positive_sign,
35950fc853eSJohn Marino 		    symbol_positive_sign);
36050fc853eSJohn Marino 		conv_mbtowc(&symbol_negative_sign, lc->negative_sign,
36150fc853eSJohn Marino 		    symbol_negative_sign);
36250fc853eSJohn Marino 	}
36350fc853eSJohn Marino 
36450fc853eSJohn Marino 	if (getenv("GNUSORT_NUMERIC_COMPATIBILITY"))
36550fc853eSJohn Marino 		gnusort_numeric_compatibility = true;
36650fc853eSJohn Marino 
36750fc853eSJohn Marino 	locale = setlocale(LC_COLLATE, NULL);
36850fc853eSJohn Marino 
36950fc853eSJohn Marino 	if (locale) {
37050fc853eSJohn Marino 		char *tmpl;
37150fc853eSJohn Marino 		const char *cclocale;
37250fc853eSJohn Marino 
37350fc853eSJohn Marino 		tmpl = sort_strdup(locale);
37450fc853eSJohn Marino 		cclocale = setlocale(LC_COLLATE, "C");
37550fc853eSJohn Marino 		if (cclocale && !strcmp(cclocale, tmpl))
37650fc853eSJohn Marino 			byte_sort = true;
37750fc853eSJohn Marino 		else {
37850fc853eSJohn Marino 			const char *pclocale;
37950fc853eSJohn Marino 
38050fc853eSJohn Marino 			pclocale = setlocale(LC_COLLATE, "POSIX");
38150fc853eSJohn Marino 			if (pclocale && !strcmp(pclocale, tmpl))
38250fc853eSJohn Marino 				byte_sort = true;
38350fc853eSJohn Marino 		}
38450fc853eSJohn Marino 		setlocale(LC_COLLATE, tmpl);
38550fc853eSJohn Marino 		sort_free(tmpl);
38650fc853eSJohn Marino 	}
38750fc853eSJohn Marino }
38850fc853eSJohn Marino 
38950fc853eSJohn Marino /*
39050fc853eSJohn Marino  * Set directory temporary files.
39150fc853eSJohn Marino  */
39250fc853eSJohn Marino static void
set_tmpdir(void)39350fc853eSJohn Marino set_tmpdir(void)
39450fc853eSJohn Marino {
39550fc853eSJohn Marino 	char *td;
39650fc853eSJohn Marino 
39750fc853eSJohn Marino 	td = getenv("TMPDIR");
39850fc853eSJohn Marino 	if (td != NULL)
39950fc853eSJohn Marino 		tmpdir = sort_strdup(td);
40050fc853eSJohn Marino }
40150fc853eSJohn Marino 
40250fc853eSJohn Marino /*
40350fc853eSJohn Marino  * Parse -S option.
40450fc853eSJohn Marino  */
40550fc853eSJohn Marino static unsigned long long
parse_memory_buffer_value(const char * value)40650fc853eSJohn Marino parse_memory_buffer_value(const char *value)
40750fc853eSJohn Marino {
40850fc853eSJohn Marino 
40950fc853eSJohn Marino 	if (value == NULL)
41050fc853eSJohn Marino 		return (available_free_memory);
41150fc853eSJohn Marino 	else {
41250fc853eSJohn Marino 		char *endptr;
41350fc853eSJohn Marino 		unsigned long long membuf;
41450fc853eSJohn Marino 
41550fc853eSJohn Marino 		endptr = NULL;
41650fc853eSJohn Marino 		errno = 0;
41750fc853eSJohn Marino 		membuf = strtoll(value, &endptr, 10);
41850fc853eSJohn Marino 
41950fc853eSJohn Marino 		if (errno != 0) {
42050fc853eSJohn Marino 			warn("%s",getstr(4));
42150fc853eSJohn Marino 			membuf = available_free_memory;
42250fc853eSJohn Marino 		} else {
42350fc853eSJohn Marino 			switch (*endptr){
42450fc853eSJohn Marino 			case 'Y':
42550fc853eSJohn Marino 				membuf *= 1024;
42650fc853eSJohn Marino 				/* FALLTHROUGH */
42750fc853eSJohn Marino 			case 'Z':
42850fc853eSJohn Marino 				membuf *= 1024;
42950fc853eSJohn Marino 				/* FALLTHROUGH */
43050fc853eSJohn Marino 			case 'E':
43150fc853eSJohn Marino 				membuf *= 1024;
43250fc853eSJohn Marino 				/* FALLTHROUGH */
43350fc853eSJohn Marino 			case 'P':
43450fc853eSJohn Marino 				membuf *= 1024;
43550fc853eSJohn Marino 				/* FALLTHROUGH */
43650fc853eSJohn Marino 			case 'T':
43750fc853eSJohn Marino 				membuf *= 1024;
43850fc853eSJohn Marino 				/* FALLTHROUGH */
43950fc853eSJohn Marino 			case 'G':
44050fc853eSJohn Marino 				membuf *= 1024;
44150fc853eSJohn Marino 				/* FALLTHROUGH */
44250fc853eSJohn Marino 			case 'M':
44350fc853eSJohn Marino 				membuf *= 1024;
44450fc853eSJohn Marino 				/* FALLTHROUGH */
44550fc853eSJohn Marino 			case '\0':
44650fc853eSJohn Marino 			case 'K':
44750fc853eSJohn Marino 				membuf *= 1024;
44850fc853eSJohn Marino 				/* FALLTHROUGH */
44950fc853eSJohn Marino 			case 'b':
45050fc853eSJohn Marino 				break;
45150fc853eSJohn Marino 			case '%':
45250fc853eSJohn Marino 				membuf = (available_free_memory * membuf) /
45350fc853eSJohn Marino 				    100;
45450fc853eSJohn Marino 				break;
45550fc853eSJohn Marino 			default:
45650fc853eSJohn Marino 				warnc(EINVAL, "%s", optarg);
45750fc853eSJohn Marino 				membuf = available_free_memory;
45850fc853eSJohn Marino 			}
45950fc853eSJohn Marino 		}
46050fc853eSJohn Marino 		return (membuf);
46150fc853eSJohn Marino 	}
46250fc853eSJohn Marino }
46350fc853eSJohn Marino 
46450fc853eSJohn Marino /*
46550fc853eSJohn Marino  * Signal handler that clears the temporary files.
46650fc853eSJohn Marino  */
46750fc853eSJohn Marino static void
sig_handler(int sig __unused,siginfo_t * siginfo __unused,void * context __unused)46850fc853eSJohn Marino sig_handler(int sig __unused, siginfo_t *siginfo __unused,
46950fc853eSJohn Marino     void *context __unused)
47050fc853eSJohn Marino {
47150fc853eSJohn Marino 
47250fc853eSJohn Marino 	clear_tmp_files();
47350fc853eSJohn Marino 	exit(-1);
47450fc853eSJohn Marino }
47550fc853eSJohn Marino 
47650fc853eSJohn Marino /*
47750fc853eSJohn Marino  * Set signal handler on panic signals.
47850fc853eSJohn Marino  */
47950fc853eSJohn Marino static void
set_signal_handler(void)48050fc853eSJohn Marino set_signal_handler(void)
48150fc853eSJohn Marino {
48250fc853eSJohn Marino 	struct sigaction sa;
48350fc853eSJohn Marino 
48450fc853eSJohn Marino 	memset(&sa, 0, sizeof(sa));
48550fc853eSJohn Marino 	sa.sa_sigaction = &sig_handler;
48650fc853eSJohn Marino 	sa.sa_flags = SA_SIGINFO;
48750fc853eSJohn Marino 
48850fc853eSJohn Marino 	if (sigaction(SIGTERM, &sa, NULL) < 0) {
48950fc853eSJohn Marino 		perror("sigaction");
49050fc853eSJohn Marino 		return;
49150fc853eSJohn Marino 	}
49250fc853eSJohn Marino 	if (sigaction(SIGHUP, &sa, NULL) < 0) {
49350fc853eSJohn Marino 		perror("sigaction");
49450fc853eSJohn Marino 		return;
49550fc853eSJohn Marino 	}
49650fc853eSJohn Marino 	if (sigaction(SIGINT, &sa, NULL) < 0) {
49750fc853eSJohn Marino 		perror("sigaction");
49850fc853eSJohn Marino 		return;
49950fc853eSJohn Marino 	}
50050fc853eSJohn Marino 	if (sigaction(SIGQUIT, &sa, NULL) < 0) {
50150fc853eSJohn Marino 		perror("sigaction");
50250fc853eSJohn Marino 		return;
50350fc853eSJohn Marino 	}
50450fc853eSJohn Marino 	if (sigaction(SIGABRT, &sa, NULL) < 0) {
50550fc853eSJohn Marino 		perror("sigaction");
50650fc853eSJohn Marino 		return;
50750fc853eSJohn Marino 	}
50850fc853eSJohn Marino 	if (sigaction(SIGBUS, &sa, NULL) < 0) {
50950fc853eSJohn Marino 		perror("sigaction");
51050fc853eSJohn Marino 		return;
51150fc853eSJohn Marino 	}
51250fc853eSJohn Marino 	if (sigaction(SIGSEGV, &sa, NULL) < 0) {
51350fc853eSJohn Marino 		perror("sigaction");
51450fc853eSJohn Marino 		return;
51550fc853eSJohn Marino 	}
51650fc853eSJohn Marino 	if (sigaction(SIGUSR1, &sa, NULL) < 0) {
51750fc853eSJohn Marino 		perror("sigaction");
51850fc853eSJohn Marino 		return;
51950fc853eSJohn Marino 	}
52050fc853eSJohn Marino 	if (sigaction(SIGUSR2, &sa, NULL) < 0) {
52150fc853eSJohn Marino 		perror("sigaction");
52250fc853eSJohn Marino 		return;
52350fc853eSJohn Marino 	}
52450fc853eSJohn Marino }
52550fc853eSJohn Marino 
52650fc853eSJohn Marino /*
52750fc853eSJohn Marino  * Print "unknown" message and exit with status 2.
52850fc853eSJohn Marino  */
52950fc853eSJohn Marino static void
unknown(const char * what)53050fc853eSJohn Marino unknown(const char *what)
53150fc853eSJohn Marino {
53250fc853eSJohn Marino 
53350fc853eSJohn Marino 	errx(2, "%s: %s", getstr(3), what);
53450fc853eSJohn Marino }
53550fc853eSJohn Marino 
53650fc853eSJohn Marino /*
53750fc853eSJohn Marino  * Check whether contradictory input options are used.
53850fc853eSJohn Marino  */
53950fc853eSJohn Marino static void
check_mutually_exclusive_flags(char c,bool * mef_flags)54050fc853eSJohn Marino check_mutually_exclusive_flags(char c, bool *mef_flags)
54150fc853eSJohn Marino {
54250fc853eSJohn Marino 	int fo_index, mec;
54350fc853eSJohn Marino 	bool found_others, found_this;
54450fc853eSJohn Marino 
54550fc853eSJohn Marino 	found_others = found_this = false;
54650fc853eSJohn Marino 	fo_index = 0;
54750fc853eSJohn Marino 
54850fc853eSJohn Marino 	for (int i = 0; i < NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS; i++) {
54950fc853eSJohn Marino 		mec = mutually_exclusive_flags[i];
55050fc853eSJohn Marino 
55150fc853eSJohn Marino 		if (mec != c) {
55250fc853eSJohn Marino 			if (mef_flags[i]) {
55350fc853eSJohn Marino 				if (found_this)
55450fc853eSJohn Marino 					errx(1, "%c:%c: %s", c, mec, getstr(1));
55550fc853eSJohn Marino 				found_others = true;
55650fc853eSJohn Marino 				fo_index = i;
55750fc853eSJohn Marino 			}
55850fc853eSJohn Marino 		} else {
55950fc853eSJohn Marino 			if (found_others)
56050fc853eSJohn Marino 				errx(1, "%c:%c: %s", c, mutually_exclusive_flags[fo_index], getstr(1));
56150fc853eSJohn Marino 			mef_flags[i] = true;
56250fc853eSJohn Marino 			found_this = true;
56350fc853eSJohn Marino 		}
56450fc853eSJohn Marino 	}
56550fc853eSJohn Marino }
56650fc853eSJohn Marino 
56750fc853eSJohn Marino /*
56850fc853eSJohn Marino  * Initialise sort opts data.
56950fc853eSJohn Marino  */
57050fc853eSJohn Marino static void
set_sort_opts(void)57150fc853eSJohn Marino set_sort_opts(void)
57250fc853eSJohn Marino {
57350fc853eSJohn Marino 
57450fc853eSJohn Marino 	memset(&default_sort_mods_object, 0,
57550fc853eSJohn Marino 	    sizeof(default_sort_mods_object));
57650fc853eSJohn Marino 	memset(&sort_opts_vals, 0, sizeof(sort_opts_vals));
57750fc853eSJohn Marino 	default_sort_mods_object.func =
57850fc853eSJohn Marino 	    get_sort_func(&default_sort_mods_object);
57950fc853eSJohn Marino }
58050fc853eSJohn Marino 
58150fc853eSJohn Marino /*
58250fc853eSJohn Marino  * Set a sort modifier on a sort modifiers object.
58350fc853eSJohn Marino  */
58450fc853eSJohn Marino static bool
set_sort_modifier(struct sort_mods * sm,int c)58550fc853eSJohn Marino set_sort_modifier(struct sort_mods *sm, int c)
58650fc853eSJohn Marino {
58750fc853eSJohn Marino 
58850fc853eSJohn Marino 	if (sm) {
58950fc853eSJohn Marino 		switch (c){
59050fc853eSJohn Marino 		case 'b':
59150fc853eSJohn Marino 			sm->bflag = true;
59250fc853eSJohn Marino 			break;
59350fc853eSJohn Marino 		case 'd':
59450fc853eSJohn Marino 			sm->dflag = true;
59550fc853eSJohn Marino 			break;
59650fc853eSJohn Marino 		case 'f':
59750fc853eSJohn Marino 			sm->fflag = true;
59850fc853eSJohn Marino 			break;
59950fc853eSJohn Marino 		case 'g':
60050fc853eSJohn Marino 			sm->gflag = true;
60150fc853eSJohn Marino 			need_hint = true;
60250fc853eSJohn Marino 			break;
60350fc853eSJohn Marino 		case 'i':
60450fc853eSJohn Marino 			sm->iflag = true;
60550fc853eSJohn Marino 			break;
6066d7e22ecSzrj #ifdef SORT_RANDOM
60750fc853eSJohn Marino 		case 'R':
60850fc853eSJohn Marino 			sm->Rflag = true;
60950fc853eSJohn Marino 			need_random = true;
61050fc853eSJohn Marino 			break;
6116d7e22ecSzrj #endif
61250fc853eSJohn Marino 		case 'M':
61350fc853eSJohn Marino 			initialise_months();
61450fc853eSJohn Marino 			sm->Mflag = true;
61550fc853eSJohn Marino 			need_hint = true;
61650fc853eSJohn Marino 			break;
61750fc853eSJohn Marino 		case 'n':
61850fc853eSJohn Marino 			sm->nflag = true;
61950fc853eSJohn Marino 			need_hint = true;
62050fc853eSJohn Marino 			print_symbols_on_debug = true;
62150fc853eSJohn Marino 			break;
62250fc853eSJohn Marino 		case 'r':
62350fc853eSJohn Marino 			sm->rflag = true;
62450fc853eSJohn Marino 			break;
62550fc853eSJohn Marino 		case 'V':
62650fc853eSJohn Marino 			sm->Vflag = true;
62750fc853eSJohn Marino 			break;
62850fc853eSJohn Marino 		case 'h':
62950fc853eSJohn Marino 			sm->hflag = true;
63050fc853eSJohn Marino 			need_hint = true;
63150fc853eSJohn Marino 			print_symbols_on_debug = true;
63250fc853eSJohn Marino 			break;
63350fc853eSJohn Marino 		default:
63450fc853eSJohn Marino 			return false;
63550fc853eSJohn Marino 		}
63650fc853eSJohn Marino 		sort_opts_vals.complex_sort = true;
63750fc853eSJohn Marino 		sm->func = get_sort_func(sm);
63850fc853eSJohn Marino 	}
63950fc853eSJohn Marino 	return (true);
64050fc853eSJohn Marino }
64150fc853eSJohn Marino 
64250fc853eSJohn Marino /*
64350fc853eSJohn Marino  * Parse POS in -k option.
64450fc853eSJohn Marino  */
64550fc853eSJohn Marino static int
parse_pos(const char * s,struct key_specs * ks,bool * mef_flags,bool second)64650fc853eSJohn Marino parse_pos(const char *s, struct key_specs *ks, bool *mef_flags, bool second)
64750fc853eSJohn Marino {
64850fc853eSJohn Marino 	regmatch_t pmatch[4];
64950fc853eSJohn Marino 	regex_t re;
65050fc853eSJohn Marino 	char *c, *f;
65150fc853eSJohn Marino 	const char *sregexp = "^([0-9]+)(\\.[0-9]+)?([bdfirMngRhV]+)?$";
65250fc853eSJohn Marino 	size_t len, nmatch;
65350fc853eSJohn Marino 	int ret;
65450fc853eSJohn Marino 
65550fc853eSJohn Marino 	ret = -1;
65650fc853eSJohn Marino 	nmatch = 4;
65750fc853eSJohn Marino 	c = f = NULL;
65850fc853eSJohn Marino 
65950fc853eSJohn Marino 	if (regcomp(&re, sregexp, REG_EXTENDED) != 0)
66050fc853eSJohn Marino 		return (-1);
66150fc853eSJohn Marino 
66250fc853eSJohn Marino 	if (regexec(&re, s, nmatch, pmatch, 0) != 0)
66350fc853eSJohn Marino 		goto end;
66450fc853eSJohn Marino 
66550fc853eSJohn Marino 	if (pmatch[0].rm_eo <= pmatch[0].rm_so)
66650fc853eSJohn Marino 		goto end;
66750fc853eSJohn Marino 
66850fc853eSJohn Marino 	if (pmatch[1].rm_eo <= pmatch[1].rm_so)
66950fc853eSJohn Marino 		goto end;
67050fc853eSJohn Marino 
67150fc853eSJohn Marino 	len = pmatch[1].rm_eo - pmatch[1].rm_so;
67250fc853eSJohn Marino 	f = sort_malloc((len + 1) * sizeof(char));
67350fc853eSJohn Marino 
67450fc853eSJohn Marino 	strncpy(f, s + pmatch[1].rm_so, len);
67550fc853eSJohn Marino 	f[len] = '\0';
67650fc853eSJohn Marino 
67750fc853eSJohn Marino 	if (second) {
67850fc853eSJohn Marino 		errno = 0;
67950fc853eSJohn Marino 		ks->f2 = (size_t) strtoul(f, NULL, 10);
68050fc853eSJohn Marino 		if (errno != 0)
68150fc853eSJohn Marino 			err(2, "-k");
68250fc853eSJohn Marino 		if (ks->f2 == 0) {
68350fc853eSJohn Marino 			warn("%s",getstr(5));
68450fc853eSJohn Marino 			goto end;
68550fc853eSJohn Marino 		}
68650fc853eSJohn Marino 	} else {
68750fc853eSJohn Marino 		errno = 0;
68850fc853eSJohn Marino 		ks->f1 = (size_t) strtoul(f, NULL, 10);
68950fc853eSJohn Marino 		if (errno != 0)
69050fc853eSJohn Marino 			err(2, "-k");
69150fc853eSJohn Marino 		if (ks->f1 == 0) {
69250fc853eSJohn Marino 			warn("%s",getstr(5));
69350fc853eSJohn Marino 			goto end;
69450fc853eSJohn Marino 		}
69550fc853eSJohn Marino 	}
69650fc853eSJohn Marino 
69750fc853eSJohn Marino 	if (pmatch[2].rm_eo > pmatch[2].rm_so) {
69850fc853eSJohn Marino 		len = pmatch[2].rm_eo - pmatch[2].rm_so - 1;
69950fc853eSJohn Marino 		c = sort_malloc((len + 1) * sizeof(char));
70050fc853eSJohn Marino 
70150fc853eSJohn Marino 		strncpy(c, s + pmatch[2].rm_so + 1, len);
70250fc853eSJohn Marino 		c[len] = '\0';
70350fc853eSJohn Marino 
70450fc853eSJohn Marino 		if (second) {
70550fc853eSJohn Marino 			errno = 0;
70650fc853eSJohn Marino 			ks->c2 = (size_t) strtoul(c, NULL, 10);
70750fc853eSJohn Marino 			if (errno != 0)
70850fc853eSJohn Marino 				err(2, "-k");
70950fc853eSJohn Marino 		} else {
71050fc853eSJohn Marino 			errno = 0;
71150fc853eSJohn Marino 			ks->c1 = (size_t) strtoul(c, NULL, 10);
71250fc853eSJohn Marino 			if (errno != 0)
71350fc853eSJohn Marino 				err(2, "-k");
71450fc853eSJohn Marino 			if (ks->c1 == 0) {
71550fc853eSJohn Marino 				warn("%s",getstr(6));
71650fc853eSJohn Marino 				goto end;
71750fc853eSJohn Marino 			}
71850fc853eSJohn Marino 		}
71950fc853eSJohn Marino 	} else {
72050fc853eSJohn Marino 		if (second)
72150fc853eSJohn Marino 			ks->c2 = 0;
72250fc853eSJohn Marino 		else
72350fc853eSJohn Marino 			ks->c1 = 1;
72450fc853eSJohn Marino 	}
72550fc853eSJohn Marino 
72650fc853eSJohn Marino 	if (pmatch[3].rm_eo > pmatch[3].rm_so) {
72750fc853eSJohn Marino 		regoff_t i = 0;
72850fc853eSJohn Marino 
72950fc853eSJohn Marino 		for (i = pmatch[3].rm_so; i < pmatch[3].rm_eo; i++) {
73050fc853eSJohn Marino 			check_mutually_exclusive_flags(s[i], mef_flags);
73150fc853eSJohn Marino 			if (s[i] == 'b') {
73250fc853eSJohn Marino 				if (second)
73350fc853eSJohn Marino 					ks->pos2b = true;
73450fc853eSJohn Marino 				else
73550fc853eSJohn Marino 					ks->pos1b = true;
73650fc853eSJohn Marino 			} else if (!set_sort_modifier(&(ks->sm), s[i]))
73750fc853eSJohn Marino 				goto end;
73850fc853eSJohn Marino 		}
73950fc853eSJohn Marino 	}
74050fc853eSJohn Marino 
74150fc853eSJohn Marino 	ret = 0;
74250fc853eSJohn Marino 
74350fc853eSJohn Marino end:
74450fc853eSJohn Marino 
74550fc853eSJohn Marino 	if (c)
74650fc853eSJohn Marino 		sort_free(c);
74750fc853eSJohn Marino 	if (f)
74850fc853eSJohn Marino 		sort_free(f);
74950fc853eSJohn Marino 	regfree(&re);
75050fc853eSJohn Marino 
75150fc853eSJohn Marino 	return (ret);
75250fc853eSJohn Marino }
75350fc853eSJohn Marino 
75450fc853eSJohn Marino /*
75550fc853eSJohn Marino  * Parse -k option value.
75650fc853eSJohn Marino  */
75750fc853eSJohn Marino static int
parse_k(const char * s,struct key_specs * ks)75850fc853eSJohn Marino parse_k(const char *s, struct key_specs *ks)
75950fc853eSJohn Marino {
76050fc853eSJohn Marino 	int ret = -1;
76150fc853eSJohn Marino 	bool mef_flags[NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS] =
76250fc853eSJohn Marino 	    { false, false, false, false, false, false };
76350fc853eSJohn Marino 
76450fc853eSJohn Marino 	if (s && *s) {
76550fc853eSJohn Marino 		char *sptr;
76650fc853eSJohn Marino 
76750fc853eSJohn Marino 		sptr = strchr(s, ',');
76850fc853eSJohn Marino 		if (sptr) {
76950fc853eSJohn Marino 			size_t size1;
77050fc853eSJohn Marino 			char *pos1, *pos2;
77150fc853eSJohn Marino 
77250fc853eSJohn Marino 			size1 = sptr - s;
77350fc853eSJohn Marino 
77450fc853eSJohn Marino 			if (size1 < 1)
77550fc853eSJohn Marino 				return (-1);
77650fc853eSJohn Marino 			pos1 = sort_malloc((size1 + 1) * sizeof(char));
77750fc853eSJohn Marino 
77850fc853eSJohn Marino 			strncpy(pos1, s, size1);
77950fc853eSJohn Marino 			pos1[size1] = '\0';
78050fc853eSJohn Marino 
78150fc853eSJohn Marino 			ret = parse_pos(pos1, ks, mef_flags, false);
78250fc853eSJohn Marino 
78350fc853eSJohn Marino 			sort_free(pos1);
78450fc853eSJohn Marino 			if (ret < 0)
78550fc853eSJohn Marino 				return (ret);
78650fc853eSJohn Marino 
78750fc853eSJohn Marino 			pos2 = sort_strdup(sptr + 1);
78850fc853eSJohn Marino 			ret = parse_pos(pos2, ks, mef_flags, true);
78950fc853eSJohn Marino 			sort_free(pos2);
79050fc853eSJohn Marino 		} else
79150fc853eSJohn Marino 			ret = parse_pos(s, ks, mef_flags, false);
79250fc853eSJohn Marino 	}
79350fc853eSJohn Marino 
79450fc853eSJohn Marino 	return (ret);
79550fc853eSJohn Marino }
79650fc853eSJohn Marino 
79750fc853eSJohn Marino /*
79850fc853eSJohn Marino  * Parse POS in +POS -POS option.
79950fc853eSJohn Marino  */
80050fc853eSJohn Marino static int
parse_pos_obs(const char * s,int * nf,int * nc,char * sopts)80150fc853eSJohn Marino parse_pos_obs(const char *s, int *nf, int *nc, char* sopts)
80250fc853eSJohn Marino {
80350fc853eSJohn Marino 	regex_t re;
80450fc853eSJohn Marino 	regmatch_t pmatch[4];
80550fc853eSJohn Marino 	char *c, *f;
80650fc853eSJohn Marino 	const char *sregexp = "^([0-9]+)(\\.[0-9]+)?([A-Za-z]+)?$";
80750fc853eSJohn Marino 	int ret;
80850fc853eSJohn Marino 	size_t len, nmatch;
80950fc853eSJohn Marino 
81050fc853eSJohn Marino 	ret = -1;
81150fc853eSJohn Marino 	nmatch = 4;
81250fc853eSJohn Marino 	c = f = NULL;
81350fc853eSJohn Marino 	*nc = *nf = 0;
81450fc853eSJohn Marino 
81550fc853eSJohn Marino 	if (regcomp(&re, sregexp, REG_EXTENDED) != 0)
81650fc853eSJohn Marino 		return (-1);
81750fc853eSJohn Marino 
81850fc853eSJohn Marino 	if (regexec(&re, s, nmatch, pmatch, 0) != 0)
81950fc853eSJohn Marino 		goto end;
82050fc853eSJohn Marino 
82150fc853eSJohn Marino 	if (pmatch[0].rm_eo <= pmatch[0].rm_so)
82250fc853eSJohn Marino 		goto end;
82350fc853eSJohn Marino 
82450fc853eSJohn Marino 	if (pmatch[1].rm_eo <= pmatch[1].rm_so)
82550fc853eSJohn Marino 		goto end;
82650fc853eSJohn Marino 
82750fc853eSJohn Marino 	len = pmatch[1].rm_eo - pmatch[1].rm_so;
82850fc853eSJohn Marino 	f = sort_malloc((len + 1) * sizeof(char));
82950fc853eSJohn Marino 
83050fc853eSJohn Marino 	strncpy(f, s + pmatch[1].rm_so, len);
83150fc853eSJohn Marino 	f[len] = '\0';
83250fc853eSJohn Marino 
83350fc853eSJohn Marino 	errno = 0;
83450fc853eSJohn Marino 	*nf = (size_t) strtoul(f, NULL, 10);
83550fc853eSJohn Marino 	if (errno != 0)
83650fc853eSJohn Marino 		errx(2, "%s", getstr(11));
83750fc853eSJohn Marino 
83850fc853eSJohn Marino 	if (pmatch[2].rm_eo > pmatch[2].rm_so) {
83950fc853eSJohn Marino 		len = pmatch[2].rm_eo - pmatch[2].rm_so - 1;
84050fc853eSJohn Marino 		c = sort_malloc((len + 1) * sizeof(char));
84150fc853eSJohn Marino 
84250fc853eSJohn Marino 		strncpy(c, s + pmatch[2].rm_so + 1, len);
84350fc853eSJohn Marino 		c[len] = '\0';
84450fc853eSJohn Marino 
84550fc853eSJohn Marino 		errno = 0;
84650fc853eSJohn Marino 		*nc = (size_t) strtoul(c, NULL, 10);
84750fc853eSJohn Marino 		if (errno != 0)
84850fc853eSJohn Marino 			errx(2, "%s", getstr(11));
84950fc853eSJohn Marino 	}
85050fc853eSJohn Marino 
85150fc853eSJohn Marino 	if (pmatch[3].rm_eo > pmatch[3].rm_so) {
85250fc853eSJohn Marino 
85350fc853eSJohn Marino 		len = pmatch[3].rm_eo - pmatch[3].rm_so;
85450fc853eSJohn Marino 
85550fc853eSJohn Marino 		strncpy(sopts, s + pmatch[3].rm_so, len);
85650fc853eSJohn Marino 		sopts[len] = '\0';
85750fc853eSJohn Marino 	}
85850fc853eSJohn Marino 
85950fc853eSJohn Marino 	ret = 0;
86050fc853eSJohn Marino 
86150fc853eSJohn Marino end:
86250fc853eSJohn Marino 	if (c)
86350fc853eSJohn Marino 		sort_free(c);
86450fc853eSJohn Marino 	if (f)
86550fc853eSJohn Marino 		sort_free(f);
86650fc853eSJohn Marino 	regfree(&re);
86750fc853eSJohn Marino 
86850fc853eSJohn Marino 	return (ret);
86950fc853eSJohn Marino }
87050fc853eSJohn Marino 
87150fc853eSJohn Marino /*
87250fc853eSJohn Marino  * "Translate" obsolete +POS1 -POS2 syntax into new -kPOS1,POS2 syntax
87350fc853eSJohn Marino  */
874aa348a5cSzrj static void
fix_obsolete_keys(int * argc,char ** argv)87550fc853eSJohn Marino fix_obsolete_keys(int *argc, char **argv)
87650fc853eSJohn Marino {
877aa348a5cSzrj 	char *snew = NULL;
87850fc853eSJohn Marino 
87950fc853eSJohn Marino 	for (int i = 1; i < *argc; i++) {
88050fc853eSJohn Marino 		char *arg1;
88150fc853eSJohn Marino 
88250fc853eSJohn Marino 		arg1 = argv[i];
88350fc853eSJohn Marino 
88450fc853eSJohn Marino 		if (strlen(arg1) > 1 && arg1[0] == '+') {
88550fc853eSJohn Marino 			int c1, f1;
88650fc853eSJohn Marino 			char sopts1[128];
88750fc853eSJohn Marino 
88850fc853eSJohn Marino 			sopts1[0] = 0;
88950fc853eSJohn Marino 			c1 = f1 = 0;
89050fc853eSJohn Marino 
89150fc853eSJohn Marino 			if (parse_pos_obs(arg1 + 1, &f1, &c1, sopts1) < 0)
89250fc853eSJohn Marino 				continue;
89350fc853eSJohn Marino 			else {
89450fc853eSJohn Marino 				f1 += 1;
89550fc853eSJohn Marino 				c1 += 1;
89650fc853eSJohn Marino 				if (i + 1 < *argc) {
89750fc853eSJohn Marino 					char *arg2 = argv[i + 1];
89850fc853eSJohn Marino 
89950fc853eSJohn Marino 					if (strlen(arg2) > 1 &&
90050fc853eSJohn Marino 					    arg2[0] == '-') {
90150fc853eSJohn Marino 						int c2, f2;
90250fc853eSJohn Marino 						char sopts2[128];
90350fc853eSJohn Marino 
90450fc853eSJohn Marino 						sopts2[0] = 0;
90550fc853eSJohn Marino 						c2 = f2 = 0;
90650fc853eSJohn Marino 
90750fc853eSJohn Marino 						if (parse_pos_obs(arg2 + 1,
90850fc853eSJohn Marino 						    &f2, &c2, sopts2) >= 0) {
90950fc853eSJohn Marino 							if (c2 > 0)
91050fc853eSJohn Marino 								f2 += 1;
911aa348a5cSzrj 							if (asprintf(&snew,
912aa348a5cSzrj 							    "-k%d.%d%s,%d.%d%s",
913aa348a5cSzrj 							    f1, c1, sopts1,
914aa348a5cSzrj 							    f2, c2, sopts2)== -1)
915aa348a5cSzrj 								return;
916aa348a5cSzrj 							argv[i] = snew;
91750fc853eSJohn Marino 							for (int j = i + 1; j + 1 < *argc; j++)
91850fc853eSJohn Marino 								argv[j] = argv[j + 1];
91950fc853eSJohn Marino 							*argc -= 1;
92050fc853eSJohn Marino 							continue;
92150fc853eSJohn Marino 						}
92250fc853eSJohn Marino 					}
92350fc853eSJohn Marino 				}
924aa348a5cSzrj 				asprintf(&snew, "-k%d.%d%s", f1, c1, sopts1);
925aa348a5cSzrj 				argv[i] = snew;
92650fc853eSJohn Marino 			}
92750fc853eSJohn Marino 		}
92850fc853eSJohn Marino 	}
92950fc853eSJohn Marino }
93050fc853eSJohn Marino 
93150fc853eSJohn Marino /*
93250fc853eSJohn Marino  * Set random seed
93350fc853eSJohn Marino  */
9346d7e22ecSzrj #if defined(SORT_RANDOM)
935*a98f7024Szrj static char *
random_md5end(MD5_CTX * ctx)936*a98f7024Szrj random_md5end(MD5_CTX *ctx)
937*a98f7024Szrj {
938*a98f7024Szrj 	unsigned char digest[MD5_DIGEST_LENGTH];
939*a98f7024Szrj 	static const char hex[]="0123456789abcdef";
940*a98f7024Szrj 	char *buf;
941*a98f7024Szrj 	int i;
942*a98f7024Szrj 
943*a98f7024Szrj 	buf = malloc(MD5_DIGEST_LENGTH * 2 + 1);
944*a98f7024Szrj 	if (!buf)
945*a98f7024Szrj 		return NULL;
946*a98f7024Szrj 	MD5_Final(digest, ctx);
947*a98f7024Szrj 	for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
948*a98f7024Szrj 		buf[2*i] = hex[digest[i] >> 4];
949*a98f7024Szrj 		buf[2*i+1] = hex[digest[i] & 0x0f];
950*a98f7024Szrj 	}
951*a98f7024Szrj 	buf[MD5_DIGEST_LENGTH * 2] = '\0';
952*a98f7024Szrj 	return buf;
953*a98f7024Szrj }
954*a98f7024Szrj 
955*a98f7024Szrj static char *
random_fromfile(const char * filename)956*a98f7024Szrj random_fromfile(const char *filename)
957*a98f7024Szrj {
958*a98f7024Szrj 	MD5_CTX ctx;
959*a98f7024Szrj 	FILE* fp;
960*a98f7024Szrj 	unsigned char buffer[4096];
961*a98f7024Szrj 	struct stat st;
962*a98f7024Szrj 	off_t size;
963*a98f7024Szrj 	int bytes;
964*a98f7024Szrj 
965*a98f7024Szrj 	fp = openfile(filename, "r");
966*a98f7024Szrj 	if (fp == NULL)
967*a98f7024Szrj 		return NULL;
968*a98f7024Szrj 	if (fstat(fileno(fp), &st) < 0) {
969*a98f7024Szrj 		bytes = -1;
970*a98f7024Szrj 		goto err;
971*a98f7024Szrj 	}
972*a98f7024Szrj 
973*a98f7024Szrj 	MD5_Init(&ctx);
974*a98f7024Szrj 	size = st.st_size;
975*a98f7024Szrj 	bytes = 0;
976*a98f7024Szrj 	while (size > 0 && (bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
977*a98f7024Szrj 		MD5_Update(&ctx, buffer, bytes);
978*a98f7024Szrj 		size -= bytes;
979*a98f7024Szrj 	}
980*a98f7024Szrj 
981*a98f7024Szrj err:
982*a98f7024Szrj 	closefile(fp, NULL);
983*a98f7024Szrj 	if (bytes < 0)
984*a98f7024Szrj 		return NULL;
985*a98f7024Szrj 
986*a98f7024Szrj 	return (random_md5end(&ctx));
987*a98f7024Szrj }
988*a98f7024Szrj 
98950fc853eSJohn Marino static void
set_random_seed(void)99050fc853eSJohn Marino set_random_seed(void)
99150fc853eSJohn Marino {
99250fc853eSJohn Marino 	if (need_random) {
99350fc853eSJohn Marino 
99450fc853eSJohn Marino 		if (strcmp(random_source, DEFAULT_RANDOM_SORT_SEED_FILE) == 0) {
99550fc853eSJohn Marino 			FILE* fseed;
99650fc853eSJohn Marino 			MD5_CTX ctx;
99750fc853eSJohn Marino 			char rsd[MAX_DEFAULT_RANDOM_SEED_DATA_SIZE];
99850fc853eSJohn Marino 			size_t sz = 0;
99950fc853eSJohn Marino 
100050fc853eSJohn Marino 			fseed = openfile(random_source, "r");
100150fc853eSJohn Marino 			while (!feof(fseed)) {
100250fc853eSJohn Marino 				int cr;
100350fc853eSJohn Marino 
100450fc853eSJohn Marino 				cr = fgetc(fseed);
100550fc853eSJohn Marino 				if (cr == EOF)
100650fc853eSJohn Marino 					break;
100750fc853eSJohn Marino 
100850fc853eSJohn Marino 				rsd[sz++] = (char) cr;
100950fc853eSJohn Marino 
101050fc853eSJohn Marino 				if (sz >= MAX_DEFAULT_RANDOM_SEED_DATA_SIZE)
101150fc853eSJohn Marino 					break;
101250fc853eSJohn Marino 			}
101350fc853eSJohn Marino 
101450fc853eSJohn Marino 			closefile(fseed, random_source);
101550fc853eSJohn Marino 
1016*a98f7024Szrj 			MD5_Init(&ctx);
1017*a98f7024Szrj 			MD5_Update(&ctx, rsd, sz);
101850fc853eSJohn Marino 
1019*a98f7024Szrj 			random_seed = random_md5end(&ctx);
102050fc853eSJohn Marino 			random_seed_size = strlen(random_seed);
102150fc853eSJohn Marino 
102250fc853eSJohn Marino 		} else {
102350fc853eSJohn Marino 			MD5_CTX ctx;
102450fc853eSJohn Marino 			char *b;
102550fc853eSJohn Marino 
1026*a98f7024Szrj 			MD5_Init(&ctx);
1027*a98f7024Szrj 			b = random_fromfile(random_source);
102850fc853eSJohn Marino 			if (b == NULL)
102950fc853eSJohn Marino 				err(2, NULL);
103050fc853eSJohn Marino 
103150fc853eSJohn Marino 			random_seed = b;
103250fc853eSJohn Marino 			random_seed_size = strlen(b);
103350fc853eSJohn Marino 		}
103450fc853eSJohn Marino 
1035*a98f7024Szrj 		MD5_Init(&md5_ctx);
103650fc853eSJohn Marino 		if(random_seed_size>0) {
1037*a98f7024Szrj 			MD5_Update(&md5_ctx, random_seed, random_seed_size);
103850fc853eSJohn Marino 		}
103950fc853eSJohn Marino 	}
104050fc853eSJohn Marino }
10416d7e22ecSzrj #endif
104250fc853eSJohn Marino 
104350fc853eSJohn Marino /*
104450fc853eSJohn Marino  * Main function.
104550fc853eSJohn Marino  */
104650fc853eSJohn Marino int
main(int argc,char ** argv)104750fc853eSJohn Marino main(int argc, char **argv)
104850fc853eSJohn Marino {
104950fc853eSJohn Marino 	char *outfile, *real_outfile;
105050fc853eSJohn Marino 	int c, result;
105150fc853eSJohn Marino 	bool mef_flags[NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS] =
105250fc853eSJohn Marino 	    { false, false, false, false, false, false };
105350fc853eSJohn Marino 
105450fc853eSJohn Marino 	result = 0;
105550fc853eSJohn Marino 	outfile = sort_strdup("-");
105650fc853eSJohn Marino 	real_outfile = NULL;
105750fc853eSJohn Marino 
105850fc853eSJohn Marino 	struct sort_mods *sm = &default_sort_mods_object;
105950fc853eSJohn Marino 
106050fc853eSJohn Marino 	init_tmp_files();
106150fc853eSJohn Marino 
106250fc853eSJohn Marino 	set_signal_handler();
106350fc853eSJohn Marino 
106450fc853eSJohn Marino 	set_hw_params();
106550fc853eSJohn Marino 	set_locale();
106650fc853eSJohn Marino 	set_tmpdir();
106750fc853eSJohn Marino 	set_sort_opts();
106850fc853eSJohn Marino 
106950fc853eSJohn Marino 	fix_obsolete_keys(&argc, argv);
107050fc853eSJohn Marino 
107150fc853eSJohn Marino 	while (((c = getopt_long(argc, argv, OPTIONS, long_options, NULL))
107250fc853eSJohn Marino 	    != -1)) {
107350fc853eSJohn Marino 
107450fc853eSJohn Marino 		check_mutually_exclusive_flags(c, mef_flags);
107550fc853eSJohn Marino 
107650fc853eSJohn Marino 		if (!set_sort_modifier(sm, c)) {
107750fc853eSJohn Marino 
107850fc853eSJohn Marino 			switch (c) {
107950fc853eSJohn Marino 			case 'c':
108050fc853eSJohn Marino 				sort_opts_vals.cflag = true;
108150fc853eSJohn Marino 				if (optarg) {
108250fc853eSJohn Marino 					if (!strcmp(optarg, "diagnose-first"))
108350fc853eSJohn Marino 						;
108450fc853eSJohn Marino 					else if (!strcmp(optarg, "silent") ||
108550fc853eSJohn Marino 					    !strcmp(optarg, "quiet"))
108650fc853eSJohn Marino 						sort_opts_vals.csilentflag = true;
108750fc853eSJohn Marino 					else if (*optarg)
108850fc853eSJohn Marino 						unknown(optarg);
108950fc853eSJohn Marino 				}
109050fc853eSJohn Marino 				break;
109150fc853eSJohn Marino 			case 'C':
109250fc853eSJohn Marino 				sort_opts_vals.cflag = true;
109350fc853eSJohn Marino 				sort_opts_vals.csilentflag = true;
109450fc853eSJohn Marino 				break;
109550fc853eSJohn Marino 			case 'k':
109650fc853eSJohn Marino 			{
109750fc853eSJohn Marino 				sort_opts_vals.complex_sort = true;
109850fc853eSJohn Marino 				sort_opts_vals.kflag = true;
109950fc853eSJohn Marino 
110050fc853eSJohn Marino 				keys_num++;
110150fc853eSJohn Marino 				keys = sort_realloc(keys, keys_num *
110250fc853eSJohn Marino 				    sizeof(struct key_specs));
110350fc853eSJohn Marino 				memset(&(keys[keys_num - 1]), 0,
110450fc853eSJohn Marino 				    sizeof(struct key_specs));
110550fc853eSJohn Marino 
110650fc853eSJohn Marino 				if (parse_k(optarg, &(keys[keys_num - 1]))
110750fc853eSJohn Marino 				    < 0) {
110850fc853eSJohn Marino 					errc(2, EINVAL, "-k %s", optarg);
110950fc853eSJohn Marino 				}
111050fc853eSJohn Marino 
111150fc853eSJohn Marino 				break;
111250fc853eSJohn Marino 			}
111350fc853eSJohn Marino 			case 'm':
111450fc853eSJohn Marino 				sort_opts_vals.mflag = true;
111550fc853eSJohn Marino 				break;
111650fc853eSJohn Marino 			case 'o':
111750fc853eSJohn Marino 				outfile = sort_realloc(outfile, (strlen(optarg) + 1));
111850fc853eSJohn Marino 				strcpy(outfile, optarg);
111950fc853eSJohn Marino 				break;
112050fc853eSJohn Marino 			case 's':
112150fc853eSJohn Marino 				sort_opts_vals.sflag = true;
112250fc853eSJohn Marino 				break;
112350fc853eSJohn Marino 			case 'S':
112450fc853eSJohn Marino 				available_free_memory =
112550fc853eSJohn Marino 				    parse_memory_buffer_value(optarg);
112650fc853eSJohn Marino 				break;
112750fc853eSJohn Marino 			case 'T':
112850fc853eSJohn Marino 				tmpdir = sort_strdup(optarg);
112950fc853eSJohn Marino 				break;
113050fc853eSJohn Marino 			case 't':
113150fc853eSJohn Marino 				while (strlen(optarg) > 1) {
113250fc853eSJohn Marino 					if (optarg[0] != '\\') {
113350fc853eSJohn Marino 						errc(2, EINVAL, "%s", optarg);
113450fc853eSJohn Marino 					}
113550fc853eSJohn Marino 					optarg += 1;
113650fc853eSJohn Marino 					if (*optarg == '0') {
113750fc853eSJohn Marino 						*optarg = 0;
113850fc853eSJohn Marino 						break;
113950fc853eSJohn Marino 					}
114050fc853eSJohn Marino 				}
114150fc853eSJohn Marino 				sort_opts_vals.tflag = true;
114250fc853eSJohn Marino 				sort_opts_vals.field_sep = btowc(optarg[0]);
114350fc853eSJohn Marino 				if (sort_opts_vals.field_sep == WEOF) {
114450fc853eSJohn Marino 					errno = EINVAL;
114550fc853eSJohn Marino 					err(2, NULL);
114650fc853eSJohn Marino 				}
114750fc853eSJohn Marino 				if (!gnusort_numeric_compatibility) {
114850fc853eSJohn Marino 					if (symbol_decimal_point == sort_opts_vals.field_sep)
114950fc853eSJohn Marino 						symbol_decimal_point = WEOF;
115050fc853eSJohn Marino 					if (symbol_thousands_sep == sort_opts_vals.field_sep)
115150fc853eSJohn Marino 						symbol_thousands_sep = WEOF;
115250fc853eSJohn Marino 					if (symbol_negative_sign == sort_opts_vals.field_sep)
115350fc853eSJohn Marino 						symbol_negative_sign = WEOF;
115450fc853eSJohn Marino 					if (symbol_positive_sign == sort_opts_vals.field_sep)
115550fc853eSJohn Marino 						symbol_positive_sign = WEOF;
115650fc853eSJohn Marino 				}
115750fc853eSJohn Marino 				break;
115850fc853eSJohn Marino 			case 'u':
115950fc853eSJohn Marino 				sort_opts_vals.uflag = true;
116050fc853eSJohn Marino 				/* stable sort for the correct unique val */
116150fc853eSJohn Marino 				sort_opts_vals.sflag = true;
116250fc853eSJohn Marino 				break;
116350fc853eSJohn Marino 			case 'z':
116450fc853eSJohn Marino 				sort_opts_vals.zflag = true;
116550fc853eSJohn Marino 				break;
116650fc853eSJohn Marino 			case SORT_OPT:
116750fc853eSJohn Marino 				if (optarg) {
116850fc853eSJohn Marino 					if (!strcmp(optarg, "general-numeric"))
116950fc853eSJohn Marino 						set_sort_modifier(sm, 'g');
117050fc853eSJohn Marino 					else if (!strcmp(optarg, "human-numeric"))
117150fc853eSJohn Marino 						set_sort_modifier(sm, 'h');
117250fc853eSJohn Marino 					else if (!strcmp(optarg, "numeric"))
117350fc853eSJohn Marino 						set_sort_modifier(sm, 'n');
117450fc853eSJohn Marino 					else if (!strcmp(optarg, "month"))
117550fc853eSJohn Marino 						set_sort_modifier(sm, 'M');
11766d7e22ecSzrj #if defined(SORT_RANDOM)
117750fc853eSJohn Marino 					else if (!strcmp(optarg, "random"))
117850fc853eSJohn Marino 						set_sort_modifier(sm, 'R');
11796d7e22ecSzrj #endif
118050fc853eSJohn Marino 					else
118150fc853eSJohn Marino 						unknown(optarg);
118250fc853eSJohn Marino 				}
118350fc853eSJohn Marino 				break;
118450fc853eSJohn Marino #if defined(SORT_THREADS)
118550fc853eSJohn Marino 			case PARALLEL_OPT:
118650fc853eSJohn Marino 				nthreads = (size_t)(atoi(optarg));
118750fc853eSJohn Marino 				if (nthreads < 1)
118850fc853eSJohn Marino 					nthreads = 1;
118950fc853eSJohn Marino 				if (nthreads > 1024)
119050fc853eSJohn Marino 					nthreads = 1024;
119150fc853eSJohn Marino 				break;
119250fc853eSJohn Marino #endif
119350fc853eSJohn Marino 			case QSORT_OPT:
119450fc853eSJohn Marino 				sort_opts_vals.sort_method = SORT_QSORT;
119550fc853eSJohn Marino 				break;
119650fc853eSJohn Marino 			case MERGESORT_OPT:
119750fc853eSJohn Marino 				sort_opts_vals.sort_method = SORT_MERGESORT;
119850fc853eSJohn Marino 				break;
119950fc853eSJohn Marino 			case MMAP_OPT:
120050fc853eSJohn Marino 				use_mmap = true;
120150fc853eSJohn Marino 				break;
120250fc853eSJohn Marino 			case HEAPSORT_OPT:
120350fc853eSJohn Marino 				sort_opts_vals.sort_method = SORT_HEAPSORT;
120450fc853eSJohn Marino 				break;
120550fc853eSJohn Marino 			case RADIXSORT_OPT:
120650fc853eSJohn Marino 				sort_opts_vals.sort_method = SORT_RADIXSORT;
120750fc853eSJohn Marino 				break;
12086d7e22ecSzrj #if defined(SORT_RANDOM)
120950fc853eSJohn Marino 			case RANDOMSOURCE_OPT:
121050fc853eSJohn Marino 				random_source = strdup(optarg);
121150fc853eSJohn Marino 				break;
12126d7e22ecSzrj #endif
121350fc853eSJohn Marino 			case COMPRESSPROGRAM_OPT:
121450fc853eSJohn Marino 				compress_program = strdup(optarg);
121550fc853eSJohn Marino 				break;
121650fc853eSJohn Marino 			case FF_OPT:
121750fc853eSJohn Marino 				read_fns_from_file0(optarg);
121850fc853eSJohn Marino 				break;
121950fc853eSJohn Marino 			case BS_OPT:
122050fc853eSJohn Marino 			{
122150fc853eSJohn Marino 				errno = 0;
122250fc853eSJohn Marino 				long mof = strtol(optarg, NULL, 10);
122350fc853eSJohn Marino 				if (errno != 0)
122450fc853eSJohn Marino 					err(2, "--batch-size");
122550fc853eSJohn Marino 				if (mof >= 2)
122650fc853eSJohn Marino 					max_open_files = (size_t) mof + 1;
122750fc853eSJohn Marino 			}
122850fc853eSJohn Marino 				break;
122950fc853eSJohn Marino 			case VERSION_OPT:
123050fc853eSJohn Marino 				printf("%s\n", VERSION);
123150fc853eSJohn Marino 				exit(EXIT_SUCCESS);
123250fc853eSJohn Marino 				/* NOTREACHED */
123350fc853eSJohn Marino 				break;
123450fc853eSJohn Marino 			case DEBUG_OPT:
123550fc853eSJohn Marino 				debug_sort = true;
123650fc853eSJohn Marino 				break;
123750fc853eSJohn Marino 			case HELP_OPT:
123850fc853eSJohn Marino 				usage(false);
123950fc853eSJohn Marino 				/* NOTREACHED */
124050fc853eSJohn Marino 				break;
124150fc853eSJohn Marino 			default:
124250fc853eSJohn Marino 				usage(true);
124350fc853eSJohn Marino 				/* NOTREACHED */
124450fc853eSJohn Marino 			}
124550fc853eSJohn Marino 		}
124650fc853eSJohn Marino 	}
124750fc853eSJohn Marino 
124850fc853eSJohn Marino 	argc -= optind;
124950fc853eSJohn Marino 	argv += optind;
125050fc853eSJohn Marino 
125150fc853eSJohn Marino #ifndef WITHOUT_NLS
125250fc853eSJohn Marino 	catalog = catopen("sort", NL_CAT_LOCALE);
125350fc853eSJohn Marino #endif
125450fc853eSJohn Marino 
125550fc853eSJohn Marino 	if (sort_opts_vals.cflag && sort_opts_vals.mflag)
125650fc853eSJohn Marino 		errx(1, "%c:%c: %s", 'm', 'c', getstr(1));
125750fc853eSJohn Marino 
125850fc853eSJohn Marino #ifndef WITHOUT_NLS
125950fc853eSJohn Marino 	catclose(catalog);
126050fc853eSJohn Marino #endif
126150fc853eSJohn Marino 
126250fc853eSJohn Marino 	if (keys_num == 0) {
126350fc853eSJohn Marino 		keys_num = 1;
126450fc853eSJohn Marino 		keys = sort_realloc(keys, sizeof(struct key_specs));
126550fc853eSJohn Marino 		memset(&(keys[0]), 0, sizeof(struct key_specs));
126650fc853eSJohn Marino 		keys[0].c1 = 1;
126750fc853eSJohn Marino 		keys[0].pos1b = default_sort_mods->bflag;
126850fc853eSJohn Marino 		keys[0].pos2b = default_sort_mods->bflag;
126950fc853eSJohn Marino 		memcpy(&(keys[0].sm), default_sort_mods,
127050fc853eSJohn Marino 		    sizeof(struct sort_mods));
127150fc853eSJohn Marino 	}
127250fc853eSJohn Marino 
127350fc853eSJohn Marino 	for (size_t i = 0; i < keys_num; i++) {
127450fc853eSJohn Marino 		struct key_specs *ks;
127550fc853eSJohn Marino 
127650fc853eSJohn Marino 		ks = &(keys[i]);
127750fc853eSJohn Marino 
127850fc853eSJohn Marino 		if (sort_modifier_empty(&(ks->sm)) && !(ks->pos1b) &&
127950fc853eSJohn Marino 		    !(ks->pos2b)) {
128050fc853eSJohn Marino 			ks->pos1b = sm->bflag;
128150fc853eSJohn Marino 			ks->pos2b = sm->bflag;
128250fc853eSJohn Marino 			memcpy(&(ks->sm), sm, sizeof(struct sort_mods));
128350fc853eSJohn Marino 		}
128450fc853eSJohn Marino 
128550fc853eSJohn Marino 		ks->sm.func = get_sort_func(&(ks->sm));
128650fc853eSJohn Marino 	}
128750fc853eSJohn Marino 
128850fc853eSJohn Marino 	if (argv_from_file0) {
128950fc853eSJohn Marino 		argc = argc_from_file0;
129050fc853eSJohn Marino 		argv = argv_from_file0;
129150fc853eSJohn Marino 	}
129250fc853eSJohn Marino 
129350fc853eSJohn Marino 	if (debug_sort) {
129450fc853eSJohn Marino 		printf("Memory to be used for sorting: %llu\n",available_free_memory);
129550fc853eSJohn Marino #if defined(SORT_THREADS)
129650fc853eSJohn Marino 		printf("Number of CPUs: %d\n",(int)ncpu);
129750fc853eSJohn Marino 		nthreads = 1;
129850fc853eSJohn Marino #endif
129950fc853eSJohn Marino 		printf("Using collate rules of %s locale\n",
130050fc853eSJohn Marino 		    setlocale(LC_COLLATE, NULL));
130150fc853eSJohn Marino 		if (byte_sort)
130250fc853eSJohn Marino 			printf("Byte sort is used\n");
130350fc853eSJohn Marino 		if (print_symbols_on_debug) {
130450fc853eSJohn Marino 			printf("Decimal Point: <%lc>\n", symbol_decimal_point);
130550fc853eSJohn Marino 			if (symbol_thousands_sep)
130650fc853eSJohn Marino 				printf("Thousands separator: <%lc>\n",
130750fc853eSJohn Marino 				    symbol_thousands_sep);
130850fc853eSJohn Marino 			printf("Positive sign: <%lc>\n", symbol_positive_sign);
130950fc853eSJohn Marino 			printf("Negative sign: <%lc>\n", symbol_negative_sign);
131050fc853eSJohn Marino 		}
131150fc853eSJohn Marino 	}
131250fc853eSJohn Marino 
13136d7e22ecSzrj #if defined(SORT_RANDOM)
131450fc853eSJohn Marino 	set_random_seed();
13156d7e22ecSzrj #endif
131650fc853eSJohn Marino 
131750fc853eSJohn Marino 	/* Case when the outfile equals one of the input files: */
131850fc853eSJohn Marino 	if (strcmp(outfile, "-")) {
131950fc853eSJohn Marino 
132050fc853eSJohn Marino 		for(int i = 0; i < argc; ++i) {
132150fc853eSJohn Marino 			if (strcmp(argv[i], outfile) == 0) {
132250fc853eSJohn Marino 				real_outfile = sort_strdup(outfile);
132350fc853eSJohn Marino 				for(;;) {
132450fc853eSJohn Marino 					char* tmp = sort_malloc(strlen(outfile) +
132550fc853eSJohn Marino 					    strlen(".tmp") + 1);
132650fc853eSJohn Marino 
132750fc853eSJohn Marino 					strcpy(tmp, outfile);
132850fc853eSJohn Marino 					strcpy(tmp + strlen(tmp), ".tmp");
132950fc853eSJohn Marino 					sort_free(outfile);
133050fc853eSJohn Marino 					outfile = tmp;
133150fc853eSJohn Marino 					if (access(outfile, F_OK) < 0)
133250fc853eSJohn Marino 						break;
133350fc853eSJohn Marino 				}
133450fc853eSJohn Marino 				tmp_file_atexit(outfile);
133550fc853eSJohn Marino 			}
133650fc853eSJohn Marino 		}
133750fc853eSJohn Marino 	}
133850fc853eSJohn Marino 
133950fc853eSJohn Marino #if defined(SORT_THREADS)
134050fc853eSJohn Marino 	if ((argc < 1) || (strcmp(outfile, "-") == 0) || (*outfile == 0))
134150fc853eSJohn Marino 		nthreads = 1;
134250fc853eSJohn Marino #endif
134350fc853eSJohn Marino 
134450fc853eSJohn Marino 	if (!sort_opts_vals.cflag && !sort_opts_vals.mflag) {
134550fc853eSJohn Marino 		struct file_list fl;
134650fc853eSJohn Marino 		struct sort_list list;
134750fc853eSJohn Marino 
134850fc853eSJohn Marino 		sort_list_init(&list);
134950fc853eSJohn Marino 		file_list_init(&fl, true);
135050fc853eSJohn Marino 
135150fc853eSJohn Marino 		if (argc < 1)
135250fc853eSJohn Marino 			procfile("-", &list, &fl);
135350fc853eSJohn Marino 		else {
135450fc853eSJohn Marino 			while (argc > 0) {
135550fc853eSJohn Marino 				procfile(*argv, &list, &fl);
135650fc853eSJohn Marino 				--argc;
135750fc853eSJohn Marino 				++argv;
135850fc853eSJohn Marino 			}
135950fc853eSJohn Marino 		}
136050fc853eSJohn Marino 
136150fc853eSJohn Marino 		if (fl.count < 1)
136250fc853eSJohn Marino 			sort_list_to_file(&list, outfile);
136350fc853eSJohn Marino 		else {
136450fc853eSJohn Marino 			if (list.count > 0) {
136550fc853eSJohn Marino 				char *flast = new_tmp_file_name();
136650fc853eSJohn Marino 
136750fc853eSJohn Marino 				sort_list_to_file(&list, flast);
136850fc853eSJohn Marino 				file_list_add(&fl, flast, false);
136950fc853eSJohn Marino 			}
137050fc853eSJohn Marino 			merge_files(&fl, outfile);
137150fc853eSJohn Marino 		}
137250fc853eSJohn Marino 
137350fc853eSJohn Marino 		file_list_clean(&fl);
137450fc853eSJohn Marino 
137550fc853eSJohn Marino 		/*
137650fc853eSJohn Marino 		 * We are about to exit the program, so we can ignore
137750fc853eSJohn Marino 		 * the clean-up for speed
137850fc853eSJohn Marino 		 *
137950fc853eSJohn Marino 		 * sort_list_clean(&list);
138050fc853eSJohn Marino 		 */
138150fc853eSJohn Marino 
138250fc853eSJohn Marino 	} else if (sort_opts_vals.cflag) {
138350fc853eSJohn Marino 		result = (argc == 0) ? (check("-")) : (check(*argv));
138450fc853eSJohn Marino 	} else if (sort_opts_vals.mflag) {
138550fc853eSJohn Marino 		struct file_list fl;
138650fc853eSJohn Marino 
138750fc853eSJohn Marino 		file_list_init(&fl, false);
138850fc853eSJohn Marino 		file_list_populate(&fl, argc, argv, true);
138950fc853eSJohn Marino 		merge_files(&fl, outfile);
139050fc853eSJohn Marino 		file_list_clean(&fl);
139150fc853eSJohn Marino 	}
139250fc853eSJohn Marino 
139350fc853eSJohn Marino 	if (real_outfile) {
139450fc853eSJohn Marino 		unlink(real_outfile);
139550fc853eSJohn Marino 		if (rename(outfile, real_outfile) < 0)
139650fc853eSJohn Marino 			err(2, NULL);
139750fc853eSJohn Marino 		sort_free(real_outfile);
139850fc853eSJohn Marino 	}
139950fc853eSJohn Marino 
140050fc853eSJohn Marino 	sort_free(outfile);
140150fc853eSJohn Marino 
140250fc853eSJohn Marino 	return (result);
14037572dc55SJohn Marino }
1404