blob: 94d669de1955f474ede99a2fb3c65fe2a4895b40 [file] [log] [blame]
Denis Vlasenko482f2b32008-01-07 16:14:14 +00001/* 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 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02009 * Licensed under GPLv2, see file LICENSE in this source tree.
Denis Vlasenko482f2b32008-01-07 16:14:14 +000010 *
11 */
12
13/* tac - concatenate and print files in reverse */
14
15/* Based on Yang Xiaopeng's (yxp at hanwang.com.cn) patch
16 * http://www.uclibc.org/lists/busybox/2003-July/008813.html
17 */
18
Pere Orga34425382011-03-31 14:43:25 +020019//usage:#define tac_trivial_usage
20//usage: "[FILE]..."
21//usage:#define tac_full_usage "\n\n"
22//usage: "Concatenate FILEs and print them in reverse"
23
Denis Vlasenko482f2b32008-01-07 16:14:14 +000024#include "libbb.h"
25
26/* This is a NOEXEC applet. Be very careful! */
27
Denis Vlasenkode24bd92008-01-09 23:00:00 +000028struct lstring {
29 int size;
Denis Vlasenko62a90cd2008-03-17 09:07:36 +000030 char buf[1];
Denis Vlasenkode24bd92008-01-09 23:00:00 +000031};
32
Denis Vlasenko482f2b32008-01-07 16:14:14 +000033int tac_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000034int tac_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko482f2b32008-01-07 16:14:14 +000035{
36 char **name;
37 FILE *f;
Denis Vlasenkode24bd92008-01-09 23:00:00 +000038 struct lstring *line = NULL;
Denis Vlasenko482f2b32008-01-07 16:14:14 +000039 llist_t *list = NULL;
40 int retval = EXIT_SUCCESS;
Denis Vlasenko474d1c52008-01-07 19:06:47 +000041
Denis Vlasenko62a90cd2008-03-17 09:07:36 +000042#if ENABLE_DESKTOP
43/* tac from coreutils 6.9 supports:
44 -b, --before
45 attach the separator before instead of after
46 -r, --regex
47 interpret the separator as a regular expression
48 -s, --separator=STRING
49 use STRING as the separator instead of newline
50We support none, but at least we will complain or handle "--":
51*/
52 getopt32(argv, "");
53 argv += optind;
54#else
Denis Vlasenko482f2b32008-01-07 16:14:14 +000055 argv++;
Denis Vlasenko62a90cd2008-03-17 09:07:36 +000056#endif
Denis Vlasenko482f2b32008-01-07 16:14:14 +000057 if (!*argv)
58 *--argv = (char *)"-";
59 /* We will read from last file to first */
60 name = argv;
61 while (*name)
62 name++;
63
64 do {
Denis Vlasenkode24bd92008-01-09 23:00:00 +000065 int ch, i;
66
Denis Vlasenko482f2b32008-01-07 16:14:14 +000067 name--;
68 f = fopen_or_warn_stdin(*name);
69 if (f == NULL) {
Denis Vlasenko62a90cd2008-03-17 09:07:36 +000070 /* error message is printed by fopen_or_warn_stdin */
Denis Vlasenko482f2b32008-01-07 16:14:14 +000071 retval = EXIT_FAILURE;
72 continue;
73 }
74
Denis Vlasenkode24bd92008-01-09 23:00:00 +000075 errno = i = 0;
76 do {
77 ch = fgetc(f);
78 if (ch != EOF) {
79 if (!(i & 0x7f))
80 /* Grow on every 128th char */
81 line = xrealloc(line, i + 0x7f + sizeof(int) + 1);
82 line->buf[i++] = ch;
83 }
Denis Vlasenko62a90cd2008-03-17 09:07:36 +000084 if (ch == '\n' || (ch == EOF && i != 0)) {
Denis Vlasenkode24bd92008-01-09 23:00:00 +000085 line = xrealloc(line, i + sizeof(int));
86 line->size = i;
87 llist_add_to(&list, line);
88 line = NULL;
89 i = 0;
90 }
91 } while (ch != EOF);
Denis Vlasenko62a90cd2008-03-17 09:07:36 +000092 /* fgetc sets errno to ENOENT on EOF, we don't want
93 * to warn on this non-error! */
Denis Vlasenko482f2b32008-01-07 16:14:14 +000094 if (errno && errno != ENOENT) {
95 bb_simple_perror_msg(*name);
96 retval = EXIT_FAILURE;
97 }
98 } while (name != argv);
99
100 while (list) {
Denis Vlasenkode24bd92008-01-09 23:00:00 +0000101 line = (struct lstring *)list->data;
102 xwrite(STDOUT_FILENO, line->buf, line->size);
103 if (ENABLE_FEATURE_CLEAN_UP) {
104 free(llist_pop(&list));
105 } else {
106 list = list->link;
107 }
Denis Vlasenko482f2b32008-01-07 16:14:14 +0000108 }
Denis Vlasenko474d1c52008-01-07 19:06:47 +0000109
Denis Vlasenko482f2b32008-01-07 16:14:14 +0000110 return retval;
111}