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