wc: Added wc
[mutos-utils.git] / wc.c
blob084efda585764d9cbfa9368897c063920a4cc6ef
1 /*
2 Copyright © 2013 Alastair Stuart
4 This program is open source software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
15 #include <errno.h>
16 #include <ctype.h>
17 #include <stdbool.h>
18 #include <stdio.h>
19 #include <string.h>
21 #include <getopt.h>
22 #include <sys/stat.h>
24 #define VERSION "0.01"
26 struct {
27 bool lines;
28 bool words;
29 bool chars;
30 bool bytes;
31 } flags;
33 size_t total_lines = 0;
34 size_t total_words = 0;
35 size_t total_chars = 0;
37 void usage(char* program)
39 printf("Usage: %s [options] [file ...]\n", program);
40 printf("Counts words, lines, and characters.\n"
41 "\n"
42 " -c, --bytes Print the number of bytes.\n"
43 " -m, --chars Print the number of characters.\n"
44 " -l, --lines Print the number of lines.\n"
45 " -w, --words Print the number of words.\n"
46 "\n"
47 " --help Print this message.\n"
48 " --version Show version info.\n"
49 "\n"
50 "If no file is given or file is '-', standard input is read.\n");
53 void word_count(FILE* file)
55 size_t lines = 0;
56 size_t words = 0;
57 size_t chars = 0;
59 int c = !EOF;
60 int c2 = fgetc(file);
61 while (c != EOF || c2 != EOF)
63 chars++;
64 if (c == '\n') {
65 lines++;
68 if ((isprint(c) && !isblank(c) && c != '\n') &&
69 (isblank(c2) || c2 == EOF || c2 == '\n')) {
70 words++;
73 c = c2;
74 c2 = fgetc(file);
76 chars--; // reading 2 characters at once
77 // causes chars to miscount
79 total_lines += lines;
80 total_words += words;
81 total_chars += chars;
83 if (flags.lines) {
84 printf("%zu\t", lines);
86 if (flags.words) {
87 printf("%zu\t", words);
89 if (flags.chars) {
90 printf("%zu\t", chars);
92 if (flags.bytes) {
93 printf("%zu\t", chars);
97 int main(int argc, char* argv[])
99 bool errors = false;
101 static struct option long_options[] = {
102 {"bytes", no_argument, NULL, 'c'},
103 {"chars", no_argument, NULL, 'm'},
104 {"lines", no_argument, NULL, 'l'},
105 {"words", no_argument, NULL, 'w'},
106 {"help", no_argument, NULL, 1},
107 {"version", no_argument, NULL, 2},
108 {NULL, 0, NULL, 0}
111 int c = 0;
112 while ((c = getopt_long(argc, argv, "cmlw",
113 long_options, NULL)) != -1)
115 switch (c)
117 case 'c':
118 flags.bytes = true;
119 break;
120 case 'm':
121 flags.chars = true;
122 break;
123 case 'l':
124 flags.lines = true;
125 break;
126 case 'w':
127 flags.words = true;
128 break;
129 case 1:
130 usage(argv[0]);
131 return 0;
132 case 2:
133 printf("wc (mutos) v"VERSION"\n");
134 return 0;
135 default:
136 fprintf(stderr, "Run '%s --help' for usage.\n",
137 argv[0]);
138 return 1;
142 // default columns
143 if (!flags.bytes && !flags.chars && !flags.lines && !flags.words) {
144 flags.lines = true;
145 flags.words = true;
146 flags.chars = true;
149 if ((argc - optind) == 0) {
150 word_count(stdin);
151 printf("\n");
154 FILE* file_array[argc - optind];
155 memset(file_array, 0, sizeof(FILE*) * (argc - optind));
157 for (int i = optind, j = 0; i < argc; i++, j++)
159 struct stat s;
160 stat(argv[i], &s);
162 if (strcmp(argv[i], "-") == 0) {
163 file_array[j] = stdin;
164 } else if (s.st_mode & S_IFDIR) { // we can't word count a directory
165 file_array[j] = NULL;
166 fprintf(stderr, "%s: %s: %s\n",
167 argv[0], "Is a directory", argv[i]);
168 errors = true;
169 } else {
170 file_array[j] = fopen(argv[i], "r");
174 size_t num_files = 0;
175 for (int i = 0; i < (argc - optind); i++)
177 if (file_array[i]) {
178 word_count(file_array[i]);
179 printf("%s\n", argv[optind + i]);
180 num_files++;
184 if (num_files > 1) {
185 if (flags.lines) {
186 printf("%zu\t", total_lines);
188 if (flags.words) {
189 printf("%zu\t", total_words);
191 if (flags.chars) {
192 printf("%zu\t", total_chars);
194 if (flags.bytes) {
195 printf("%zu\t", total_chars);
197 printf("total\n");
200 if (errors) {
201 return 1;
202 } else {
203 return 0;