blob: c2250531419ec8d567100fc9767bcda86d9c3456
1 | /* |
2 | * rev implementation for busybox |
3 | * |
4 | * Copyright (C) 2010 Marek Polacek <mmpolacek@gmail.com> |
5 | * |
6 | * Licensed under GPLv2, see file LICENSE in this source tree. |
7 | */ |
8 | //config:config REV |
9 | //config: bool "rev" |
10 | //config: default y |
11 | //config: help |
12 | //config: Reverse lines of a file or files. |
13 | |
14 | //applet:IF_REV(APPLET(rev, BB_DIR_BIN, BB_SUID_DROP)) |
15 | |
16 | //kbuild:lib-$(CONFIG_REV) += rev.o |
17 | |
18 | //usage:#define rev_trivial_usage |
19 | //usage: "[FILE]..." |
20 | //usage:#define rev_full_usage "\n\n" |
21 | //usage: "Reverse lines of FILE" |
22 | |
23 | #include "libbb.h" |
24 | #include "unicode.h" |
25 | |
26 | #undef CHAR_T |
27 | #if ENABLE_UNICODE_SUPPORT |
28 | # define CHAR_T wchar_t |
29 | #else |
30 | # define CHAR_T char |
31 | #endif |
32 | |
33 | /* In-place invert */ |
34 | static void strrev(CHAR_T *s, int len) |
35 | { |
36 | int i; |
37 | |
38 | if (len != 0) { |
39 | len--; |
40 | if (len != 0 && s[len] == '\n') |
41 | len--; |
42 | } |
43 | |
44 | for (i = 0; i < len; i++, len--) { |
45 | CHAR_T c = s[i]; |
46 | s[i] = s[len]; |
47 | s[len] = c; |
48 | } |
49 | } |
50 | |
51 | int rev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
52 | int rev_main(int argc UNUSED_PARAM, char **argv) |
53 | { |
54 | int retval; |
55 | size_t bufsize; |
56 | char *buf; |
57 | |
58 | init_unicode(); |
59 | |
60 | getopt32(argv, ""); |
61 | argv += optind; |
62 | if (!argv[0]) |
63 | argv = (char **)&bb_argv_dash; |
64 | |
65 | retval = EXIT_SUCCESS; |
66 | bufsize = 256; |
67 | buf = xmalloc(bufsize); |
68 | do { |
69 | size_t pos; |
70 | FILE *fp; |
71 | |
72 | fp = fopen_or_warn_stdin(*argv++); |
73 | if (!fp) { |
74 | retval = EXIT_FAILURE; |
75 | continue; |
76 | } |
77 | |
78 | pos = 0; |
79 | while (1) { |
80 | /* Read one line */ |
81 | buf[bufsize - 1] = 1; /* not 0 */ |
82 | if (!fgets(buf + pos, bufsize - pos, fp)) |
83 | break; /* EOF/error */ |
84 | if (buf[bufsize - 1] == '\0' /* fgets filled entire buffer */ |
85 | && buf[bufsize - 2] != '\n' /* and did not read '\n' */ |
86 | && !feof(fp) |
87 | ) { |
88 | /* Line is too long, extend buffer */ |
89 | pos = bufsize - 1; |
90 | bufsize += 64 + bufsize / 8; |
91 | buf = xrealloc(buf, bufsize); |
92 | continue; |
93 | } |
94 | |
95 | /* Process and print it */ |
96 | #if ENABLE_UNICODE_SUPPORT |
97 | { |
98 | wchar_t *tmp = xmalloc(bufsize * sizeof(wchar_t)); |
99 | /* Convert to wchar_t (might error out!) */ |
100 | int len = mbstowcs(tmp, buf, bufsize); |
101 | if (len >= 0) { |
102 | strrev(tmp, len); |
103 | /* Convert back to char */ |
104 | wcstombs(buf, tmp, bufsize); |
105 | } |
106 | free(tmp); |
107 | } |
108 | #else |
109 | strrev(buf, strlen(buf)); |
110 | #endif |
111 | fputs(buf, stdout); |
112 | } |
113 | fclose(fp); |
114 | } while (*argv); |
115 | |
116 | if (ENABLE_FEATURE_CLEAN_UP) |
117 | free(buf); |
118 | |
119 | fflush_stdout_and_exit(retval); |
120 | } |
121 |