diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-01-09 23:00:00 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-01-09 23:00:00 +0000 |
commit | de24bd960f3708e7aad013bd898b725fc13d15b2 (patch) | |
tree | 1ecf1b299dfdf02dbc26a4c84d95bf32fc49c328 | |
parent | d2c450ce811454fb77679d049538530d2cf54dd8 (diff) | |
download | busybox-w32-de24bd960f3708e7aad013bd898b725fc13d15b2.tar.gz busybox-w32-de24bd960f3708e7aad013bd898b725fc13d15b2.tar.bz2 busybox-w32-de24bd960f3708e7aad013bd898b725fc13d15b2.zip |
tac: handle NULs properly. +145 bytes
-rw-r--r-- | coreutils/tac.c | 46 |
1 files changed, 35 insertions, 11 deletions
diff --git a/coreutils/tac.c b/coreutils/tac.c index b1b47302f..7951be255 100644 --- a/coreutils/tac.c +++ b/coreutils/tac.c | |||
@@ -20,12 +20,17 @@ | |||
20 | 20 | ||
21 | /* This is a NOEXEC applet. Be very careful! */ | 21 | /* This is a NOEXEC applet. Be very careful! */ |
22 | 22 | ||
23 | struct lstring { | ||
24 | int size; | ||
25 | char buf[]; | ||
26 | }; | ||
27 | |||
23 | int tac_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 28 | int tac_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
24 | int tac_main(int argc, char **argv) | 29 | int tac_main(int argc, char **argv) |
25 | { | 30 | { |
26 | char **name; | 31 | char **name; |
27 | FILE *f; | 32 | FILE *f; |
28 | char *line; | 33 | struct lstring *line = NULL; |
29 | llist_t *list = NULL; | 34 | llist_t *list = NULL; |
30 | int retval = EXIT_SUCCESS; | 35 | int retval = EXIT_SUCCESS; |
31 | 36 | ||
@@ -38,6 +43,8 @@ int tac_main(int argc, char **argv) | |||
38 | name++; | 43 | name++; |
39 | 44 | ||
40 | do { | 45 | do { |
46 | int ch, i; | ||
47 | |||
41 | name--; | 48 | name--; |
42 | f = fopen_or_warn_stdin(*name); | 49 | f = fopen_or_warn_stdin(*name); |
43 | if (f == NULL) { | 50 | if (f == NULL) { |
@@ -45,14 +52,26 @@ int tac_main(int argc, char **argv) | |||
45 | continue; | 52 | continue; |
46 | } | 53 | } |
47 | 54 | ||
48 | errno = 0; | 55 | errno = i = 0; |
49 | /* FIXME: NUL bytes are mishandled. */ | 56 | do { |
50 | while ((line = xmalloc_fgets(f)) != NULL) | 57 | ch = fgetc(f); |
51 | llist_add_to(&list, line); | 58 | if (ch != EOF) { |
52 | 59 | if (!(i & 0x7f)) | |
53 | /* xmalloc_fgets uses getc and returns NULL on error or EOF. */ | 60 | /* Grow on every 128th char */ |
54 | /* It sets errno to ENOENT on EOF, but fopen_or_warn_stdin would */ | 61 | line = xrealloc(line, i + 0x7f + sizeof(int) + 1); |
55 | /* catch this error so we can filter it out here. */ | 62 | line->buf[i++] = ch; |
63 | } | ||
64 | if ((ch == '\n' || ch == EOF) && i) { | ||
65 | line = xrealloc(line, i + sizeof(int)); | ||
66 | line->size = i; | ||
67 | llist_add_to(&list, line); | ||
68 | line = NULL; | ||
69 | i = 0; | ||
70 | } | ||
71 | } while (ch != EOF); | ||
72 | /* fgetc sets errno to ENOENT on EOF, but */ | ||
73 | /* fopen_or_warn_stdin would catch this error */ | ||
74 | /* so we can filter it out here. */ | ||
56 | if (errno && errno != ENOENT) { | 75 | if (errno && errno != ENOENT) { |
57 | bb_simple_perror_msg(*name); | 76 | bb_simple_perror_msg(*name); |
58 | retval = EXIT_FAILURE; | 77 | retval = EXIT_FAILURE; |
@@ -60,8 +79,13 @@ int tac_main(int argc, char **argv) | |||
60 | } while (name != argv); | 79 | } while (name != argv); |
61 | 80 | ||
62 | while (list) { | 81 | while (list) { |
63 | printf("%s", list->data); | 82 | line = (struct lstring *)list->data; |
64 | list = list->link; | 83 | xwrite(STDOUT_FILENO, line->buf, line->size); |
84 | if (ENABLE_FEATURE_CLEAN_UP) { | ||
85 | free(llist_pop(&list)); | ||
86 | } else { | ||
87 | list = list->link; | ||
88 | } | ||
65 | } | 89 | } |
66 | 90 | ||
67 | return retval; | 91 | return retval; |