aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2025-11-13 07:50:50 +0000
committerDenys Vlasenko <vda.linux@googlemail.com>2026-03-05 21:46:04 +0100
commitea01f254b4e0dc2f59db4cba9dd4fa98e9f5b2e5 (patch)
treecce0009e2d1ade4f28a32c9e23709dc20ede2d80
parentb59b00323181d5d450a92959b9bbfe3585c6786b (diff)
downloadbusybox-w32-ea01f254b4e0dc2f59db4cba9dd4fa98e9f5b2e5.tar.gz
busybox-w32-ea01f254b4e0dc2f59db4cba9dd4fa98e9f5b2e5.tar.bz2
busybox-w32-ea01f254b4e0dc2f59db4cba9dd4fa98e9f5b2e5.zip
paste: fix output when file lengths differ
If the files being pasted had different numbers of lines the output was incorrect. Rewrite the loop over all lines to allow for this. Add tests for such conditions. function old new delta paste_main 458 526 +68 Signed-off-by: Ron Yorston <rmy@pobox.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--coreutils/paste.c36
-rw-r--r--testsuite/paste/paste-long-short19
-rw-r--r--testsuite/paste/paste-short-long19
3 files changed, 62 insertions, 12 deletions
diff --git a/coreutils/paste.c b/coreutils/paste.c
index 3e5f20158..363340e3d 100644
--- a/coreutils/paste.c
+++ b/coreutils/paste.c
@@ -34,27 +34,38 @@
34 34
35static void paste_files(FILE** files, int file_cnt, char* delims, int del_cnt) 35static void paste_files(FILE** files, int file_cnt, char* delims, int del_cnt)
36{ 36{
37 char *line; 37 char **line = xmalloc(file_cnt * sizeof(char *));
38 char delim; 38 char delim;
39 int active_files = file_cnt; 39 int active_files = file_cnt;
40 int i; 40 int i;
41 41
42 while (active_files > 0) { 42 while (active_files > 0) {
43 int del_idx = 0; 43 int del_idx = 0;
44 int got_line = FALSE;
44 45
45 for (i = 0; i < file_cnt; ++i) { 46 for (i = 0; i < file_cnt; ++i) {
46 if (files[i] == NULL) 47 if (files[i]) {
47 continue; 48 line[i] = xmalloc_fgetline(files[i]);
48 49 if (!line[i]) {
49 line = xmalloc_fgetline(files[i]); 50 fclose_if_not_stdin(files[i]);
50 if (!line) { 51 files[i] = NULL;
51 fclose_if_not_stdin(files[i]); 52 --active_files;
52 files[i] = NULL; 53 } else {
53 --active_files; 54 got_line = TRUE;
54 continue; 55 }
56 } else {
57 line[i] = NULL;
58 }
59 }
60
61 if (!got_line)
62 break;
63
64 for (i = 0; i < file_cnt; ++i) {
65 if (line[i]) {
66 fputs_stdout(line[i]);
67 free(line[i]);
55 } 68 }
56 fputs_stdout(line);
57 free(line);
58 delim = '\n'; 69 delim = '\n';
59 if (i != file_cnt - 1) { 70 if (i != file_cnt - 1) {
60 delim = delims[del_idx++]; 71 delim = delims[del_idx++];
@@ -65,6 +76,7 @@ static void paste_files(FILE** files, int file_cnt, char* delims, int del_cnt)
65 fputc(delim, stdout); 76 fputc(delim, stdout);
66 } 77 }
67 } 78 }
79 free(line);
68} 80}
69 81
70static void paste_files_separate(FILE** files, char* delims, int del_cnt) 82static void paste_files_separate(FILE** files, char* delims, int del_cnt)
diff --git a/testsuite/paste/paste-long-short b/testsuite/paste/paste-long-short
new file mode 100644
index 000000000..e626d730e
--- /dev/null
+++ b/testsuite/paste/paste-long-short
@@ -0,0 +1,19 @@
1cat > foo <<EOF
2foo1
3foo2
4foo3
5EOF
6
7cat > bar <<EOF
8bar1
9bar2
10EOF
11
12cat > baz <<EOF
13foo1 bar1
14foo2 bar2
15foo3
16EOF
17
18busybox paste foo bar > qux
19diff -u baz qux
diff --git a/testsuite/paste/paste-short-long b/testsuite/paste/paste-short-long
new file mode 100644
index 000000000..785da60a7
--- /dev/null
+++ b/testsuite/paste/paste-short-long
@@ -0,0 +1,19 @@
1cat > foo <<EOF
2foo1
3foo2
4EOF
5
6cat > bar <<EOF
7bar1
8bar2
9bar3
10EOF
11
12cat > baz <<EOF
13foo1 bar1
14foo2 bar2
15 bar3
16EOF
17
18busybox paste foo bar > qux
19diff -u baz qux