diff options
Diffstat (limited to 'util-linux')
-rw-r--r-- | util-linux/rev.c | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/util-linux/rev.c b/util-linux/rev.c new file mode 100644 index 000000000..fa3a453ae --- /dev/null +++ b/util-linux/rev.c @@ -0,0 +1,121 @@ +/* + * rev implementation for busybox + * + * Copyright (C) 2010 Marek Polacek <mmpolacek@gmail.com> + * + * Licensed under GPLv2, see file License in this tarball for details. + */ + +//applet:IF_REV(APPLET(rev, _BB_DIR_BIN, _BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_REV) += rev.o + +//config:config REV +//config: bool "rev" +//config: default y +//config: help +//config: Reverse lines of a file or files. + +//usage:#define rev_trivial_usage +//usage: "[FILE]..." +//usage:#define rev_full_usage "\n\n" +//usage: "Reverse lines of FILE" + +#include "libbb.h" +#include "unicode.h" + +#undef CHAR_T +#if ENABLE_UNICODE_SUPPORT +# define CHAR_T wchar_t +#else +# define CHAR_T char +#endif + +/* In-place invert */ +static void strrev(CHAR_T *s, int len) +{ + int i; + + if (len != 0) { + len--; + if (len != 0 && s[len] == '\n') + len--; + } + + for (i = 0; i < len; i++, len--) { + CHAR_T c = s[i]; + s[i] = s[len]; + s[len] = c; + } +} + +int rev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int rev_main(int argc UNUSED_PARAM, char **argv) +{ + int retval; + size_t bufsize; + char *buf; + + init_unicode(); + + getopt32(argv, ""); + argv += optind; + if (!argv[0]) + argv = (char **)&bb_argv_dash; + + retval = EXIT_SUCCESS; + bufsize = 256; + buf = xmalloc(bufsize); + do { + size_t pos; + FILE *fp; + + fp = fopen_or_warn_stdin(*argv++); + if (!fp) { + retval = EXIT_FAILURE; + continue; + } + + pos = 0; + while (1) { + /* Read one line */ + buf[bufsize - 1] = 1; /* not 0 */ + if (!fgets(buf + pos, bufsize - pos, fp)) + break; /* EOF/error */ + if (buf[bufsize - 1] == '\0' /* fgets filled entire buffer */ + && buf[bufsize - 2] != '\n' /* and did not read '\n' */ + && !feof(fp) + ) { + /* Line is too long, extend buffer */ + pos = bufsize - 1; + bufsize += 64 + bufsize / 8; + buf = xrealloc(buf, bufsize); + continue; + } + + /* Process and print it */ +#if ENABLE_UNICODE_SUPPORT + { + wchar_t *tmp = xmalloc(bufsize * sizeof(wchar_t)); + /* Convert to wchar_t (might error out!) */ + int len = mbstowcs(tmp, buf, bufsize); + if (len >= 0) { + strrev(tmp, len); + /* Convert back to char */ + wcstombs(buf, tmp, bufsize); + } + free(tmp); + } +#else + strrev(buf, strlen(buf)); +#endif + fputs(buf, stdout); + } + fclose(fp); + } while (*argv); + + if (ENABLE_FEATURE_CLEAN_UP) + free(buf); + + fflush_stdout_and_exit(retval); +} |