File: | src/games/number/number.c |
Warning: | line 92, column 2 Value stored to 'argc' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: number.c,v 1.20 2016/03/07 12:07:56 mestre Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1988, 1993, 1994 |
5 | * The Regents of the University of California. All rights reserved. |
6 | * |
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. |
18 | * |
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. |
30 | */ |
31 | |
32 | #include <ctype.h> |
33 | #include <err.h> |
34 | #include <stdio.h> |
35 | #include <stdlib.h> |
36 | #include <string.h> |
37 | #include <unistd.h> |
38 | |
39 | #define MAXNUM65 65 /* Biggest number we handle. */ |
40 | #define LINELEN256 256 |
41 | |
42 | static const char *const name1[] = { |
43 | "", "one", "two", "three", |
44 | "four", "five", "six", "seven", |
45 | "eight", "nine", "ten", "eleven", |
46 | "twelve", "thirteen", "fourteen", "fifteen", |
47 | "sixteen", "seventeen", "eighteen", "nineteen", |
48 | }, |
49 | *const name2[] = { |
50 | "", "ten", "twenty", "thirty", |
51 | "forty", "fifty", "sixty", "seventy", |
52 | "eighty", "ninety", |
53 | }, |
54 | *const name3[] = { |
55 | "hundred", "thousand", "million", "billion", |
56 | "trillion", "quadrillion", "quintillion", "sextillion", |
57 | "septillion", "octillion", "nonillion", "decillion", |
58 | "undecillion", "duodecillion", "tredecillion", "quattuordecillion", |
59 | "quindecillion", "sexdecillion", |
60 | "septendecillion", "octodecillion", |
61 | "novemdecillion", "vigintillion", |
62 | }; |
63 | |
64 | void convert(char *); |
65 | void convertexp(char *); |
66 | int number(const char *, int); |
67 | void pfract(int); |
68 | int unit(int, const char *); |
69 | __dead__attribute__((__noreturn__)) void usage(void); |
70 | |
71 | int lflag; |
72 | |
73 | int |
74 | main(int argc, char *argv[]) |
75 | { |
76 | int ch, first; |
77 | char line[LINELEN256]; |
78 | |
79 | if (pledge("stdio", NULL((void *)0)) == -1) |
80 | err(1, "pledge"); |
81 | |
82 | lflag = 0; |
83 | while ((ch = getopt(argc, argv, "hl")) != -1) |
84 | switch (ch) { |
85 | case 'l': |
86 | lflag = 1; |
87 | break; |
88 | case 'h': |
89 | default: |
90 | usage(); |
91 | } |
92 | argc -= optind; |
Value stored to 'argc' is never read | |
93 | argv += optind; |
94 | |
95 | if (*argv == NULL((void *)0)) |
96 | for (first = 1; |
97 | fgets(line, sizeof(line), stdin(&__sF[0])) != NULL((void *)0); first = 0) { |
98 | if (strchr(line, '\n') == NULL((void *)0)) |
99 | errx(1, "line too long."); |
100 | if (!first) |
101 | (void)printf("...\n"); |
102 | convert(line); |
103 | if (lflag) |
104 | (void)printf("\n"); |
105 | } |
106 | else |
107 | for (first = 1; *argv != NULL((void *)0); first = 0, ++argv) { |
108 | if (!first) |
109 | (void)printf("...\n"); |
110 | convert(*argv); |
111 | if (lflag) |
112 | (void)printf("\n"); |
113 | } |
114 | return 0; |
115 | } |
116 | |
117 | void |
118 | convert(char *line) |
119 | { |
120 | int flen, len, rval; |
121 | char *p, *fraction; |
122 | |
123 | /* strip trailing and leading whitespace */ |
124 | len = strlen(line) - 1; |
125 | while ((isblank((unsigned char)line[len])) || (line[len] == '\n')) |
126 | line[len--] = '\0'; |
127 | while ((isblank((unsigned char)line[0])) || (line[0] == '\n')) |
128 | line++; |
129 | if (strchr(line, 'e') || strchr(line, 'E')) |
130 | convertexp(line); |
131 | else { |
132 | fraction = NULL((void *)0); |
133 | for (p = line; *p != '\0' && *p != '\n'; ++p) { |
134 | if (isblank((unsigned char)*p)) |
135 | goto badnum; |
136 | if (isdigit((unsigned char)*p)) |
137 | continue; |
138 | switch (*p) { |
139 | case '.': |
140 | if (fraction != NULL((void *)0)) |
141 | goto badnum; |
142 | fraction = p + 1; |
143 | *p = '\0'; |
144 | break; |
145 | case '-': |
146 | case '+': |
147 | if (p == line) |
148 | break; |
149 | /* FALLTHROUGH */ |
150 | default: |
151 | badnum: errx(1, "illegal number: %s", line); |
152 | break; |
153 | } |
154 | } |
155 | *p = '\0'; |
156 | |
157 | if ((len = strlen(line)) > MAXNUM65 || |
158 | ((fraction != NULL((void *)0)) && (flen = strlen(fraction)) > MAXNUM65)) |
159 | errx(1, "number too long (max %d digits).", MAXNUM65); |
160 | |
161 | if (*line == '-') { |
162 | (void)printf("minus%s", lflag ? " " : "\n"); |
163 | ++line; |
164 | --len; |
165 | } |
166 | if (*line == '+') { |
167 | (void)printf("plus%s", lflag ? " " : "\n"); |
168 | ++line; |
169 | --len; |
170 | } |
171 | |
172 | rval = len > 0 ? unit(len, line) : 0; |
173 | if (fraction != NULL((void *)0) && flen != 0) |
174 | for (p = fraction; *p != '\0'; ++p) |
175 | if (*p != '0') { |
176 | if (rval) |
177 | (void)printf("%sand%s", |
178 | lflag ? " " : "", |
179 | lflag ? " " : "\n"); |
180 | if (unit(flen, fraction)) { |
181 | if (lflag) |
182 | (void)printf(" "); |
183 | pfract(flen); |
184 | rval = 1; |
185 | } |
186 | break; |
187 | } |
188 | if (!rval) |
189 | (void)printf("zero%s", lflag ? "" : ".\n"); |
190 | } |
191 | } |
192 | |
193 | void |
194 | convertexp(char *line) |
195 | { |
196 | char locline[LINELEN256]; |
197 | char *part1, *part2, *part3, *part4; |
198 | char tmp[2]; |
199 | int i, j; |
200 | |
201 | (void)strlcpy(locline,line,LINELEN256); |
202 | part3 = locline; |
203 | part2 = strsep(&part3, "eE"); /* part3 is the exponent */ |
204 | part4 = part3; |
205 | (void)strsep(&part4, "."); /* no decimal allowed in the exponent */ |
206 | if (part4) |
207 | errx(1, "illegal number: %s", line); |
208 | part1 = strsep(&part2, "."); /* we can have one in the mantissa */ |
209 | /* At this point everything should be null or a digit. Check for |
210 | * that before starting to convert. Two characters may be + or -. |
211 | */ |
212 | j = strlen(line); |
213 | for (i = 0; i < j; i++) |
214 | if ((!isdigit((unsigned char)locline[i])) && (locline[i])) |
215 | if (((locline[i] != '+') && (locline[i] != '-')) || |
216 | ((i != 0) && (i != part3 - locline))) |
217 | errx(1, "illegal number: %s", line); |
218 | convert(part1); |
219 | printf("%s", lflag ? " " : ""); |
220 | if (part2 && part2[0]) { /* do individual digits separately */ |
221 | (void)printf("point%s", lflag ? " " : "\n"); |
222 | j = strlen(part2); tmp[1] = '\0'; |
223 | for (i = 0 ; i < j; i++ ) { |
224 | tmp[0] = part2[i]; |
225 | convert(tmp); |
226 | (void)printf("%s", lflag ? " " : ""); |
227 | } |
228 | } |
229 | (void)printf("times ten to the%s", lflag ? " " : "\n"); |
230 | if (part3 && part3[0]) |
231 | convert(part3); |
232 | else |
233 | (void)printf("zero%s", lflag ? " " : ".\n"); |
234 | } |
235 | |
236 | int |
237 | unit(int len, const char *p) |
238 | { |
239 | int off, rval; |
240 | |
241 | rval = 0; |
242 | if (len > 3) { |
243 | if (len % 3) { |
244 | off = len % 3; |
245 | len -= off; |
246 | if (number(p, off)) { |
247 | rval = 1; |
248 | (void)printf(" %s%s", |
249 | name3[len / 3], lflag ? " " : ".\n"); |
250 | } |
251 | p += off; |
252 | } |
253 | for (; len > 3; p += 3) { |
254 | len -= 3; |
255 | if (number(p, 3)) { |
256 | rval = 1; |
257 | (void)printf(" %s%s", |
258 | name3[len / 3], lflag ? " " : ".\n"); |
259 | } |
260 | } |
261 | } |
262 | if (number(p, len)) { |
263 | if (!lflag) |
264 | (void)printf(".\n"); |
265 | rval = 1; |
266 | } |
267 | return (rval); |
268 | } |
269 | |
270 | int |
271 | number(const char *p, int len) |
272 | { |
273 | int val, rval; |
274 | |
275 | rval = 0; |
276 | switch (len) { |
277 | case 3: |
278 | if (*p != '0') { |
279 | rval = 1; |
280 | (void)printf("%s hundred", name1[*p - '0']); |
281 | } |
282 | ++p; |
283 | /* FALLTHROUGH */ |
284 | case 2: |
285 | val = (p[1] - '0') + (p[0] - '0') * 10; |
286 | if (val) { |
287 | if (rval) |
288 | (void)printf(" "); |
289 | if (val < 20) |
290 | (void)printf("%s", name1[val]); |
291 | else { |
292 | (void)printf("%s", name2[val / 10]); |
293 | if (val % 10) |
294 | (void)printf("-%s", name1[val % 10]); |
295 | } |
296 | rval = 1; |
297 | } |
298 | break; |
299 | case 1: |
300 | if (*p != '0') { |
301 | rval = 1; |
302 | (void)printf("%s", name1[*p - '0']); |
303 | } |
304 | } |
305 | return (rval); |
306 | } |
307 | |
308 | void |
309 | pfract(int len) |
310 | { |
311 | static const char *const pref[] = { "", "ten-", "hundred-" }; |
312 | |
313 | switch(len) { |
314 | case 1: |
315 | (void)printf("tenths%s", lflag ? "" : ".\n"); |
316 | break; |
317 | case 2: |
318 | (void)printf("hundredths%s", lflag ? "" : ".\n"); |
319 | break; |
320 | default: |
321 | (void)printf("%s%sths%s", pref[len % 3], name3[len / 3], |
322 | lflag ? "" : ".\n"); |
323 | break; |
324 | } |
325 | } |
326 | |
327 | void |
328 | usage(void) |
329 | { |
330 | (void)fprintf(stderr(&__sF[2]), "usage: %s [-l] [--] [# ...]\n", getprogname()); |
331 | exit(1); |
332 | } |