Use an int to hold the result of fgetc (bug noted by David Kimdon).
[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         if (print_type & print_lines) {
46                 printf("%7d ", lines);
47         }
48         if (print_type & print_words) {
49                 printf("%7d ", words);
50         }
51         if (print_type & print_chars) {
52                 printf("%7d ", chars);
53         }
54         if (print_type & print_length) {
55                 printf("%7d ", length);
56         }
57         if (*name) {
58                 printf("%s", name);
59         }
60         putchar('\n');
61 }
62
63 static void wc_file(FILE * file, const char *name)
64 {
65         unsigned int lines = 0;
66         unsigned int words = 0;
67         unsigned int chars = 0;
68         unsigned int length = 0;
69         unsigned int linepos = 0;
70         char in_word = 0;
71         int c;
72
73         while ((c = getc(file)) != EOF) {
74                 chars++;
75                 switch (c) {
76                 case '\n':
77                         lines++;
78                 case '\r':
79                 case '\f':
80                         if (linepos > length)
81                                 length = linepos;
82                         linepos = 0;
83                         goto word_separator;
84                 case '\t':
85                         linepos += 8 - (linepos % 8);
86                         goto word_separator;
87                 case ' ':
88                         linepos++;
89                 case '\v':
90 word_separator:
91                         if (in_word) {
92                                 in_word = 0;
93                                 words++;
94                         }
95                         break;
96                 default:
97                         linepos++;
98                         in_word = 1;
99                         break;
100                 }
101         }
102         if (linepos > length) {
103                 length = linepos;
104         }
105         if (in_word) {
106                 words++;
107         }
108         print_counts(lines, words, chars, length, name);
109         total_lines += lines;
110         total_words += words;
111         total_chars += chars;
112         if (length > max_length) {
113                 max_length = length;
114         }
115 }
116
117 int wc_main(int argc, char **argv)
118 {
119         int opt;
120
121         while ((opt = getopt(argc, argv, "clLw")) > 0) {
122                 switch (opt) {
123                         case 'c':
124                                 print_type |= print_chars;
125                                 break;
126                         case 'l':
127                                 print_type |= print_lines;
128                                 break;
129                         case 'L':
130                                 print_type |= print_length;
131                                 break;
132                         case 'w':
133                                 print_type |= print_words;
134                                 break;
135                         default:
136                                 show_usage();
137                 }
138         }
139
140         if (print_type == 0) {
141                 print_type = print_lines | print_words | print_chars;
142         }
143
144         if (argv[optind] == NULL || strcmp(argv[optind], "-") == 0) {
145                 wc_file(stdin, "");
146         } else {
147                 unsigned short num_files_counted = 0;
148                 while (optind < argc) {
149                         if (print_type == print_chars) {
150                                 struct stat statbuf;
151                                 stat(argv[optind], &statbuf);
152                                 print_counts(0, 0, statbuf.st_size, 0, argv[optind]);
153                                 total_chars += statbuf.st_size;
154                         } else {
155                                 FILE *file;
156                                 file = xfopen(argv[optind], "r");
157                                 wc_file(file, argv[optind]);
158                                 fclose(file);
159                         }
160                         optind++;
161                         num_files_counted++;
162                 }
163                 if (num_files_counted > 1) {
164                         print_counts(total_lines, total_words, total_chars, max_length, "total");
165                 }
166         }
167
168         return(EXIT_SUCCESS);
169 }