18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni *
49b50d902SRodney W. Grimes * Copyright (c) 1980, 1987, 1991, 1993
59b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved.
69b50d902SRodney W. Grimes *
79b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without
89b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions
99b50d902SRodney W. Grimes * are met:
109b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
119b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer.
129b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
139b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
149b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
169b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software
179b50d902SRodney W. Grimes * without specific prior written permission.
189b50d902SRodney W. Grimes *
199b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
209b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
239b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299b50d902SRodney W. Grimes * SUCH DAMAGE.
309b50d902SRodney W. Grimes */
319b50d902SRodney W. Grimes
329e4c5144SMariusz Zaborski #include <sys/capsicum.h>
339b50d902SRodney W. Grimes #include <sys/param.h>
349b50d902SRodney W. Grimes #include <sys/stat.h>
352c51e5edSBruce Evans
369e4c5144SMariusz Zaborski #include <capsicum_helpers.h>
372c51e5edSBruce Evans #include <ctype.h>
38ebb42aeeSTim J. Robbins #include <errno.h>
399b50d902SRodney W. Grimes #include <fcntl.h>
40ae6fa8aeSAndrey A. Chernov #include <locale.h>
41dad64f0eSDag-Erling Smørgrav #include <stdbool.h>
42a821e36eSMike Barcroft #include <stdint.h>
439b50d902SRodney W. Grimes #include <stdio.h>
449b50d902SRodney W. Grimes #include <stdlib.h>
459b50d902SRodney W. Grimes #include <string.h>
462c51e5edSBruce Evans #include <unistd.h>
47149a123bSTim J. Robbins #include <wchar.h>
48e58245f7STim J. Robbins #include <wctype.h>
496711c482SMarcel Moolenaar #include <libxo/xo.h>
509b50d902SRodney W. Grimes
519e4c5144SMariusz Zaborski #include <libcasper.h>
529e4c5144SMariusz Zaborski #include <casper/cap_fileargs.h>
539e4c5144SMariusz Zaborski
54*6e6da538SBram #define WC_XO_VERSION "1"
55*6e6da538SBram
56dad64f0eSDag-Erling Smørgrav static const char *stdin_filename = "stdin";
57dad64f0eSDag-Erling Smørgrav
589e4c5144SMariusz Zaborski static fileargs_t *fa;
598df975a2SEd Schouten static uintmax_t tlinect, twordct, tcharct, tlongline;
60dad64f0eSDag-Erling Smørgrav static bool doline, doword, dochar, domulti, dolongline;
61c9a96406SPawel Jakub Dawidek static volatile sig_atomic_t siginfo;
626711c482SMarcel Moolenaar static xo_handle_t *stderr_handle;
639b50d902SRodney W. Grimes
64f09bc093SPawel Jakub Dawidek static void show_cnt(const char *file, uintmax_t linect, uintmax_t wordct,
65f09bc093SPawel Jakub Dawidek uintmax_t charct, uintmax_t llct);
663f330d7dSWarner Losh static int cnt(const char *);
673f330d7dSWarner Losh static void usage(void);
689b50d902SRodney W. Grimes
69f09bc093SPawel Jakub Dawidek static void
siginfo_handler(int sig __unused)70f09bc093SPawel Jakub Dawidek siginfo_handler(int sig __unused)
71f09bc093SPawel Jakub Dawidek {
72f09bc093SPawel Jakub Dawidek
73f09bc093SPawel Jakub Dawidek siginfo = 1;
74f09bc093SPawel Jakub Dawidek }
75f09bc093SPawel Jakub Dawidek
768ded906dSBryan Drewery static void
reset_siginfo(void)778ded906dSBryan Drewery reset_siginfo(void)
788ded906dSBryan Drewery {
798ded906dSBryan Drewery
808ded906dSBryan Drewery signal(SIGINFO, SIG_DFL);
818ded906dSBryan Drewery siginfo = 0;
828ded906dSBryan Drewery }
838ded906dSBryan Drewery
849b50d902SRodney W. Grimes int
main(int argc,char * argv[])85806abfccSJosef El-Rayes main(int argc, char *argv[])
869b50d902SRodney W. Grimes {
87a0cf59e6SSheldon Hearn int ch, errors, total;
889e4c5144SMariusz Zaborski cap_rights_t rights;
899b50d902SRodney W. Grimes
90ae6fa8aeSAndrey A. Chernov (void) setlocale(LC_CTYPE, "");
91ae6fa8aeSAndrey A. Chernov
926711c482SMarcel Moolenaar argc = xo_parse_args(argc, argv);
936711c482SMarcel Moolenaar if (argc < 0)
94dad64f0eSDag-Erling Smørgrav exit(EXIT_FAILURE);
956711c482SMarcel Moolenaar
96f45dd010SGiorgos Keramidas while ((ch = getopt(argc, argv, "clmwL")) != -1)
979b50d902SRodney W. Grimes switch((char)ch) {
989b50d902SRodney W. Grimes case 'l':
99dad64f0eSDag-Erling Smørgrav doline = true;
1009b50d902SRodney W. Grimes break;
1019b50d902SRodney W. Grimes case 'w':
102dad64f0eSDag-Erling Smørgrav doword = true;
1039b50d902SRodney W. Grimes break;
1049b50d902SRodney W. Grimes case 'c':
105dad64f0eSDag-Erling Smørgrav dochar = true;
106dad64f0eSDag-Erling Smørgrav domulti = false;
107ebb42aeeSTim J. Robbins break;
108f45dd010SGiorgos Keramidas case 'L':
109dad64f0eSDag-Erling Smørgrav dolongline = true;
110f45dd010SGiorgos Keramidas break;
111ebb42aeeSTim J. Robbins case 'm':
112dad64f0eSDag-Erling Smørgrav domulti = true;
113dad64f0eSDag-Erling Smørgrav dochar = false;
1149b50d902SRodney W. Grimes break;
1159b50d902SRodney W. Grimes case '?':
1169b50d902SRodney W. Grimes default:
1179b50d902SRodney W. Grimes usage();
1189b50d902SRodney W. Grimes }
1199b50d902SRodney W. Grimes argv += optind;
1209b50d902SRodney W. Grimes argc -= optind;
1219b50d902SRodney W. Grimes
1229e4c5144SMariusz Zaborski fa = fileargs_init(argc, argv, O_RDONLY, 0,
123d76eef34SEd Maste cap_rights_init(&rights, CAP_READ, CAP_FSTAT), FA_OPEN);
124dad64f0eSDag-Erling Smørgrav if (fa == NULL)
125dad64f0eSDag-Erling Smørgrav xo_err(EXIT_FAILURE, "Unable to initialize casper");
1269e4c5144SMariusz Zaborski caph_cache_catpages();
127dad64f0eSDag-Erling Smørgrav if (caph_limit_stdio() < 0)
128dad64f0eSDag-Erling Smørgrav xo_err(EXIT_FAILURE, "Unable to limit stdio");
129dad64f0eSDag-Erling Smørgrav if (caph_enter_casper() < 0)
130dad64f0eSDag-Erling Smørgrav xo_err(EXIT_FAILURE, "Unable to enter capability mode");
1319e4c5144SMariusz Zaborski
1329b50d902SRodney W. Grimes /* Wc's flags are on by default. */
133dad64f0eSDag-Erling Smørgrav if (!(doline || doword || dochar || domulti || dolongline))
134dad64f0eSDag-Erling Smørgrav doline = doword = dochar = true;
1359b50d902SRodney W. Grimes
1366711c482SMarcel Moolenaar stderr_handle = xo_create_to_file(stderr, XO_STYLE_TEXT, 0);
137*6e6da538SBram
138*6e6da538SBram xo_set_version(WC_XO_VERSION);
1396711c482SMarcel Moolenaar xo_open_container("wc");
1406711c482SMarcel Moolenaar xo_open_list("file");
1416711c482SMarcel Moolenaar
142d0bf8b5aSBryan Drewery (void)signal(SIGINFO, siginfo_handler);
1432c51e5edSBruce Evans errors = 0;
1449b50d902SRodney W. Grimes total = 0;
145dad64f0eSDag-Erling Smørgrav if (argc == 0) {
1466711c482SMarcel Moolenaar xo_open_instance("file");
147dad64f0eSDag-Erling Smørgrav if (cnt(NULL) != 0)
1482c51e5edSBruce Evans ++errors;
1496711c482SMarcel Moolenaar xo_close_instance("file");
150f09bc093SPawel Jakub Dawidek } else {
151dad64f0eSDag-Erling Smørgrav while (argc--) {
1526711c482SMarcel Moolenaar xo_open_instance("file");
153dad64f0eSDag-Erling Smørgrav if (cnt(*argv++) != 0)
1542c51e5edSBruce Evans ++errors;
1556711c482SMarcel Moolenaar xo_close_instance("file");
1569b50d902SRodney W. Grimes ++total;
157dad64f0eSDag-Erling Smørgrav }
1589b50d902SRodney W. Grimes }
159f09bc093SPawel Jakub Dawidek
160399d3485SMarcel Moolenaar xo_close_list("file");
161399d3485SMarcel Moolenaar
1626711c482SMarcel Moolenaar if (total > 1) {
1636711c482SMarcel Moolenaar xo_open_container("total");
164f09bc093SPawel Jakub Dawidek show_cnt("total", tlinect, twordct, tcharct, tlongline);
1656711c482SMarcel Moolenaar xo_close_container("total");
1666711c482SMarcel Moolenaar }
167399d3485SMarcel Moolenaar
1689e4c5144SMariusz Zaborski fileargs_free(fa);
1696711c482SMarcel Moolenaar xo_close_container("wc");
170dad64f0eSDag-Erling Smørgrav if (xo_finish() < 0)
171dad64f0eSDag-Erling Smørgrav xo_err(EXIT_FAILURE, "stdout");
172dad64f0eSDag-Erling Smørgrav exit(errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
1739b50d902SRodney W. Grimes }
1749b50d902SRodney W. Grimes
175f09bc093SPawel Jakub Dawidek static void
show_cnt(const char * file,uintmax_t linect,uintmax_t wordct,uintmax_t charct,uintmax_t llct)176f09bc093SPawel Jakub Dawidek show_cnt(const char *file, uintmax_t linect, uintmax_t wordct,
177f09bc093SPawel Jakub Dawidek uintmax_t charct, uintmax_t llct)
178f09bc093SPawel Jakub Dawidek {
1796711c482SMarcel Moolenaar xo_handle_t *xop;
180f09bc093SPawel Jakub Dawidek
181f09bc093SPawel Jakub Dawidek if (!siginfo)
1826711c482SMarcel Moolenaar xop = NULL;
183f09bc093SPawel Jakub Dawidek else {
1846711c482SMarcel Moolenaar xop = stderr_handle;
185f09bc093SPawel Jakub Dawidek siginfo = 0;
186f09bc093SPawel Jakub Dawidek }
187f09bc093SPawel Jakub Dawidek
188f09bc093SPawel Jakub Dawidek if (doline)
1896711c482SMarcel Moolenaar xo_emit_h(xop, " {:lines/%7ju/%ju}", linect);
190f09bc093SPawel Jakub Dawidek if (doword)
1916711c482SMarcel Moolenaar xo_emit_h(xop, " {:words/%7ju/%ju}", wordct);
192f09bc093SPawel Jakub Dawidek if (dochar || domulti)
1936711c482SMarcel Moolenaar xo_emit_h(xop, " {:characters/%7ju/%ju}", charct);
194f09bc093SPawel Jakub Dawidek if (dolongline)
1956711c482SMarcel Moolenaar xo_emit_h(xop, " {:long-lines/%7ju/%ju}", llct);
196dad64f0eSDag-Erling Smørgrav if (file != stdin_filename)
197985c93f0SMarcel Moolenaar xo_emit_h(xop, " {:filename/%s}\n", file);
198f09bc093SPawel Jakub Dawidek else
1996711c482SMarcel Moolenaar xo_emit_h(xop, "\n");
200f09bc093SPawel Jakub Dawidek }
201f09bc093SPawel Jakub Dawidek
202a821e36eSMike Barcroft static int
cnt(const char * file)203806abfccSJosef El-Rayes cnt(const char *file)
2049b50d902SRodney W. Grimes {
2055016d112SDag-Erling Smørgrav static char buf[MAXBSIZE];
2069b50d902SRodney W. Grimes struct stat sb;
207149a123bSTim J. Robbins mbstate_t mbs;
2085016d112SDag-Erling Smørgrav const char *p;
209dad64f0eSDag-Erling Smørgrav uintmax_t linect, wordct, charct, llct, tmpll;
210dad64f0eSDag-Erling Smørgrav ssize_t len;
211dad64f0eSDag-Erling Smørgrav size_t clen;
212dad64f0eSDag-Erling Smørgrav int fd;
213dad64f0eSDag-Erling Smørgrav wchar_t wch;
214dad64f0eSDag-Erling Smørgrav bool gotsp, warned;
2159b50d902SRodney W. Grimes
216f45dd010SGiorgos Keramidas linect = wordct = charct = llct = tmpll = 0;
217dad64f0eSDag-Erling Smørgrav if (file == NULL) {
2182c51e5edSBruce Evans fd = STDIN_FILENO;
219dad64f0eSDag-Erling Smørgrav file = stdin_filename;
220dad64f0eSDag-Erling Smørgrav } else if ((fd = fileargs_open(fa, file)) < 0) {
2216711c482SMarcel Moolenaar xo_warn("%s: open", file);
2222c51e5edSBruce Evans return (1);
223a0d038a4SWolfram Schneider }
224ebb42aeeSTim J. Robbins if (doword || (domulti && MB_CUR_MAX != 1))
2259b50d902SRodney W. Grimes goto word;
2269b50d902SRodney W. Grimes /*
2270dc7c9e6SConrad Meyer * If all we need is the number of characters and it's a regular file,
2280dc7c9e6SConrad Meyer * just stat it.
2299b50d902SRodney W. Grimes */
23084b851c2SConrad Meyer if (doline == 0 && dolongline == 0) {
2310dc7c9e6SConrad Meyer if (fstat(fd, &sb)) {
232dad64f0eSDag-Erling Smørgrav xo_warn("%s: fstat", file);
2330dc7c9e6SConrad Meyer (void)close(fd);
2340dc7c9e6SConrad Meyer return (1);
2350dc7c9e6SConrad Meyer }
2368e05c237SRicardo Branco /* pseudo-filesystems advertize a zero size */
2378e05c237SRicardo Branco if (S_ISREG(sb.st_mode) && sb.st_size > 0) {
2380dc7c9e6SConrad Meyer reset_siginfo();
2390dc7c9e6SConrad Meyer charct = sb.st_size;
2400dc7c9e6SConrad Meyer show_cnt(file, linect, wordct, charct, llct);
2410dc7c9e6SConrad Meyer tcharct += charct;
2420dc7c9e6SConrad Meyer (void)close(fd);
2430dc7c9e6SConrad Meyer return (0);
2440dc7c9e6SConrad Meyer }
2450dc7c9e6SConrad Meyer }
2460dc7c9e6SConrad Meyer /*
2470dc7c9e6SConrad Meyer * For files we can't stat, or if we need line counting, slurp the
2480dc7c9e6SConrad Meyer * file. Line counting is split out because it's a lot faster to get
2490dc7c9e6SConrad Meyer * lines than to get words, since the word count requires locale
2500dc7c9e6SConrad Meyer * handling.
2510dc7c9e6SConrad Meyer */
2525016d112SDag-Erling Smørgrav while ((len = read(fd, buf, sizeof(buf))) != 0) {
253dad64f0eSDag-Erling Smørgrav if (len < 0) {
254dad64f0eSDag-Erling Smørgrav xo_warn("%s: read", file);
2552c51e5edSBruce Evans (void)close(fd);
2562c51e5edSBruce Evans return (1);
2572c51e5edSBruce Evans }
2580dc7c9e6SConrad Meyer if (siginfo)
2590dc7c9e6SConrad Meyer show_cnt(file, linect, wordct, charct, llct);
2609b50d902SRodney W. Grimes charct += len;
26184b851c2SConrad Meyer if (doline || dolongline) {
262dad64f0eSDag-Erling Smørgrav for (p = buf; len > 0; --len, ++p) {
263f45dd010SGiorgos Keramidas if (*p == '\n') {
264f45dd010SGiorgos Keramidas if (tmpll > llct)
265f45dd010SGiorgos Keramidas llct = tmpll;
266f45dd010SGiorgos Keramidas tmpll = 0;
2679b50d902SRodney W. Grimes ++linect;
268dad64f0eSDag-Erling Smørgrav } else {
269f45dd010SGiorgos Keramidas tmpll++;
2709b50d902SRodney W. Grimes }
271de143041SConrad Meyer }
272dad64f0eSDag-Erling Smørgrav }
273dad64f0eSDag-Erling Smørgrav }
2748ded906dSBryan Drewery reset_siginfo();
275de143041SConrad Meyer if (doline)
2769b50d902SRodney W. Grimes tlinect += linect;
277f09bc093SPawel Jakub Dawidek if (dochar)
2789b50d902SRodney W. Grimes tcharct += charct;
27984b851c2SConrad Meyer if (dolongline && llct > tlongline)
280f45dd010SGiorgos Keramidas tlongline = llct;
281f09bc093SPawel Jakub Dawidek show_cnt(file, linect, wordct, charct, llct);
2829b50d902SRodney W. Grimes (void)close(fd);
2832c51e5edSBruce Evans return (0);
2849b50d902SRodney W. Grimes
2859b50d902SRodney W. Grimes /* Do it the hard way... */
286dad64f0eSDag-Erling Smørgrav word: gotsp = true;
287dad64f0eSDag-Erling Smørgrav warned = false;
288149a123bSTim J. Robbins memset(&mbs, 0, sizeof(mbs));
289dad64f0eSDag-Erling Smørgrav while ((len = read(fd, buf, sizeof(buf))) != 0) {
290dad64f0eSDag-Erling Smørgrav if (len < 0) {
291dad64f0eSDag-Erling Smørgrav xo_warn("%s: read", file);
2922c51e5edSBruce Evans (void)close(fd);
2932c51e5edSBruce Evans return (1);
2942c51e5edSBruce Evans }
295ebb42aeeSTim J. Robbins p = buf;
296ebb42aeeSTim J. Robbins while (len > 0) {
297f09bc093SPawel Jakub Dawidek if (siginfo)
298f09bc093SPawel Jakub Dawidek show_cnt(file, linect, wordct, charct, llct);
299ebb42aeeSTim J. Robbins if (!domulti || MB_CUR_MAX == 1) {
300ebb42aeeSTim J. Robbins clen = 1;
301ebb42aeeSTim J. Robbins wch = (unsigned char)*p;
302dad64f0eSDag-Erling Smørgrav } else if ((clen = mbrtowc(&wch, p, len, &mbs)) == 0) {
303dad64f0eSDag-Erling Smørgrav clen = 1;
304dad64f0eSDag-Erling Smørgrav } else if (clen == (size_t)-1) {
305ebb42aeeSTim J. Robbins if (!warned) {
306ebb42aeeSTim J. Robbins errno = EILSEQ;
307dad64f0eSDag-Erling Smørgrav xo_warn("%s", file);
308dad64f0eSDag-Erling Smørgrav warned = true;
309ebb42aeeSTim J. Robbins }
310149a123bSTim J. Robbins memset(&mbs, 0, sizeof(mbs));
311149a123bSTim J. Robbins clen = 1;
312149a123bSTim J. Robbins wch = (unsigned char)*p;
313dad64f0eSDag-Erling Smørgrav } else if (clen == (size_t)-2) {
314ebb42aeeSTim J. Robbins break;
315dad64f0eSDag-Erling Smørgrav }
316ebb42aeeSTim J. Robbins charct++;
317f45dd010SGiorgos Keramidas if (wch != L'\n')
318f45dd010SGiorgos Keramidas tmpll++;
319ebb42aeeSTim J. Robbins len -= clen;
320ebb42aeeSTim J. Robbins p += clen;
321f45dd010SGiorgos Keramidas if (wch == L'\n') {
322f45dd010SGiorgos Keramidas if (tmpll > llct)
323f45dd010SGiorgos Keramidas llct = tmpll;
324f45dd010SGiorgos Keramidas tmpll = 0;
3259b50d902SRodney W. Grimes ++linect;
326f45dd010SGiorgos Keramidas }
327dad64f0eSDag-Erling Smørgrav if (iswspace(wch)) {
328dad64f0eSDag-Erling Smørgrav gotsp = true;
329dad64f0eSDag-Erling Smørgrav } else if (gotsp) {
330dad64f0eSDag-Erling Smørgrav gotsp = false;
3319b50d902SRodney W. Grimes ++wordct;
3329b50d902SRodney W. Grimes }
3339b50d902SRodney W. Grimes }
3349b50d902SRodney W. Grimes }
3358ded906dSBryan Drewery reset_siginfo();
336dad64f0eSDag-Erling Smørgrav if (domulti && MB_CUR_MAX > 1) {
337149a123bSTim J. Robbins if (mbrtowc(NULL, NULL, 0, &mbs) == (size_t)-1 && !warned)
338dad64f0eSDag-Erling Smørgrav xo_warn("%s", file);
339dad64f0eSDag-Erling Smørgrav }
340f09bc093SPawel Jakub Dawidek if (doline)
3419b50d902SRodney W. Grimes tlinect += linect;
342f09bc093SPawel Jakub Dawidek if (doword)
3439b50d902SRodney W. Grimes twordct += wordct;
344f09bc093SPawel Jakub Dawidek if (dochar || domulti)
3459b50d902SRodney W. Grimes tcharct += charct;
34684b851c2SConrad Meyer if (dolongline && llct > tlongline)
347f45dd010SGiorgos Keramidas tlongline = llct;
348f09bc093SPawel Jakub Dawidek show_cnt(file, linect, wordct, charct, llct);
3499b50d902SRodney W. Grimes (void)close(fd);
3502c51e5edSBruce Evans return (0);
3519b50d902SRodney W. Grimes }
3529b50d902SRodney W. Grimes
353a821e36eSMike Barcroft static void
usage(void)3540970727fSEd Schouten usage(void)
3559b50d902SRodney W. Grimes {
3566711c482SMarcel Moolenaar xo_error("usage: wc [-Lclmw] [file ...]\n");
357dad64f0eSDag-Erling Smørgrav exit(EXIT_FAILURE);
3589b50d902SRodney W. Grimes }
359