[git commit master] sort: make sort -o FILE FILE (same FILE) work. Closes bug 785. -3 bytes

Denys Vlasenko vda.linux at googlemail.com
Sun Dec 13 01:09:22 UTC 2009


commit: http://git.busybox.net/busybox/commit/?id=aa42d13e320250d3573c6be975876a612c00e91f
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 coreutils/sort.c     |   56 ++++++++++++++++++++++++++++++++-----------------
 testsuite/sort.tests |   13 +++++++++++
 2 files changed, 49 insertions(+), 20 deletions(-)

diff --git a/coreutils/sort.c b/coreutils/sort.c
index e2e7983..5c3fa1a 100644
--- a/coreutils/sort.c
+++ b/coreutils/sort.c
@@ -278,27 +278,32 @@ static unsigned str2u(char **str)
 int sort_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int sort_main(int argc UNUSED_PARAM, char **argv)
 {
-	FILE *fp, *outfile = stdout;
-	char *line, **lines = NULL;
+	char *line, **lines;
 	char *str_ignored, *str_o, *str_t;
 	llist_t *lst_k = NULL;
 	int i, flag;
-	int linecount = 0;
+	int linecount;
+	unsigned opts;
 
 	xfunc_error_retval = 2;
 
 	/* Parse command line options */
 	/* -o and -t can be given at most once */
-	opt_complementary = "o--o:t--t:" /* -t, -o: maximum one of each */
+	opt_complementary = "o--o:t--t:" /* -t, -o: at most one of each */
 			"k::"; /* -k takes list */
-	getopt32(argv, OPT_STR, &str_ignored, &str_ignored, &str_o, &lst_k, &str_t);
+	opts = getopt32(argv, OPT_STR, &str_ignored, &str_ignored, &str_o, &lst_k, &str_t);
+	/* global b strips leading and trailing spaces */
+	if (opts & FLAG_b)
+		option_mask32 |= FLAG_bb;
 #if ENABLE_FEATURE_SORT_BIG
-	if (option_mask32 & FLAG_o) outfile = xfopen_for_write(str_o);
-	if (option_mask32 & FLAG_t) {
+	if (opts & FLAG_t) {
 		if (!str_t[0] || str_t[1])
 			bb_error_msg_and_die("bad -t parameter");
 		key_separator = str_t[0];
 	}
+	/* note: below this point we use option_mask32, not opts,
+	 * since that reduces register pressure and makes code smaller */
+
 	/* parse sort key */
 	while (lst_k) {
 		enum {
@@ -315,7 +320,6 @@ int sort_main(int argc UNUSED_PARAM, char **argv)
 		};
 		struct sort_key *key = add_key();
 		char *str_k = llist_pop(&lst_k);
-		const char *temp2;
 
 		i = 0; /* i==0 before comma, 1 after (-k3,6) */
 		while (*str_k) {
@@ -327,11 +331,13 @@ int sort_main(int argc UNUSED_PARAM, char **argv)
 				key->range[2*i+1] = str2u(&str_k);
 			}
 			while (*str_k) {
+				const char *temp2;
+
 				if (*str_k == ',' && !i++) {
 					str_k++;
 					break;
 				} /* no else needed: fall through to syntax error
-					 because comma isn't in OPT_STR */
+					because comma isn't in OPT_STR */
 				temp2 = strchr(OPT_STR, *str_k);
 				if (!temp2)
 					bb_error_msg_and_die("unknown key option");
@@ -339,27 +345,29 @@ int sort_main(int argc UNUSED_PARAM, char **argv)
 				if (flag & ~FLAG_allowed_for_k)
 					bb_error_msg_and_die("unknown sort type");
 				/* b after ',' means strip _trailing_ space */
-				if (i && flag == FLAG_b) flag = FLAG_bb;
+				if (i && flag == FLAG_b)
+					flag = FLAG_bb;
 				key->flags |= flag;
 				str_k++;
 			}
 		}
 	}
 #endif
-	/* global b strips leading and trailing spaces */
-	if (option_mask32 & FLAG_b) option_mask32 |= FLAG_bb;
 
 	/* Open input files and read data */
 	argv += optind;
 	if (!*argv)
 		*--argv = (char*)"-";
+	linecount = 0;
+	lines = NULL;
 	do {
 		/* coreutils 6.9 compat: abort on first open error,
 		 * do not continue to next file: */
-		fp = xfopen_stdin(*argv);
+		FILE *fp = xfopen_stdin(*argv);
 		for (;;) {
 			line = GET_LINE(fp);
-			if (!line) break;
+			if (!line)
+				break;
 			lines = xrealloc_vector(lines, 6, linecount);
 			lines[linecount++] = line;
 		}
@@ -373,16 +381,17 @@ int sort_main(int argc UNUSED_PARAM, char **argv)
 	/* handle -c */
 	if (option_mask32 & FLAG_c) {
 		int j = (option_mask32 & FLAG_u) ? -1 : 0;
-		for (i = 1; i < linecount; i++)
+		for (i = 1; i < linecount; i++) {
 			if (compare_keys(&lines[i-1], &lines[i]) > j) {
-				fprintf(stderr, "Check line %d\n", i);
+				fprintf(stderr, "Check line %u\n", i);
 				return EXIT_FAILURE;
 			}
+		}
 		return EXIT_SUCCESS;
 	}
 #endif
 	/* Perform the actual sort */
-	qsort(lines, linecount, sizeof(char *), compare_keys);
+	qsort(lines, linecount, sizeof(lines[0]), compare_keys);
 	/* handle -u */
 	if (option_mask32 & FLAG_u) {
 		flag = 0;
@@ -390,17 +399,24 @@ int sort_main(int argc UNUSED_PARAM, char **argv)
 		/* -- disabling last-resort compare... */
 		option_mask32 |= FLAG_s;
 		for (i = 1; i < linecount; i++) {
-			if (!compare_keys(&lines[flag], &lines[i]))
+			if (compare_keys(&lines[flag], &lines[i]) == 0)
 				free(lines[i]);
 			else
 				lines[++flag] = lines[i];
 		}
-		if (linecount) linecount = flag+1;
+		if (linecount)
+			linecount = flag+1;
 	}
+
 	/* Print it */
+#if ENABLE_FEATURE_SORT_BIG
+	/* Open output file _after_ we read all input ones */
+	if (option_mask32 & FLAG_o)
+		xmove_fd(xopen3(str_o, O_WRONLY, 0666), STDOUT_FILENO);
+#endif
 	flag = (option_mask32 & FLAG_z) ? '\0' : '\n';
 	for (i = 0; i < linecount; i++)
-		fprintf(outfile, "%s%c", lines[i], flag);
+		printf("%s%c", lines[i], flag);
 
 	fflush_stdout_and_exit(EXIT_SUCCESS);
 }
diff --git a/testsuite/sort.tests b/testsuite/sort.tests
index 5ed29fb..72df80b 100755
--- a/testsuite/sort.tests
+++ b/testsuite/sort.tests
@@ -27,6 +27,8 @@ egg	1	2	papyrus
 999	3	0	algebra
 "
 
+# testing "description" "command(s)" "result" "infile" "stdin"
+
 # Sorting with keys
 
 testing "sort one key" "sort -k4,4 input" \
@@ -115,4 +117,15 @@ one\0two\0three\0\
 testing "sort key doesn't strip leading blanks, disables fallback global sort" \
 "sort -n -k2 -t ' '" " a \n 1 \n 2 \n" "" " 2 \n 1 \n a \n"
 
+testing "sort file in place" \
+"strace -oZZZ sort -o input input && cat input" "\
+111
+222
+" "\
+222
+111
+" ""
+
+# testing "description" "command(s)" "result" "infile" "stdin"
+
 exit $FAILCOUNT
-- 
1.6.3.3



More information about the busybox-cvs mailing list