]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - usr.bin/wc/wc.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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 #ifndef lint
35 static const char copyright[] =
36 "@(#) Copyright (c) 1980, 1987, 1991, 1993\n\
37         The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39
40 #if 0
41 #ifndef lint
42 static char sccsid[] = "@(#)wc.c        8.1 (Berkeley) 6/6/93";
43 #endif /* not lint */
44 #endif
45
46 #include <sys/cdefs.h>
47 __FBSDID("$FreeBSD$");
48
49 #include <sys/param.h>
50 #include <sys/stat.h>
51
52 #include <ctype.h>
53 #include <err.h>
54 #include <errno.h>
55 #include <fcntl.h>
56 #include <locale.h>
57 #include <stdint.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <unistd.h>
62 #include <wchar.h>
63 #include <wctype.h>
64
65 uintmax_t tlinect, twordct, tcharct, tlongline;
66 int doline, doword, dochar, domulti, dolongline;
67
68 static int      cnt(const char *);
69 static void     usage(void);
70
71 int
72 main(int argc, char *argv[])
73 {
74         int ch, errors, total;
75
76         (void) setlocale(LC_CTYPE, "");
77
78         while ((ch = getopt(argc, argv, "clmwL")) != -1)
79                 switch((char)ch) {
80                 case 'l':
81                         doline = 1;
82                         break;
83                 case 'w':
84                         doword = 1;
85                         break;
86                 case 'c':
87                         dochar = 1;
88                         domulti = 0;
89                         break;
90                 case 'L':
91                         dolongline = 1;
92                         break;
93                 case 'm':
94                         domulti = 1;
95                         dochar = 0;
96                         break;
97                 case '?':
98                 default:
99                         usage();
100                 }
101         argv += optind;
102         argc -= optind;
103
104         /* Wc's flags are on by default. */
105         if (doline + doword + dochar + domulti + dolongline == 0)
106                 doline = doword = dochar = 1;
107
108         errors = 0;
109         total = 0;
110         if (!*argv) {
111                 if (cnt((char *)NULL) != 0)
112                         ++errors;
113                 else
114                         (void)printf("\n");
115         }
116         else do {
117                 if (cnt(*argv) != 0)
118                         ++errors;
119                 else
120                         (void)printf(" %s\n", *argv);
121                 ++total;
122         } while(*++argv);
123
124         if (total > 1) {
125                 if (doline)
126                         (void)printf(" %7ju", tlinect);
127                 if (doword)
128                         (void)printf(" %7ju", twordct);
129                 if (dochar || domulti)
130                         (void)printf(" %7ju", tcharct);
131                 if (dolongline)
132                         (void)printf(" %7ju", tlongline);
133                 (void)printf(" total\n");
134         }
135         exit(errors == 0 ? 0 : 1);
136 }
137
138 static int
139 cnt(const char *file)
140 {
141         struct stat sb;
142         uintmax_t linect, wordct, charct, llct, tmpll;
143         int fd, len, warned;
144         size_t clen;
145         short gotsp;
146         u_char *p;
147         u_char buf[MAXBSIZE];
148         wchar_t wch;
149         mbstate_t mbs;
150
151         linect = wordct = charct = llct = tmpll = 0;
152         if (file == NULL) {
153                 file = "stdin";
154                 fd = STDIN_FILENO;
155         } else {
156                 if ((fd = open(file, O_RDONLY, 0)) < 0) {
157                         warn("%s: open", file);
158                         return (1);
159                 }
160                 if (doword || (domulti && MB_CUR_MAX != 1))
161                         goto word;
162                 /*
163                  * Line counting is split out because it's a lot faster to get
164                  * lines than to get words, since the word count requires some
165                  * logic.
166                  */
167                 if (doline) {
168                         while ((len = read(fd, buf, MAXBSIZE))) {
169                                 if (len == -1) {
170                                         warn("%s: read", file);
171                                         (void)close(fd);
172                                         return (1);
173                                 }
174                                 charct += len;
175                                 for (p = buf; len--; ++p)
176                                         if (*p == '\n') {
177                                                 if (tmpll > llct)
178                                                         llct = tmpll;
179                                                 tmpll = 0;
180                                                 ++linect;
181                                         } else
182                                                 tmpll++;
183                         }
184                         tlinect += linect;
185                         (void)printf(" %7ju", linect);
186                         if (dochar) {
187                                 tcharct += charct;
188                                 (void)printf(" %7ju", charct);
189                         }
190                         if (dolongline) {
191                                 if (llct > tlongline)
192                                         tlongline = llct;
193                                 (void)printf(" %7ju", tlongline);
194                         }
195                         (void)close(fd);
196                         return (0);
197                 }
198                 /*
199                  * If all we need is the number of characters and it's a
200                  * regular file, just stat the puppy.
201                  */
202                 if (dochar || domulti) {
203                         if (fstat(fd, &sb)) {
204                                 warn("%s: fstat", file);
205                                 (void)close(fd);
206                                 return (1);
207                         }
208                         if (S_ISREG(sb.st_mode)) {
209                                 (void)printf(" %7lld", (long long)sb.st_size);
210                                 tcharct += sb.st_size;
211                                 (void)close(fd);
212                                 return (0);
213                         }
214                 }
215         }
216
217         /* Do it the hard way... */
218 word:   gotsp = 1;
219         warned = 0;
220         memset(&mbs, 0, sizeof(mbs));
221         while ((len = read(fd, buf, MAXBSIZE)) != 0) {
222                 if (len == -1) {
223                         warn("%s: read", file);
224                         (void)close(fd);
225                         return (1);
226                 }
227                 p = buf;
228                 while (len > 0) {
229                         if (!domulti || MB_CUR_MAX == 1) {
230                                 clen = 1;
231                                 wch = (unsigned char)*p;
232                         } else if ((clen = mbrtowc(&wch, p, len, &mbs)) ==
233                             (size_t)-1) {
234                                 if (!warned) {
235                                         errno = EILSEQ;
236                                         warn("%s", file);
237                                         warned = 1;
238                                 }
239                                 memset(&mbs, 0, sizeof(mbs));
240                                 clen = 1;
241                                 wch = (unsigned char)*p;
242                         } else if (clen == (size_t)-2)
243                                 break;
244                         else if (clen == 0)
245                                 clen = 1;
246                         charct++;
247                         if (wch != L'\n')
248                                 tmpll++;
249                         len -= clen;
250                         p += clen;
251                         if (wch == L'\n') {
252                                 if (tmpll > llct)
253                                         llct = tmpll;
254                                 tmpll = 0;
255                                 ++linect;
256                         }
257                         if (iswspace(wch))
258                                 gotsp = 1;
259                         else if (gotsp) {
260                                 gotsp = 0;
261                                 ++wordct;
262                         }
263                 }
264         }
265         if (domulti && MB_CUR_MAX > 1)
266                 if (mbrtowc(NULL, NULL, 0, &mbs) == (size_t)-1 && !warned)
267                         warn("%s", file);
268         if (doline) {
269                 tlinect += linect;
270                 (void)printf(" %7ju", linect);
271         }
272         if (doword) {
273                 twordct += wordct;
274                 (void)printf(" %7ju", wordct);
275         }
276         if (dochar || domulti) {
277                 tcharct += charct;
278                 (void)printf(" %7ju", charct);
279         }
280         if (dolongline) {
281                 if (llct > tlongline)
282                         tlongline = llct;
283                 (void)printf(" %7ju", llct);
284         }
285         (void)close(fd);
286         return (0);
287 }
288
289 static void
290 usage()
291 {
292         (void)fprintf(stderr, "usage: wc [-Lclmw] [file ...]\n");
293         exit(1);
294 }