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