number.c revision 141581
1177633Sdfr/* 2177633Sdfr * Copyright (c) 1988, 1993, 1994 3177633Sdfr * The Regents of the University of California. All rights reserved. 4177633Sdfr * 5177633Sdfr * Redistribution and use in source and binary forms, with or without 6177633Sdfr * modification, are permitted provided that the following conditions 7177633Sdfr * are met: 8177633Sdfr * 1. Redistributions of source code must retain the above copyright 9177633Sdfr * notice, this list of conditions and the following disclaimer. 10177633Sdfr * 2. Redistributions in binary form must reproduce the above copyright 11177633Sdfr * notice, this list of conditions and the following disclaimer in the 12177633Sdfr * documentation and/or other materials provided with the distribution. 13177633Sdfr * 3. All advertising materials mentioning features or use of this software 14177633Sdfr * must display the following acknowledgement: 15177633Sdfr * This product includes software developed by the University of 16177633Sdfr * California, Berkeley and its contributors. 17177633Sdfr * 4. Neither the name of the University nor the names of its contributors 18177633Sdfr * may be used to endorse or promote products derived from this software 19177633Sdfr * without specific prior written permission. 20177633Sdfr * 21177633Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22177633Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23177633Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24177633Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25177633Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26177633Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27177633Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28177633Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29177633Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30177633Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31177633Sdfr * SUCH DAMAGE. 32177633Sdfr */ 33177633Sdfr 34177633Sdfr#ifndef lint 35177633Sdfrstatic const char copyright[] = 36177633Sdfr"@(#) Copyright (c) 1988, 1993, 1994\n\ 37177633Sdfr The Regents of the University of California. All rights reserved.\n"; 38177633Sdfr#endif /* not lint */ 39177633Sdfr 40177633Sdfr#ifndef lint 41177633Sdfr#if 0 42177633Sdfrstatic char sccsid[] = "@(#)number.c 8.3 (Berkeley) 5/4/95"; 43177633Sdfr#endif 44177633Sdfrstatic const char rcsid[] = 45177633Sdfr "$FreeBSD: head/games/number/number.c 141581 2005-02-09 18:22:15Z ru $"; 46177633Sdfr#endif /* not lint */ 47177633Sdfr 48177633Sdfr#include <sys/types.h> 49177633Sdfr 50177633Sdfr#include <ctype.h> 51177633Sdfr#include <err.h> 52177633Sdfr#include <stdio.h> 53177633Sdfr#include <stdlib.h> 54177633Sdfr#include <string.h> 55184588Sdfr#include <unistd.h> 56184588Sdfr 57184588Sdfr#define MAXNUM 65 /* Biggest number we handle. */ 58184588Sdfr 59184588Sdfrstatic const char *name1[] = { 60184588Sdfr "", "one", "two", "three", 61184588Sdfr "four", "five", "six", "seven", 62177633Sdfr "eight", "nine", "ten", "eleven", 63177633Sdfr "twelve", "thirteen", "fourteen", "fifteen", 64177633Sdfr "sixteen", "seventeen", "eighteen", "nineteen", 65177633Sdfr}, 66177633Sdfr *name2[] = { 67177633Sdfr "", "ten", "twenty", "thirty", 68177633Sdfr "forty", "fifty", "sixty", "seventy", 69177633Sdfr "eighty", "ninety", 70177633Sdfr}, 71177633Sdfr *name3[] = { 72177633Sdfr "hundred", "thousand", "million", "billion", 73177633Sdfr "trillion", "quadrillion", "quintillion", "sextillion", 74177633Sdfr "septillion", "octillion", "nonillion", "decillion", 75177633Sdfr "undecillion", "duodecillion", "tredecillion", "quattuordecillion", 76177633Sdfr "quindecillion", "sexdecillion", 77177633Sdfr "septendecillion", "octodecillion", 78177633Sdfr "novemdecillion", "vigintillion", 79177633Sdfr}; 80177633Sdfr 81177633Sdfrvoid convert(char *); 82177633Sdfrint number(char *, int); 83177633Sdfrvoid pfract(int); 84177633Sdfrvoid toobig(void); 85177633Sdfrint unit(int, char *); 86177633Sdfrvoid usage(void); 87184588Sdfr 88184588Sdfrint lflag; 89177633Sdfr 90177633Sdfrint 91177633Sdfrmain(argc, argv) 92177633Sdfr int argc; 93177633Sdfr char *argv[]; 94177633Sdfr{ 95177633Sdfr int ch, first; 96177633Sdfr char line[256]; 97177633Sdfr 98177633Sdfr lflag = 0; 99177633Sdfr while ((ch = getopt(argc, argv, "l")) != -1) 100184588Sdfr switch (ch) { 101184588Sdfr case 'l': 102184588Sdfr lflag = 1; 103184588Sdfr break; 104184588Sdfr case '?': 105177633Sdfr default: 106177633Sdfr usage(); 107177633Sdfr } 108177633Sdfr argc -= optind; 109177633Sdfr argv += optind; 110177633Sdfr 111177633Sdfr if (*argv == NULL) 112184588Sdfr for (first = 1; 113184588Sdfr fgets(line, sizeof(line), stdin) != NULL; first = 0) { 114184588Sdfr if (strchr(line, '\n') == NULL) 115184588Sdfr errx(1, "line too long."); 116184588Sdfr if (!first) 117184588Sdfr (void)printf("...\n"); 118184588Sdfr convert(line); 119184588Sdfr } 120184588Sdfr else 121184588Sdfr for (first = 1; *argv != NULL; first = 0, ++argv) { 122184588Sdfr if (!first) 123184588Sdfr (void)printf("...\n"); 124184588Sdfr convert(*argv); 125184588Sdfr } 126184588Sdfr exit(0); 127184588Sdfr} 128184588Sdfr 129184588Sdfrvoid 130184588Sdfrconvert(line) 131184588Sdfr char *line; 132184588Sdfr{ 133184588Sdfr int flen, len, rval; 134184588Sdfr char *p, *fraction; 135184588Sdfr 136184588Sdfr flen = 0; 137184588Sdfr fraction = NULL; 138184588Sdfr for (p = line; *p != '\0' && *p != '\n'; ++p) { 139184588Sdfr if (isblank(*p)) { 140184588Sdfr if (p == line) { 141184588Sdfr ++line; 142177633Sdfr continue; 143177633Sdfr } 144177633Sdfr goto badnum; 145177633Sdfr } 146184588Sdfr if (isdigit(*p)) 147184588Sdfr continue; 148177633Sdfr switch (*p) { 149177633Sdfr case '.': 150177633Sdfr if (fraction != NULL) 151177633Sdfr goto badnum; 152184588Sdfr fraction = p + 1; 153184588Sdfr *p = '\0'; 154184588Sdfr break; 155177633Sdfr case '-': 156184588Sdfr if (p == line) 157184588Sdfr break; 158184588Sdfr /* FALLTHROUGH */ 159184588Sdfr default: 160184588Sdfrbadnum: errx(1, "illegal number: %s", line); 161184588Sdfr break; 162184588Sdfr } 163184588Sdfr } 164184588Sdfr *p = '\0'; 165184588Sdfr 166184588Sdfr if ((len = strlen(line)) > MAXNUM || 167184588Sdfr (fraction != NULL && ((flen = strlen(fraction)) > MAXNUM))) 168177633Sdfr errx(1, "number too large, max %d digits.", MAXNUM); 169177633Sdfr 170177633Sdfr if (*line == '-') { 171177633Sdfr (void)printf("minus%s", lflag ? " " : "\n"); 172177633Sdfr ++line; 173177633Sdfr --len; 174177633Sdfr } 175177633Sdfr 176177633Sdfr rval = len > 0 ? unit(len, line) : 0; 177177633Sdfr if (fraction != NULL && flen != 0) 178184588Sdfr for (p = fraction; *p != '\0'; ++p) 179177633Sdfr if (*p != '0') { 180177633Sdfr if (rval) 181177633Sdfr (void)printf("%sand%s", 182177633Sdfr lflag ? " " : "", 183184588Sdfr lflag ? " " : "\n"); 184184588Sdfr if (unit(flen, fraction)) { 185177633Sdfr if (lflag) 186177633Sdfr (void)printf(" "); 187184588Sdfr pfract(flen); 188184588Sdfr rval = 1; 189184588Sdfr } 190184588Sdfr break; 191184588Sdfr } 192177633Sdfr if (!rval) 193177633Sdfr (void)printf("zero%s", lflag ? "" : ".\n"); 194177633Sdfr if (lflag) 195177633Sdfr (void)printf("\n"); 196177633Sdfr} 197 198int 199unit(len, p) 200 int len; 201 char *p; 202{ 203 int off, rval; 204 205 rval = 0; 206 if (len > 3) { 207 if (len % 3) { 208 off = len % 3; 209 len -= off; 210 if (number(p, off)) { 211 rval = 1; 212 (void)printf(" %s%s", 213 name3[len / 3], lflag ? " " : ".\n"); 214 } 215 p += off; 216 } 217 for (; len > 3; p += 3) { 218 len -= 3; 219 if (number(p, 3)) { 220 rval = 1; 221 (void)printf(" %s%s", 222 name3[len / 3], lflag ? " " : ".\n"); 223 } 224 } 225 } 226 if (number(p, len)) { 227 if (!lflag) 228 (void)printf(".\n"); 229 rval = 1; 230 } 231 return (rval); 232} 233 234int 235number(p, len) 236 char *p; 237 int len; 238{ 239 int val, rval; 240 241 rval = 0; 242 switch (len) { 243 case 3: 244 if (*p != '0') { 245 rval = 1; 246 (void)printf("%s hundred", name1[*p - '0']); 247 } 248 ++p; 249 /* FALLTHROUGH */ 250 case 2: 251 val = (p[1] - '0') + (p[0] - '0') * 10; 252 if (val) { 253 if (rval) 254 (void)printf(" "); 255 if (val < 20) 256 (void)printf("%s", name1[val]); 257 else { 258 (void)printf("%s", name2[val / 10]); 259 if (val % 10) 260 (void)printf("-%s", name1[val % 10]); 261 } 262 rval = 1; 263 } 264 break; 265 case 1: 266 if (*p != '0') { 267 rval = 1; 268 (void)printf("%s", name1[*p - '0']); 269 } 270 } 271 return (rval); 272} 273 274void 275pfract(len) 276 int len; 277{ 278 static char *pref[] = { "", "ten-", "hundred-" }; 279 280 switch(len) { 281 case 1: 282 (void)printf("tenths.\n"); 283 break; 284 case 2: 285 (void)printf("hundredths.\n"); 286 break; 287 default: 288 (void)printf("%s%sths.\n", pref[len % 3], name3[len / 3]); 289 break; 290 } 291} 292 293void 294usage() 295{ 296 (void)fprintf(stderr, "usage: number [-l] [# ...]\n"); 297 exit(1); 298} 299