]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/wc/wc.c
This commit was generated by cvs2svn to compensate for changes in r91116,
[FreeBSD/FreeBSD.git] / usr.bin / wc / wc.c
1 /*
2  * Copyright (c) 1980, 1987, 1991, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include <sys/cdefs.h>
35
36 __FBSDID("$FreeBSD$");
37
38 #ifndef lint
39 static const char copyright[] =
40 "@(#) Copyright (c) 1980, 1987, 1991, 1993\n\
41         The Regents of the University of California.  All rights reserved.\n";
42 #endif
43
44 #ifndef lint
45 static const char sccsid[] = "@(#)wc.c  8.1 (Berkeley) 6/6/93";
46 #endif
47
48 #include <sys/param.h>
49 #include <sys/stat.h>
50
51 #include <ctype.h>
52 #include <err.h>
53 #include <fcntl.h>
54 #include <locale.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <unistd.h>
59
60 u_quad_t tlinect, twordct, tcharct;
61 int doline, doword, dochar;
62
63 int cnt __P((const char *));
64 void usage __P((void));
65
66 int
67 main(argc, argv)
68         int argc;
69         char *argv[];
70 {
71         int ch, errors, total;
72
73         (void) setlocale(LC_CTYPE, "");
74
75         while ((ch = getopt(argc, argv, "lwc")) != -1)
76                 switch((char)ch) {
77                 case 'l':
78                         doline = 1;
79                         break;
80                 case 'w':
81                         doword = 1;
82                         break;
83                 case 'c':
84                         dochar = 1;
85                         break;
86                 case '?':
87                 default:
88                         usage();
89                 }
90         argv += optind;
91         argc -= optind;
92
93         /* Wc's flags are on by default. */
94         if (doline + doword + dochar == 0)
95                 doline = doword = dochar = 1;
96
97         errors = 0;
98         total = 0;
99         if (!*argv) {
100                 if (cnt((char *)NULL) != 0)
101                         ++errors;
102                 else
103                         (void)printf("\n");
104         }
105         else do {
106                 if (cnt(*argv) != 0)
107                         ++errors;
108                 else
109                         (void)printf(" %s\n", *argv);
110                 ++total;
111         } while(*++argv);
112
113         if (total > 1) {
114                 if (doline)
115                         (void)printf(" %7qu", tlinect);
116                 if (doword)
117                         (void)printf(" %7qu", twordct);
118                 if (dochar)
119                         (void)printf(" %7qu", tcharct);
120                 (void)printf(" total\n");
121         }
122         exit(errors == 0 ? 0 : 1);
123 }
124
125 int
126 cnt(file)
127         const char *file;
128 {
129         struct stat sb;
130         u_quad_t linect, wordct, charct;
131         int fd, len;
132         short gotsp;
133         u_char *p;
134         u_char buf[MAXBSIZE], ch;
135
136         linect = wordct = charct = 0;
137         if (file == NULL) {
138                 file = "stdin";
139                 fd = STDIN_FILENO;
140         } else {
141                 if ((fd = open(file, O_RDONLY, 0)) < 0) {
142                         warn("%s: open", file);
143                         return (1);
144                 }
145                 if (doword)
146                         goto word;
147                 /*
148                  * Line counting is split out because it's a lot faster to get
149                  * lines than to get words, since the word count requires some
150                  * logic.
151                  */
152                 if (doline) {
153                         while ((len = read(fd, buf, MAXBSIZE))) {
154                                 if (len == -1) {
155                                         warn("%s: read", file);
156                                         (void)close(fd);
157                                         return (1);
158                                 }
159                                 charct += len;
160                                 for (p = buf; len--; ++p)
161                                         if (*p == '\n')
162                                                 ++linect;
163                         }
164                         tlinect += linect;
165                         (void)printf(" %7qu", linect);
166                         if (dochar) {
167                                 tcharct += charct;
168                                 (void)printf(" %7qu", charct);
169                         }
170                         (void)close(fd);
171                         return (0);
172                 }
173                 /*
174                  * If all we need is the number of characters and it's a
175                  * regular or linked file, just stat the puppy.
176                  */
177                 if (dochar) {
178                         if (fstat(fd, &sb)) {
179                                 warn("%s: fstat", file);
180                                 (void)close(fd);
181                                 return (1);
182                         }
183                         if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) {
184                                 (void)printf(" %7lld", (long long)sb.st_size);
185                                 tcharct += sb.st_size;
186                                 (void)close(fd);
187                                 return (0);
188                         }
189                 }
190         }
191
192         /* Do it the hard way... */
193 word:   for (gotsp = 1; (len = read(fd, buf, MAXBSIZE));) {
194                 if (len == -1) {
195                         warn("%s: read", file);
196                         (void)close(fd);
197                         return (1);
198                 }
199                 /*
200                  * This loses in the presence of multi-byte characters.
201                  * To do it right would require a function to return a
202                  * character while knowing how many bytes it consumed.
203                  */
204                 charct += len;
205                 for (p = buf; len--;) {
206                         ch = *p++;
207                         if (ch == '\n')
208                                 ++linect;
209                         if (isspace(ch))
210                                 gotsp = 1;
211                         else if (gotsp) {
212                                 gotsp = 0;
213                                 ++wordct;
214                         }
215                 }
216         }
217         if (doline) {
218                 tlinect += linect;
219                 (void)printf(" %7qu", linect);
220         }
221         if (doword) {
222                 twordct += wordct;
223                 (void)printf(" %7qu", wordct);
224         }
225         if (dochar) {
226                 tcharct += charct;
227                 (void)printf(" %7qu", charct);
228         }
229         (void)close(fd);
230         return (0);
231 }
232
233 void
234 usage()
235 {
236         (void)fprintf(stderr, "usage: wc [-clw] [file ...]\n");
237         exit(1);
238 }