Avoid printing a trailing blank character.
[oweals/busybox.git] / coreutils / wc.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Mini wc implementation for busybox
4  *
5  * Copyright (C) 2000  Edward Betts <edward@debian.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  *
21  */
22
23 #include <stdio.h>
24 #include <getopt.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include "busybox.h"
28
29 enum print_e {
30         print_lines = 1,
31         print_words = 2,
32         print_chars = 4,
33         print_length = 8
34 };
35
36 static unsigned int total_lines = 0;
37 static unsigned int total_words = 0;
38 static unsigned int total_chars = 0;
39 static unsigned int max_length = 0;
40 static char print_type = 0;
41
42 static void print_counts(const unsigned int lines, const unsigned int words,
43         const unsigned int chars, const unsigned int length, const char *name)
44 {
45         int output = 0;
46
47         if (print_type & print_lines) {
48                 printf("%7d", lines);
49                 output++;
50         }
51         if (print_type & print_words) {
52                 if (output++)
53                         putchar(' ');
54                 printf("%7d", words);
55         }
56         if (print_type & print_chars) {
57                 if (output++)
58                         putchar(' ');
59                 printf("%7d", chars);
60         }
61         if (print_type & print_length) {
62                 if (output++)
63                         putchar(' ');
64                 printf("%7d", length);
65         }
66         if (*name) {
67                 printf(" %s", name);
68         }
69         putchar('\n');
70 }
71
72 static void wc_file(FILE * file, const char *name)
73 {
74         unsigned int lines = 0;
75         unsigned int words = 0;
76         unsigned int chars = 0;
77         unsigned int length = 0;
78         unsigned int linepos = 0;
79         char in_word = 0;
80         int c;
81
82         while ((c = getc(file)) != EOF) {
83                 chars++;
84                 switch (c) {
85                 case '\n':
86                         lines++;
87                 case '\r':
88                 case '\f':
89                         if (linepos > length)
90                                 length = linepos;
91                         linepos = 0;
92                         goto word_separator;
93                 case '\t':
94                         linepos += 8 - (linepos % 8);
95                         goto word_separator;
96                 case ' ':
97                         linepos++;
98                 case '\v':
99 word_separator:
100                         if (in_word) {
101                                 in_word = 0;
102                                 words++;
103                         }
104                         break;
105                 default:
106                         linepos++;
107                         in_word = 1;
108                         break;
109                 }
110         }
111         if (linepos > length) {
112                 length = linepos;
113         }
114         if (in_word) {
115                 words++;
116         }
117         print_counts(lines, words, chars, length, name);
118         total_lines += lines;
119         total_words += words;
120         total_chars += chars;
121         if (length > max_length) {
122                 max_length = length;
123         }
124 }
125
126 int wc_main(int argc, char **argv)
127 {
128         int opt;
129
130         while ((opt = getopt(argc, argv, "clLw")) > 0) {
131                 switch (opt) {
132                         case 'c':
133                                 print_type |= print_chars;
134                                 break;
135                         case 'l':
136                                 print_type |= print_lines;
137                                 break;
138                         case 'L':
139                                 print_type |= print_length;
140                                 break;
141                         case 'w':
142                                 print_type |= print_words;
143                                 break;
144                         default:
145                                 show_usage();
146                 }
147         }
148
149         if (print_type == 0) {
150                 print_type = print_lines | print_words | print_chars;
151         }
152
153         if (argv[optind] == NULL || strcmp(argv[optind], "-") == 0) {
154                 wc_file(stdin, "");
155         } else {
156                 unsigned short num_files_counted = 0;
157                 while (optind < argc) {
158                         if (print_type == print_chars) {
159                                 struct stat statbuf;
160                                 stat(argv[optind], &statbuf);
161                                 print_counts(0, 0, statbuf.st_size, 0, argv[optind]);
162                                 total_chars += statbuf.st_size;
163                         } else {
164                                 FILE *file;
165                                 file = xfopen(argv[optind], "r");
166                                 wc_file(file, argv[optind]);
167                                 fclose(file);
168                         }
169                         optind++;
170                         num_files_counted++;
171                 }
172                 if (num_files_counted > 1) {
173                         print_counts(total_lines, total_words, total_chars, max_length, "total");
174                 }
175         }
176
177         return(EXIT_SUCCESS);
178 }