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