Expand PMF_FN_* macros.
[netbsd-mini2440.git] / games / number / number.c
blobf2afb75e94db6df56b4ce9d8f013af05b530d269
1 /* $NetBSD: number.c,v 1.12 2008/07/20 01:03:21 lukem Exp $ */
3 /*
4 * Copyright (c) 1988, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\
35 The Regents of the University of California. All rights reserved.");
36 #endif /* not lint */
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)number.c 8.3 (Berkeley) 5/4/95";
41 #else
42 __RCSID("$NetBSD: number.c,v 1.12 2008/07/20 01:03:21 lukem Exp $");
43 #endif
44 #endif /* not lint */
46 #include <sys/types.h>
48 #include <ctype.h>
49 #include <err.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
55 #define MAXNUM 65 /* Biggest number we handle. */
57 static const char *const name1[] = {
58 "", "one", "two", "three",
59 "four", "five", "six", "seven",
60 "eight", "nine", "ten", "eleven",
61 "twelve", "thirteen", "fourteen", "fifteen",
62 "sixteen", "seventeen", "eighteen", "nineteen",
64 *const name2[] = {
65 "", "ten", "twenty", "thirty",
66 "forty", "fifty", "sixty", "seventy",
67 "eighty", "ninety",
69 *const name3[] = {
70 "hundred", "thousand", "million", "billion",
71 "trillion", "quadrillion", "quintillion", "sextillion",
72 "septillion", "octillion", "nonillion", "decillion",
73 "undecillion", "duodecillion", "tredecillion", "quattuordecillion",
74 "quindecillion", "sexdecillion",
75 "septendecillion", "octodecillion",
76 "novemdecillion", "vigintillion",
79 int main(int, char *[]);
80 static void convert(char *);
81 static int number(const char *, int);
82 static void pfract(int);
83 static int unit(int, const char *);
84 static void usage(void) __dead;
86 static int lflag;
88 int
89 main(argc, argv)
90 int argc;
91 char *argv[];
93 int ch, first;
94 char line[256];
96 lflag = 0;
97 while ((ch = getopt(argc, argv, "l")) != -1)
98 switch (ch) {
99 case 'l':
100 lflag = 1;
101 break;
102 case '?':
103 default:
104 usage();
106 argc -= optind;
107 argv += optind;
109 if (*argv == NULL)
110 for (first = 1;
111 fgets(line, sizeof(line), stdin) != NULL; first = 0) {
112 if (strchr(line, '\n') == NULL)
113 errx(1, "line too long.");
114 if (!first)
115 (void)printf("...\n");
116 convert(line);
118 else
119 for (first = 1; *argv != NULL; first = 0, ++argv) {
120 if (!first)
121 (void)printf("...\n");
122 convert(*argv);
124 exit(0);
127 void
128 convert(line)
129 char *line;
131 int flen, len, rval;
132 char *p, *fraction;
134 flen = 0;
135 fraction = NULL;
136 for (p = line; *p != '\0' && *p != '\n'; ++p) {
137 if (isblank(*p)) {
138 if (p == line) {
139 ++line;
140 continue;
142 goto badnum;
144 if (isdigit((unsigned char)*p))
145 continue;
146 switch (*p) {
147 case '.':
148 if (fraction != NULL)
149 goto badnum;
150 fraction = p + 1;
151 *p = '\0';
152 break;
153 case '-':
154 if (p == line)
155 break;
156 /* FALLTHROUGH */
157 default:
158 badnum: errx(1, "illegal number: %s", line);
159 break;
162 *p = '\0';
164 if ((len = strlen(line)) > MAXNUM ||
165 (fraction != NULL && (flen = strlen(fraction)) > MAXNUM))
166 errx(1, "number too large, max %d digits.", MAXNUM);
168 if (*line == '-') {
169 (void)printf("minus%s", lflag ? " " : "\n");
170 ++line;
171 --len;
174 rval = len > 0 ? unit(len, line) : 0;
175 if (fraction != NULL && flen != 0)
176 for (p = fraction; *p != '\0'; ++p)
177 if (*p != '0') {
178 if (rval)
179 (void)printf("%sand%s",
180 lflag ? " " : "",
181 lflag ? " " : "\n");
182 if (unit(flen, fraction)) {
183 if (lflag)
184 (void)printf(" ");
185 pfract(flen);
186 rval = 1;
188 break;
190 if (!rval)
191 (void)printf("zero%s", lflag ? "" : ".\n");
192 if (lflag)
193 (void)printf("\n");
197 unit(len, p)
198 int len;
199 const char *p;
201 int off, rval;
203 rval = 0;
204 if (len > 3) {
205 if (len % 3) {
206 off = len % 3;
207 len -= off;
208 if (number(p, off)) {
209 rval = 1;
210 (void)printf(" %s%s",
211 name3[len / 3], lflag ? " " : ".\n");
213 p += off;
215 for (; len > 3; p += 3) {
216 len -= 3;
217 if (number(p, 3)) {
218 rval = 1;
219 (void)printf(" %s%s",
220 name3[len / 3], lflag ? " " : ".\n");
224 if (number(p, len)) {
225 if (!lflag)
226 (void)printf(".\n");
227 rval = 1;
229 return (rval);
233 number(p, len)
234 const char *p;
235 int len;
237 int val, rval;
239 rval = 0;
240 switch (len) {
241 case 3:
242 if (*p != '0') {
243 rval = 1;
244 (void)printf("%s hundred", name1[*p - '0']);
246 ++p;
247 /* FALLTHROUGH */
248 case 2:
249 val = (p[1] - '0') + (p[0] - '0') * 10;
250 if (val) {
251 if (rval)
252 (void)printf(" ");
253 if (val < 20)
254 (void)printf("%s", name1[val]);
255 else {
256 (void)printf("%s", name2[val / 10]);
257 if (val % 10)
258 (void)printf("-%s", name1[val % 10]);
260 rval = 1;
262 break;
263 case 1:
264 if (*p != '0') {
265 rval = 1;
266 (void)printf("%s", name1[*p - '0']);
269 return (rval);
272 void
273 pfract(len)
274 int len;
276 static const char *const pref[] = { "", "ten-", "hundred-" };
278 switch(len) {
279 case 1:
280 (void)printf("tenths.\n");
281 break;
282 case 2:
283 (void)printf("hundredths.\n");
284 break;
285 default:
286 (void)printf("%s%sths.\n", pref[len % 3], name3[len / 3]);
287 break;
291 void
292 usage()
294 (void)fprintf(stderr, "usage: number [# ...]\n");
295 exit(1);