blob: 2bef9b9befb2748de996836328e00e18fd3f4179 [file] [log] [blame]
Marek Polacekfc6f6e92010-06-22 12:53:35 +02001/*
2 * rev implementation for busybox
3 *
4 * Copyright (C) 2010 Marek Polacek <mmpolacek@gmail.com>
5 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02006 * Licensed under GPLv2, see file LICENSE in this source tree.
Marek Polacekfc6f6e92010-06-22 12:53:35 +02007 */
Marek Polacekfc6f6e92010-06-22 12:53:35 +02008//config:config REV
Denys Vlasenko4eed2c62017-07-18 22:01:24 +02009//config: bool "rev (4.5 kb)"
Marek Polacekfc6f6e92010-06-22 12:53:35 +020010//config: default y
11//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020012//config: Reverse lines of a file or files.
Marek Polacekfc6f6e92010-06-22 12:53:35 +020013
Denys Vlasenkodd898c92016-11-23 11:46:32 +010014//applet:IF_REV(APPLET(rev, BB_DIR_BIN, BB_SUID_DROP))
15
16//kbuild:lib-$(CONFIG_REV) += rev.o
17
Marek Polacekfc6f6e92010-06-22 12:53:35 +020018//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 */
34static 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
51int rev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
52int 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}