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