rev.c 2.3 KB

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