#include "libbb.h" #include "unicode.h" /* Copyright (C) 2003 Manuel Novoa III /* /* Licensed under GPLv2 or later, see file LICENSE in this source tree. #if !ENABLE_LOCALE_SUPPORT # undef isprint # undef isspace # define isprint(c) ((unsigned)((c) - 0x20) <= (0x7e - 0x20)) # define isspace(c) ((c) == ' ') #endif #if ENABLE_FEATURE_WC_LARGE # define COUNT_T unsigned long long # define COUNT_FMT "llu" #else # define COUNT_T unsigned # define COUNT_FMT "u" #endif enum { WC_LINES = 0, /* -l */ WC_WORDS = 1, /* -w */ WC_UNICHARS = 2, /* -m */ WC_BYTES = 3, /* -c */ WC_LENGTH = 4, /* -L */ NUM_WCS = 5, }; int wc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int wc_main(int argc UNUSED_PARAM, char **argv) { const char *arg; const char *start_fmt = " %9"COUNT_FMT + 1; const char *fname_fmt = " %s\n"; COUNT_T *pcounts; COUNT_T counts[NUM_WCS]; COUNT_T totals[NUM_WCS]; int num_files; smallint status = EXIT_SUCCESS; unsigned print_type; init_unicode(); print_type = getopt32(argv, "lwmcL"); if (print_type == 0) { print_type = (1 << WC_LINES) | (1 << WC_WORDS) | (1 << WC_BYTES); } argv += optind; if (!argv[0]) { *--argv = (char *) bb_msg_standard_input; fname_fmt = "\n"; } if (!argv[1]) { /* zero or one filename? */ if (!((print_type-1) & print_type)) /* exactly one option? */ start_fmt = "%"COUNT_FMT; } memset(totals, 0, sizeof(totals)); pcounts = counts; num_files = 0; while ((arg = *argv++) != NULL) { FILE *fp; const char *s; unsigned u; unsigned linepos; smallint in_word; ++num_files; fp = fopen_or_warn_stdin(arg); if (!fp) { status = EXIT_FAILURE; continue; } memset(counts, 0, sizeof(counts)); linepos = 0; in_word = 0; while (1) { int c; c = getc(fp); if (c == EOF) { if (ferror(fp)) { bb_simple_perror_msg(arg); status = EXIT_FAILURE; } goto DO_EOF; /* Treat an EOF as '\r'. */ } ++counts[WC_BYTES]; if (unicode_status != UNICODE_ON /* every byte is a new char */ || (c & 0xc0) != 0x80 /* it isn't a 2nd+ byte of a Unicode char */ ) { ++counts[WC_UNICHARS]; } if (isprint_asciionly(c)) { /* FIXME: not unicode-aware */ ++linepos; if (!isspace(c)) { in_word = 1; continue; } } else if ((unsigned)(c - 9) <= 4) { if (c == '\t') { linepos = (linepos | 7) + 1; } else { /* '\n', '\r', '\f', or '\v' */ DO_EOF: if (linepos > counts[WC_LENGTH]) { counts[WC_LENGTH] = linepos; } if (c == '\n') { ++counts[WC_LINES]; } if (c != '\v') { linepos = 0; } } } else { continue; } counts[WC_WORDS] += in_word; in_word = 0; if (c == EOF) { break; } } fclose_if_not_stdin(fp); if (totals[WC_LENGTH] < counts[WC_LENGTH]) { totals[WC_LENGTH] = counts[WC_LENGTH]; } totals[WC_LENGTH] -= counts[WC_LENGTH]; OUTPUT: s = start_fmt; u = 0; do { if (print_type & (1 << u)) { printf(s, pcounts[u]); s = " %9"COUNT_FMT; /* Ok... restore the leading space. */ } totals[u] += pcounts[u]; } while (++u < NUM_WCS); printf(fname_fmt, arg); } if (num_files > 1) { num_files = 0; /* Make sure we don't get here again. */ arg = "total"; pcounts = totals; --argv; goto OUTPUT; } fflush_stdout_and_exit(status); }