xref: /original-bsd/games/number/number.c (revision 1451ccc8)
1 /*
2  * Copyright (c) 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1988 Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)number.c	4.5 (Berkeley) 06/27/88";
26 #endif /* not lint */
27 
28 #include <stdio.h>
29 #include <ctype.h>
30 
31 #define	YES		1
32 #define	NO		0
33 #define	EOS		'\0'
34 #define	MAXNUM		65		/* biggest number we handle */
35 
36 static char	*name1[] = {
37 	"",		"one",		"two",		"three",
38 	"four",		"five",		"six",		"seven",
39 	"eight",	"nine",		"ten",		"eleven",
40 	"twelve",	"thirteen",	"fourteen",	"fifteen",
41 	"sixteen",	"seventeen",	"eighteen",	"nineteen",
42 },
43 		*name2[] = {
44 	"",		"ten",		"twenty",	"thirty",
45 	"forty",	"fifty",	"sixty",	"seventy",
46 	"eighty",	"ninety",
47 },
48 		*name3[] = {
49 	"hundred",	"thousand",	"million",	"billion",
50 	"trillion",	"quadrillion",	"quintillion",	"sextillion",
51 	"septillion",	"octillion",	"nonillion",	"decillion",
52 	"undecillion",	"duodecillion",	"tredecillion",	"quattuordecillion",
53 	"quindecillion",		"sexdecillion",
54 	"septendecillion",		"octodecillion",
55 	"novemdecillion",		"vigintillion",
56 };
57 
58 main(argc,argv)
59 	int	argc;
60 	char	**argv;
61 {
62 	register int	cnt;
63 	char	line[MAXNUM * 2 + 2];		/* MAXNUM '.' MAXNUM '\0' */
64 
65 	if (argc > 1)
66 		for (cnt = 1;cnt < argc;++cnt) {
67 			convert(argv[cnt]);
68 			puts("...");
69 		}
70 	else
71 		while (fgets(line,sizeof(line),stdin)) {
72 			convert(line);
73 			puts("...");
74 		}
75 	exit(0);
76 }
77 
78 static
79 convert(line)
80 	char	*line;
81 {
82 	register int	len,
83 			ret;
84 	register char	*C,
85 			*fraction;
86 
87 	for (fraction = NULL, C = line;*C && *C != '\n';++C)
88 		if (!isdigit(*C))
89 			switch(*C) {
90 			case '-':
91 				if (C != line)
92 					usage(NO);
93 				break;
94 			case '.':
95 				if (!fraction) {
96 					fraction = C + 1;
97 					*C = EOS;
98 					break;
99 				}
100 			default:
101 				usage(NO);
102 			}
103 	*C = EOS;
104 	if (*line == '-') {
105 		puts("minus");
106 		++line;
107 	}
108 	ret = NO;
109 	if (len = strlen(line)) {
110 		if (len > MAXNUM)
111 			usage(YES);
112 		ret = unit(len,line);
113 	}
114 	if (fraction && (len = strlen(fraction))) {
115 		if (len > MAXNUM)
116 			usage(YES);
117 		for (C = fraction;*C;++C)
118 			if (*C != '0') {
119 				if (ret)
120 					puts("and");
121 				if (unit(len,fraction)) {
122 					++ret;
123 					pfract(len);
124 				}
125 				break;
126 			}
127 	}
128 	if (!ret)
129 		puts("zero.");
130 }
131 
132 static
133 unit(len,C)
134 	register int	len;
135 	register char	*C;
136 {
137 	register int	off,
138 			ret;
139 
140 	ret = NO;
141 	if (len > 3) {
142 		if (len % 3) {
143 			off = len % 3;
144 			len -= off;
145 			if (number(C,off)) {
146 				ret = YES;
147 				printf(" %s.\n",name3[len / 3]);
148 			}
149 			C += off;
150 		}
151 		for (;len > 3;C += 3) {
152 			len -= 3;
153 			if (number(C,3)) {
154 				ret = YES;
155 				printf(" %s.\n",name3[len / 3]);
156 			}
157 		}
158 	}
159 	if (number(C,len)) {
160 		puts(".");
161 		ret = YES;
162 	}
163 	return(ret);
164 }
165 
166 static
167 number(C,len)
168 	register char	*C;
169 	int	len;
170 {
171 	register int	val,
172 			ret;
173 
174 	ret = 0;
175 	switch(len) {
176 	case 3:
177 		if (*C != '0') {
178 			++ret;
179 			printf("%s hundred",name1[*C - '0']);
180 		}
181 		++C;
182 		/*FALLTHROUGH*/
183 	case 2:
184 		val = (C[1] - '0') + (C[0] - '0') * 10;
185 		if (val) {
186 			if (ret++)
187 				putchar(' ');
188 			if (val < 20)
189 				fputs(name1[val],stdout);
190 			else {
191 				fputs(name2[val / 10],stdout);
192 				if (val % 10)
193 					printf("-%s",name1[val % 10]);
194 			}
195 		}
196 		break;
197 	case 1:
198 		if (*C != '0') {
199 			++ret;
200 			fputs(name1[*C - '0'],stdout);
201 		}
202 	}
203 	return(ret);
204 }
205 
206 static
207 pfract(len)
208 	register int	len;
209 {
210 	static char	*pref[] = { "", "ten-", "hundred-" };
211 
212 	switch(len) {
213 	case 1:
214 		puts("tenths.");
215 		break;
216 	case 2:
217 		puts("hundredths.");
218 		break;
219 	default:
220 		printf("%s%sths.\n",pref[len % 3],name3[len / 3]);
221 	}
222 }
223 
224 static
225 usage(toobig)
226 	int	toobig;
227 {
228 	if (toobig)
229 		fprintf(stderr,"number: number too large, max %d digits.\n",MAXNUM);
230 	fputs("usage: number # ...\n",stderr);
231 	exit(-1);
232 }
233