tac.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * tac implementation for busybox
  4. *
  5. * Copyright (C) 2003 Yang Xiaopeng <yxp at hanwang.com.cn>
  6. * Copyright (C) 2007 Natanael Copa <natanael.copa@gmail.com>
  7. * Copyright (C) 2007 Tito Ragusa <farmatito@tiscali.it>
  8. *
  9. * Licensed under GPLv2, see file License in this tarball for details.
  10. *
  11. */
  12. /* tac - concatenate and print files in reverse */
  13. /* Based on Yang Xiaopeng's (yxp at hanwang.com.cn) patch
  14. * http://www.uclibc.org/lists/busybox/2003-July/008813.html
  15. */
  16. #include "libbb.h"
  17. /* This is a NOEXEC applet. Be very careful! */
  18. struct lstring {
  19. int size;
  20. char buf[1];
  21. };
  22. int tac_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  23. int tac_main(int argc ATTRIBUTE_UNUSED, char **argv)
  24. {
  25. char **name;
  26. FILE *f;
  27. struct lstring *line = NULL;
  28. llist_t *list = NULL;
  29. int retval = EXIT_SUCCESS;
  30. #if ENABLE_DESKTOP
  31. /* tac from coreutils 6.9 supports:
  32. -b, --before
  33. attach the separator before instead of after
  34. -r, --regex
  35. interpret the separator as a regular expression
  36. -s, --separator=STRING
  37. use STRING as the separator instead of newline
  38. We support none, but at least we will complain or handle "--":
  39. */
  40. getopt32(argv, "");
  41. argv += optind;
  42. #else
  43. argv++;
  44. #endif
  45. if (!*argv)
  46. *--argv = (char *)"-";
  47. /* We will read from last file to first */
  48. name = argv;
  49. while (*name)
  50. name++;
  51. do {
  52. int ch, i;
  53. name--;
  54. f = fopen_or_warn_stdin(*name);
  55. if (f == NULL) {
  56. /* error message is printed by fopen_or_warn_stdin */
  57. retval = EXIT_FAILURE;
  58. continue;
  59. }
  60. errno = i = 0;
  61. do {
  62. ch = fgetc(f);
  63. if (ch != EOF) {
  64. if (!(i & 0x7f))
  65. /* Grow on every 128th char */
  66. line = xrealloc(line, i + 0x7f + sizeof(int) + 1);
  67. line->buf[i++] = ch;
  68. }
  69. if (ch == '\n' || (ch == EOF && i != 0)) {
  70. line = xrealloc(line, i + sizeof(int));
  71. line->size = i;
  72. llist_add_to(&list, line);
  73. line = NULL;
  74. i = 0;
  75. }
  76. } while (ch != EOF);
  77. /* fgetc sets errno to ENOENT on EOF, we don't want
  78. * to warn on this non-error! */
  79. if (errno && errno != ENOENT) {
  80. bb_simple_perror_msg(*name);
  81. retval = EXIT_FAILURE;
  82. }
  83. } while (name != argv);
  84. while (list) {
  85. line = (struct lstring *)list->data;
  86. xwrite(STDOUT_FILENO, line->buf, line->size);
  87. if (ENABLE_FEATURE_CLEAN_UP) {
  88. free(llist_pop(&list));
  89. } else {
  90. list = list->link;
  91. }
  92. }
  93. return retval;
  94. }