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 source tree. 10 * 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 19//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 24#include "libbb.h" 25 26/* This is a NOEXEC applet. Be very careful! */ 27 28struct lstring { 29 int size; 30 char buf[1]; 31}; 32 33int tac_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 34int tac_main(int argc UNUSED_PARAM, char **argv) 35{ 36 char **name; 37 FILE *f; 38 struct lstring *line = NULL; 39 llist_t *list = NULL; 40 int retval = EXIT_SUCCESS; 41 42#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 55 argv++; 56#endif 57 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 { 65 int ch, i; 66 67 name--; 68 f = fopen_or_warn_stdin(*name); 69 if (f == NULL) { 70 /* error message is printed by fopen_or_warn_stdin */ 71 retval = EXIT_FAILURE; 72 continue; 73 } 74 75 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 } 84 if (ch == '\n' || (ch == EOF && i != 0)) { 85 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); 92 /* fgetc sets errno to ENOENT on EOF, we don't want 93 * to warn on this non-error! */ 94 if (errno && errno != ENOENT) { 95 bb_simple_perror_msg(*name); 96 retval = EXIT_FAILURE; 97 } 98 } while (name != argv); 99 100 while (list) { 101 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 } 108 } 109 110 return retval; 111} 112