]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - games/number/number.c
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / games / number / number.c
1 /*
2  * Copyright (c) 1988, 1993, 1994
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. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #ifndef lint
31 static const char copyright[] =
32 "@(#) Copyright (c) 1988, 1993, 1994\n\
33         The Regents of the University of California.  All rights reserved.\n";
34 #endif /* not lint */
35
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)number.c    8.3 (Berkeley) 5/4/95";
39 #endif
40 static const char rcsid[] =
41  "$FreeBSD$";
42 #endif /* not lint */
43
44 #include <sys/types.h>
45
46 #include <ctype.h>
47 #include <err.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <unistd.h>
52
53 #define MAXNUM          65              /* Biggest number we handle. */
54
55 static const char       *name1[] = {
56         "",             "one",          "two",          "three",
57         "four",         "five",         "six",          "seven",
58         "eight",        "nine",         "ten",          "eleven",
59         "twelve",       "thirteen",     "fourteen",     "fifteen",
60         "sixteen",      "seventeen",    "eighteen",     "nineteen",
61 },
62                 *name2[] = {
63         "",             "ten",          "twenty",       "thirty",
64         "forty",        "fifty",        "sixty",        "seventy",
65         "eighty",       "ninety",
66 },
67                 *name3[] = {
68         "hundred",      "thousand",     "million",      "billion",
69         "trillion",     "quadrillion",  "quintillion",  "sextillion",
70         "septillion",   "octillion",    "nonillion",    "decillion",
71         "undecillion",  "duodecillion", "tredecillion", "quattuordecillion",
72         "quindecillion",                "sexdecillion",
73         "septendecillion",              "octodecillion",
74         "novemdecillion",               "vigintillion",
75 };
76
77 void    convert(char *);
78 int     number(char *, int);
79 void    pfract(int);
80 void    toobig(void);
81 int     unit(int, char *);
82 void    usage(void);
83
84 int lflag;
85
86 int
87 main(int argc, char *argv[])
88 {
89         int ch, first;
90         char line[256];
91
92         lflag = 0;
93         while ((ch = getopt(argc, argv, "l")) != -1)
94                 switch (ch) {
95                 case 'l':
96                         lflag = 1;
97                         break;
98                 case '?':
99                 default:
100                         usage();
101                 }
102         argc -= optind;
103         argv += optind;
104
105         if (*argv == NULL)
106                 for (first = 1;
107                     fgets(line, sizeof(line), stdin) != NULL; first = 0) {
108                         if (strchr(line, '\n') == NULL)
109                                 errx(1, "line too long.");
110                         if (!first)
111                                 (void)printf("...\n");
112                         convert(line);
113                 }
114         else
115                 for (first = 1; *argv != NULL; first = 0, ++argv) {
116                         if (!first)
117                                 (void)printf("...\n");
118                         convert(*argv);
119                 }
120         exit(0);
121 }
122
123 void
124 convert(char *line)
125 {
126         int flen, len, rval;
127         char *p, *fraction;
128
129         flen = 0;
130         fraction = NULL;
131         for (p = line; *p != '\0' && *p != '\n'; ++p) {
132                 if (isblank(*p)) {
133                         if (p == line) {
134                                 ++line;
135                                 continue;
136                         }
137                         goto badnum;
138                 }
139                 if (isdigit(*p))
140                         continue;
141                 switch (*p) {
142                 case '.':
143                         if (fraction != NULL)
144                                 goto badnum;
145                         fraction = p + 1;
146                         *p = '\0';
147                         break;
148                 case '-':
149                         if (p == line)
150                                 break;
151                         /* FALLTHROUGH */
152                 default:
153 badnum:                 errx(1, "illegal number: %s", line);
154                         break;
155                 }
156         }
157         *p = '\0';
158
159         if ((len = strlen(line)) > MAXNUM ||
160             (fraction != NULL && ((flen = strlen(fraction)) > MAXNUM)))
161                 errx(1, "number too large, max %d digits.", MAXNUM);
162
163         if (*line == '-') {
164                 (void)printf("minus%s", lflag ? " " : "\n");
165                 ++line;
166                 --len;
167         }
168
169         rval = len > 0 ? unit(len, line) : 0;
170         if (fraction != NULL && flen != 0)
171                 for (p = fraction; *p != '\0'; ++p)
172                         if (*p != '0') {
173                                 if (rval)
174                                         (void)printf("%sand%s",
175                                             lflag ? " " : "",
176                                             lflag ? " " : "\n");
177                                 if (unit(flen, fraction)) {
178                                         if (lflag)
179                                                 (void)printf(" ");
180                                         pfract(flen);
181                                         rval = 1;
182                                 }
183                                 break;
184                         }
185         if (!rval)
186                 (void)printf("zero%s", lflag ? "" : ".\n");
187         if (lflag)
188                 (void)printf("\n");
189 }
190
191 int
192 unit(int len, char *p)
193 {
194         int off, rval;
195
196         rval = 0;
197         if (len > 3) {
198                 if (len % 3) {
199                         off = len % 3;
200                         len -= off;
201                         if (number(p, off)) {
202                                 rval = 1;
203                                 (void)printf(" %s%s",
204                                     name3[len / 3], lflag ? " " : ".\n");
205                         }
206                         p += off;
207                 }
208                 for (; len > 3; p += 3) {
209                         len -= 3;
210                         if (number(p, 3)) {
211                                 rval = 1;
212                                 (void)printf(" %s%s",
213                                     name3[len / 3], lflag ? " " : ".\n");
214                         }
215                 }
216         }
217         if (number(p, len)) {
218                 if (!lflag)
219                         (void)printf(".\n");
220                 rval = 1;
221         }
222         return (rval);
223 }
224
225 int
226 number(char *p, int len)
227 {
228         int val, rval;
229
230         rval = 0;
231         switch (len) {
232         case 3:
233                 if (*p != '0') {
234                         rval = 1;
235                         (void)printf("%s hundred", name1[*p - '0']);
236                 }
237                 ++p;
238                 /* FALLTHROUGH */
239         case 2:
240                 val = (p[1] - '0') + (p[0] - '0') * 10;
241                 if (val) {
242                         if (rval)
243                                 (void)printf(" ");
244                         if (val < 20)
245                                 (void)printf("%s", name1[val]);
246                         else {
247                                 (void)printf("%s", name2[val / 10]);
248                                 if (val % 10)
249                                         (void)printf("-%s", name1[val % 10]);
250                         }
251                         rval = 1;
252                 }
253                 break;
254         case 1:
255                 if (*p != '0') {
256                         rval = 1;
257                         (void)printf("%s", name1[*p - '0']);
258                 }
259         }
260         return (rval);
261 }
262
263 void
264 pfract(int len)
265 {
266         static char const * const pref[] = { "", "ten-", "hundred-" };
267
268         switch(len) {
269         case 1:
270                 (void)printf("tenths.\n");
271                 break;
272         case 2:
273                 (void)printf("hundredths.\n");
274                 break;
275         default:
276                 (void)printf("%s%sths.\n", pref[len % 3], name3[len / 3]);
277                 break;
278         }
279 }
280
281 void
282 usage(void)
283 {
284         (void)fprintf(stderr, "usage: number [-l] [# ...]\n");
285         exit(1);
286 }