number.c revision 53215
12490Sjkh/* 22490Sjkh * Copyright (c) 1988, 1993, 1994 32490Sjkh * The Regents of the University of California. All rights reserved. 42490Sjkh * 52490Sjkh * Redistribution and use in source and binary forms, with or without 62490Sjkh * modification, are permitted provided that the following conditions 72490Sjkh * are met: 82490Sjkh * 1. Redistributions of source code must retain the above copyright 92490Sjkh * notice, this list of conditions and the following disclaimer. 102490Sjkh * 2. Redistributions in binary form must reproduce the above copyright 112490Sjkh * notice, this list of conditions and the following disclaimer in the 122490Sjkh * documentation and/or other materials provided with the distribution. 132490Sjkh * 3. All advertising materials mentioning features or use of this software 142490Sjkh * must display the following acknowledgement: 152490Sjkh * This product includes software developed by the University of 162490Sjkh * California, Berkeley and its contributors. 172490Sjkh * 4. Neither the name of the University nor the names of its contributors 182490Sjkh * may be used to endorse or promote products derived from this software 192490Sjkh * without specific prior written permission. 202490Sjkh * 212490Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 222490Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 232490Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 242490Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 252490Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 262490Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 272490Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 282490Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 292490Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 302490Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 312490Sjkh * SUCH DAMAGE. 3253209Sbillf * 3353209Sbillf * $FreeBSD: head/games/number/number.c 53215 1999-11-16 11:49:21Z marcel $ 342490Sjkh */ 352490Sjkh 362490Sjkh#ifndef lint 372490Sjkhstatic char copyright[] = 382490Sjkh"@(#) Copyright (c) 1988, 1993, 1994\n\ 392490Sjkh The Regents of the University of California. All rights reserved.\n"; 402490Sjkh#endif /* not lint */ 412490Sjkh 422490Sjkh#ifndef lint 4323726Speterstatic char sccsid[] = "@(#)number.c 8.3 (Berkeley) 5/4/95"; 442490Sjkh#endif /* not lint */ 452490Sjkh 462490Sjkh#include <sys/types.h> 472490Sjkh 482490Sjkh#include <ctype.h> 4923726Speter#include <err.h> 502490Sjkh#include <stdio.h> 512490Sjkh#include <stdlib.h> 522490Sjkh#include <string.h> 5323726Speter#include <unistd.h> 542490Sjkh 552490Sjkh#define MAXNUM 65 /* Biggest number we handle. */ 562490Sjkh 572490Sjkhstatic char *name1[] = { 582490Sjkh "", "one", "two", "three", 592490Sjkh "four", "five", "six", "seven", 602490Sjkh "eight", "nine", "ten", "eleven", 612490Sjkh "twelve", "thirteen", "fourteen", "fifteen", 622490Sjkh "sixteen", "seventeen", "eighteen", "nineteen", 632490Sjkh}, 642490Sjkh *name2[] = { 652490Sjkh "", "ten", "twenty", "thirty", 662490Sjkh "forty", "fifty", "sixty", "seventy", 672490Sjkh "eighty", "ninety", 682490Sjkh}, 692490Sjkh *name3[] = { 702490Sjkh "hundred", "thousand", "million", "billion", 712490Sjkh "trillion", "quadrillion", "quintillion", "sextillion", 722490Sjkh "septillion", "octillion", "nonillion", "decillion", 732490Sjkh "undecillion", "duodecillion", "tredecillion", "quattuordecillion", 748856Srgrimes "quindecillion", "sexdecillion", 752490Sjkh "septendecillion", "octodecillion", 762490Sjkh "novemdecillion", "vigintillion", 772490Sjkh}; 782490Sjkh 792490Sjkhvoid convert __P((char *)); 802490Sjkhint number __P((char *, int)); 812490Sjkhvoid pfract __P((int)); 822490Sjkhvoid toobig __P((void)); 832490Sjkhint unit __P((int, char *)); 842490Sjkhvoid usage __P((void)); 852490Sjkh 862490Sjkhint lflag; 872490Sjkh 882490Sjkhint 892490Sjkhmain(argc, argv) 902490Sjkh int argc; 912490Sjkh char *argv[]; 922490Sjkh{ 932490Sjkh int ch, first; 942490Sjkh char line[256]; 952490Sjkh 962490Sjkh lflag = 0; 9733937Sjkh while ((ch = getopt(argc, argv, "l")) != -1) 982490Sjkh switch (ch) { 992490Sjkh case 'l': 1002490Sjkh lflag = 1; 1012490Sjkh break; 1022490Sjkh case '?': 1032490Sjkh default: 1042490Sjkh usage(); 1052490Sjkh } 1062490Sjkh argc -= optind; 1072490Sjkh argv += optind; 1082490Sjkh 1092490Sjkh if (*argv == NULL) 1102490Sjkh for (first = 1; 1112490Sjkh fgets(line, sizeof(line), stdin) != NULL; first = 0) { 1122490Sjkh if (strchr(line, '\n') == NULL) 1132490Sjkh errx(1, "line too long."); 1142490Sjkh if (!first) 1152490Sjkh (void)printf("...\n"); 1162490Sjkh convert(line); 1172490Sjkh } 1182490Sjkh else 1192490Sjkh for (first = 1; *argv != NULL; first = 0, ++argv) { 1202490Sjkh if (!first) 1212490Sjkh (void)printf("...\n"); 1222490Sjkh convert(*argv); 1232490Sjkh } 1242490Sjkh exit(0); 1252490Sjkh} 1262490Sjkh 1272490Sjkhvoid 1282490Sjkhconvert(line) 1292490Sjkh char *line; 1302490Sjkh{ 13153215Smarcel int flen, len, rval; 13253210Sbillf char *p, *fraction; 1332490Sjkh 1342490Sjkh fraction = NULL; 1352490Sjkh for (p = line; *p != '\0' && *p != '\n'; ++p) { 1362490Sjkh if (isblank(*p)) { 1372490Sjkh if (p == line) { 1382490Sjkh ++line; 1392490Sjkh continue; 1402490Sjkh } 1412490Sjkh goto badnum; 1422490Sjkh } 1432490Sjkh if (isdigit(*p)) 1442490Sjkh continue; 1452490Sjkh switch (*p) { 1462490Sjkh case '.': 1472490Sjkh if (fraction != NULL) 1482490Sjkh goto badnum; 1492490Sjkh fraction = p + 1; 1502490Sjkh *p = '\0'; 1512490Sjkh break; 1522490Sjkh case '-': 1532490Sjkh if (p == line) 1542490Sjkh break; 1552490Sjkh /* FALLTHROUGH */ 1562490Sjkh default: 1572490Sjkhbadnum: errx(1, "illegal number: %s", line); 1582490Sjkh break; 1592490Sjkh } 1602490Sjkh } 1612490Sjkh *p = '\0'; 1622490Sjkh 1632490Sjkh if ((len = strlen(line)) > MAXNUM || 1642490Sjkh fraction != NULL && (flen = strlen(fraction)) > MAXNUM) 1652490Sjkh errx(1, "number too large, max %d digits.", MAXNUM); 1662490Sjkh 1672490Sjkh if (*line == '-') { 1682490Sjkh (void)printf("minus%s", lflag ? " " : "\n"); 1692490Sjkh ++line; 17033856Ssteve --len; 1712490Sjkh } 1722490Sjkh 1732490Sjkh rval = len > 0 ? unit(len, line) : 0; 1742490Sjkh if (fraction != NULL && flen != 0) 1752490Sjkh for (p = fraction; *p != '\0'; ++p) 1762490Sjkh if (*p != '0') { 1772490Sjkh if (rval) 1782490Sjkh (void)printf("%sand%s", 1792490Sjkh lflag ? " " : "", 1802490Sjkh lflag ? " " : "\n"); 1812490Sjkh if (unit(flen, fraction)) { 1822490Sjkh if (lflag) 1832490Sjkh (void)printf(" "); 1842490Sjkh pfract(flen); 1852490Sjkh rval = 1; 1862490Sjkh } 1872490Sjkh break; 1882490Sjkh } 1892490Sjkh if (!rval) 1902490Sjkh (void)printf("zero%s", lflag ? "" : ".\n"); 1912490Sjkh if (lflag) 1922490Sjkh (void)printf("\n"); 1932490Sjkh} 1942490Sjkh 1952490Sjkhint 1962490Sjkhunit(len, p) 19753210Sbillf int len; 19853210Sbillf char *p; 1992490Sjkh{ 20053210Sbillf int off, rval; 2012490Sjkh 2022490Sjkh rval = 0; 2032490Sjkh if (len > 3) { 2042490Sjkh if (len % 3) { 2052490Sjkh off = len % 3; 2062490Sjkh len -= off; 2072490Sjkh if (number(p, off)) { 2082490Sjkh rval = 1; 2092490Sjkh (void)printf(" %s%s", 2102490Sjkh name3[len / 3], lflag ? " " : ".\n"); 2112490Sjkh } 2122490Sjkh p += off; 2132490Sjkh } 2142490Sjkh for (; len > 3; p += 3) { 2152490Sjkh len -= 3; 2162490Sjkh if (number(p, 3)) { 2172490Sjkh rval = 1; 2182490Sjkh (void)printf(" %s%s", 2192490Sjkh name3[len / 3], lflag ? " " : ".\n"); 2202490Sjkh } 2212490Sjkh } 2222490Sjkh } 2232490Sjkh if (number(p, len)) { 2242490Sjkh if (!lflag) 2252490Sjkh (void)printf(".\n"); 2262490Sjkh rval = 1; 2272490Sjkh } 2282490Sjkh return (rval); 2292490Sjkh} 2302490Sjkh 2312490Sjkhint 2322490Sjkhnumber(p, len) 23353210Sbillf char *p; 2342490Sjkh int len; 2352490Sjkh{ 23653210Sbillf int val, rval; 2372490Sjkh 2382490Sjkh rval = 0; 2392490Sjkh switch (len) { 2402490Sjkh case 3: 2412490Sjkh if (*p != '0') { 2422490Sjkh rval = 1; 2432490Sjkh (void)printf("%s hundred", name1[*p - '0']); 2442490Sjkh } 2452490Sjkh ++p; 2462490Sjkh /* FALLTHROUGH */ 2472490Sjkh case 2: 2482490Sjkh val = (p[1] - '0') + (p[0] - '0') * 10; 2492490Sjkh if (val) { 2502490Sjkh if (rval) 2512490Sjkh (void)printf(" "); 2522490Sjkh if (val < 20) 2532490Sjkh (void)printf("%s", name1[val]); 2542490Sjkh else { 2552490Sjkh (void)printf("%s", name2[val / 10]); 2562490Sjkh if (val % 10) 2572490Sjkh (void)printf("-%s", name1[val % 10]); 2582490Sjkh } 2592490Sjkh rval = 1; 2602490Sjkh } 2612490Sjkh break; 2622490Sjkh case 1: 2632490Sjkh if (*p != '0') { 2642490Sjkh rval = 1; 2652490Sjkh (void)printf("%s", name1[*p - '0']); 2662490Sjkh } 2672490Sjkh } 2682490Sjkh return (rval); 2692490Sjkh} 2702490Sjkh 2712490Sjkhvoid 2722490Sjkhpfract(len) 2732490Sjkh int len; 2742490Sjkh{ 2752490Sjkh static char *pref[] = { "", "ten-", "hundred-" }; 2762490Sjkh 2772490Sjkh switch(len) { 2782490Sjkh case 1: 2792490Sjkh (void)printf("tenths.\n"); 2802490Sjkh break; 2812490Sjkh case 2: 2822490Sjkh (void)printf("hundredths.\n"); 2832490Sjkh break; 2842490Sjkh default: 2852490Sjkh (void)printf("%s%sths.\n", pref[len % 3], name3[len / 3]); 2862490Sjkh break; 2872490Sjkh } 2882490Sjkh} 2892490Sjkh 2902490Sjkhvoid 2912490Sjkhusage() 2922490Sjkh{ 2932490Sjkh (void)fprintf(stderr, "usage: number [# ...]\n"); 2942490Sjkh exit(1); 2952490Sjkh} 296