]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/wc/wc.c
This commit was generated by cvs2svn to compensate for changes in r168433,
[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 #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;
66 int doline, doword, dochar, domulti;
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, "clmw")) != -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 'm':
91                         domulti = 1;
92                         dochar = 0;
93                         break;
94                 case '?':
95                 default:
96                         usage();
97                 }
98         argv += optind;
99         argc -= optind;
100
101         /* Wc's flags are on by default. */
102         if (doline + doword + dochar + domulti == 0)
103                 doline = doword = dochar = 1;
104
105         errors = 0;
106         total = 0;
107         if (!*argv) {
108                 if (cnt((char *)NULL) != 0)
109                         ++errors;
110                 else
111                         (void)printf("\n");
112         }
113         else do {
114                 if (cnt(*argv) != 0)
115                         ++errors;
116                 else
117                         (void)printf(" %s\n", *argv);
118                 ++total;
119         } while(*++argv);
120
121         if (total > 1) {
122                 if (doline)
123                         (void)printf(" %7ju", tlinect);
124                 if (doword)
125                         (void)printf(" %7ju", twordct);
126                 if (dochar || domulti)
127                         (void)printf(" %7ju", tcharct);
128                 (void)printf(" total\n");
129         }
130         exit(errors == 0 ? 0 : 1);
131 }
132
133 static int
134 cnt(const char *file)
135 {
136         struct stat sb;
137         uintmax_t linect, wordct, charct;
138         int fd, len, warned;
139         size_t clen;
140         short gotsp;
141         u_char *p;
142         u_char buf[MAXBSIZE];
143         wchar_t wch;
144         mbstate_t mbs;
145
146         linect = wordct = charct = 0;
147         if (file == NULL) {
148                 file = "stdin";
149                 fd = STDIN_FILENO;
150         } else {
151                 if ((fd = open(file, O_RDONLY, 0)) < 0) {
152                         warn("%s: open", file);
153                         return (1);
154                 }
155                 if (doword || (domulti && MB_CUR_MAX != 1))
156                         goto word;
157                 /*
158                  * Line counting is split out because it's a lot faster to get
159                  * lines than to get words, since the word count requires some
160                  * logic.
161                  */
162                 if (doline) {
163                         while ((len = read(fd, buf, MAXBSIZE))) {
164                                 if (len == -1) {
165                                         warn("%s: read", file);
166                                         (void)close(fd);
167                                         return (1);
168                                 }
169                                 charct += len;
170                                 for (p = buf; len--; ++p)
171                                         if (*p == '\n')
172                                                 ++linect;
173                         }
174                         tlinect += linect;
175                         (void)printf(" %7ju", linect);
176                         if (dochar) {
177                                 tcharct += charct;
178                                 (void)printf(" %7ju", charct);
179                         }
180                         (void)close(fd);
181                         return (0);
182                 }
183                 /*
184                  * If all we need is the number of characters and it's a
185                  * regular file, just stat the puppy.
186                  */
187                 if (dochar || domulti) {
188                         if (fstat(fd, &sb)) {
189                                 warn("%s: fstat", file);
190                                 (void)close(fd);
191                                 return (1);
192                         }
193                         if (S_ISREG(sb.st_mode)) {
194                                 (void)printf(" %7lld", (long long)sb.st_size);
195                                 tcharct += sb.st_size;
196                                 (void)close(fd);
197                                 return (0);
198                         }
199                 }
200         }
201
202         /* Do it the hard way... */
203 word:   gotsp = 1;
204         warned = 0;
205         memset(&mbs, 0, sizeof(mbs));
206         while ((len = read(fd, buf, MAXBSIZE)) != 0) {
207                 if (len == -1) {
208                         warn("%s: read", file);
209                         (void)close(fd);
210                         return (1);
211                 }
212                 p = buf;
213                 while (len > 0) {
214                         if (!domulti || MB_CUR_MAX == 1) {
215                                 clen = 1;
216                                 wch = (unsigned char)*p;
217                         } else if ((clen = mbrtowc(&wch, p, len, &mbs)) ==
218                             (size_t)-1) {
219                                 if (!warned) {
220                                         errno = EILSEQ;
221                                         warn("%s", file);
222                                         warned = 1;
223                                 }
224                                 memset(&mbs, 0, sizeof(mbs));
225                                 clen = 1;
226                                 wch = (unsigned char)*p;
227                         } else if (clen == (size_t)-2)
228                                 break;
229                         else if (clen == 0)
230                                 clen = 1;
231                         charct++;
232                         len -= clen;
233                         p += clen;
234                         if (wch == L'\n')
235                                 ++linect;
236                         if (iswspace(wch))
237                                 gotsp = 1;
238                         else if (gotsp) {
239                                 gotsp = 0;
240                                 ++wordct;
241                         }
242                 }
243         }
244         if (domulti && MB_CUR_MAX > 1)
245                 if (mbrtowc(NULL, NULL, 0, &mbs) == (size_t)-1 && !warned)
246                         warn("%s", file);
247         if (doline) {
248                 tlinect += linect;
249                 (void)printf(" %7ju", linect);
250         }
251         if (doword) {
252                 twordct += wordct;
253                 (void)printf(" %7ju", wordct);
254         }
255         if (dochar || domulti) {
256                 tcharct += charct;
257                 (void)printf(" %7ju", charct);
258         }
259         (void)close(fd);
260         return (0);
261 }
262
263 static void
264 usage()
265 {
266         (void)fprintf(stderr, "usage: wc [-clmw] [file ...]\n");
267         exit(1);
268 }