Practice 12.
wcount as a Unix utility
In the Practice 4 we implemented a simple wcount program to count the number of newlines, words and characters reading from the standard input. However, real Unix utilities are more complex, they can read from files given as command line parameters. In this practice, we will implement such a version of wcount.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
//
// wcount -- similar to unix wc command
// counts newlines, words and characters
// v2. reading from standard input or from files
//
#include <iostream>
#include <fstream> // for std::ifstream
#include <iomanip> // for std::setw
#include <cctype> // for std::isspace
#include <cerrno> // for std::errno
#include <cstring> // for std::strerror
#include <clocale> // for std::setlocale
// this function will do the actual job for a single file
void wcount(std::istream &inp, std::string filename);
// this variables will collect the summary information
int slcount = 0; // sum newlines
int swcount = 0; // sum words
int sccount = 0; // sum characters
int main(int argc, char*argv[])
{
int exit_code = 0; // exit code of process
// 0 == no error,
// 1 == at least one file failed
if ( argc < 2 ) // no parameter: read from cin
{
wcount( std::cin, "");
}
else // there are filename parameters
{
for ( int i = 1; i < argc; ++i)
{
std::ifstream inp(argv[i]);
if ( inp ) // open succesful
{
wcount( inp, argv[i]);
}
else // open failed
{
// set the language to locale
std::setlocale(LC_ALL, "hu_HU.utf8");
// convert readable error message from errno
std::cerr << argv[i] << ": "
<< std::strerror(errno) << '\n';
exit_code = 1;
}
}
if ( argc > 2 ) // more than 1 files: write summary
{
std::cout << std::right << std::setw(6) << slcount
<< " " << std::right << std::setw(6) << swcount
<< " " << std::right << std::setw(6) << sccount
<< " \tsummary" << '\n';
}
}
return exit_code; // for the operating system
}
// counting one file or cin until EOF
void wcount(std::istream &inp, std::string filename)
{
int lcount = 0; // newlines
int wcount = 0; // words
int ccount = 0; // characters
char ch; // current character to read in
char prev = '\n'; // previous char for wcount initialized
// to whitespace for the very first word
// at the beginning of the input
inp >> std::noskipws; // otherwise operator>> skips
// whitespace characters
while ( inp >> ch ) // true until reading fails
{
++ccount;
if ( '\n' == ch ) ++lcount; // literal on the left
if ( std::isspace(prev) && !std::isspace(ch) ) ++wcount;
prev = ch;
}
// print results for this file
std::cout << std::right << std::setw(6) << lcount
<< " " << std::right << std::setw(6) << wcount
<< " " << std::right << std::setw(6) << ccount
<< " \t" << filename << '\n';
// update summary
slcount += lcount;
swcount += wcount;
sccount += ccount;
}
The program can be tested against the standard input or given one or more filename parameters. If any of filename parameters missing an error message should appear on standard error.
$ g++ -Wall -Wextra wcount2.cpp -o wcount
$ ./wcount < wcount2.cpp
83 344 2218
$ ./wcount wcount1.cpp wcount2.cpp
31 146 873 wcount1.cpp
83 344 2218 wcount2.cpp
114 490 3091 summary
$ ./wcount wcount1.cpp nonexist.cpp wcount2.cpp
31 146 873 wcount1.cpp
nonexist.cpp: Nincs ilyen fájl vagy könyvtár
83 344 2218 wcount2.cpp
114 490 3091 summary
Financed from the financial support ELTE won from the Higher Education
Restructuring Fund of the Hungarian Government.