number.c revision 53920
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. 322490Sjkh */ 332490Sjkh 342490Sjkh#ifndef lint 3553920Sbillfstatic const char copyright[] = 362490Sjkh"@(#) Copyright (c) 1988, 1993, 1994\n\ 372490Sjkh The Regents of the University of California. All rights reserved.\n"; 382490Sjkh#endif /* not lint */ 392490Sjkh 402490Sjkh#ifndef lint 4153920Sbillf#if 0 4223726Speterstatic char sccsid[] = "@(#)number.c 8.3 (Berkeley) 5/4/95"; 4353920Sbillf#endif 4453920Sbillfstatic const char rcsid[] = 4553920Sbillf "$FreeBSD: head/games/number/number.c 53920 1999-11-30 03:50:02Z billf $"; 462490Sjkh#endif /* not lint */ 472490Sjkh 482490Sjkh#include <sys/types.h> 492490Sjkh 502490Sjkh#include <ctype.h> 5123726Speter#include <err.h> 522490Sjkh#include <stdio.h> 532490Sjkh#include <stdlib.h> 542490Sjkh#include <string.h> 5523726Speter#include <unistd.h> 562490Sjkh 572490Sjkh#define MAXNUM 65 /* Biggest number we handle. */ 582490Sjkh 592490Sjkhstatic char *name1[] = { 602490Sjkh "", "one", "two", "three", 612490Sjkh "four", "five", "six", "seven", 622490Sjkh "eight", "nine", "ten", "eleven", 632490Sjkh "twelve", "thirteen", "fourteen", "fifteen", 642490Sjkh "sixteen", "seventeen", "eighteen", "nineteen", 652490Sjkh}, 662490Sjkh *name2[] = { 672490Sjkh "", "ten", "twenty", "thirty", 682490Sjkh "forty", "fifty", "sixty", "seventy", 692490Sjkh "eighty", "ninety", 702490Sjkh}, 712490Sjkh *name3[] = { 722490Sjkh "hundred", "thousand", "million", "billion", 732490Sjkh "trillion", "quadrillion", "quintillion", "sextillion", 742490Sjkh "septillion", "octillion", "nonillion", "decillion", 752490Sjkh "undecillion", "duodecillion", "tredecillion", "quattuordecillion", 768856Srgrimes "quindecillion", "sexdecillion", 772490Sjkh "septendecillion", "octodecillion", 782490Sjkh "novemdecillion", "vigintillion", 792490Sjkh}; 802490Sjkh 812490Sjkhvoid convert __P((char *)); 822490Sjkhint number __P((char *, int)); 832490Sjkhvoid pfract __P((int)); 842490Sjkhvoid toobig __P((void)); 852490Sjkhint unit __P((int, char *)); 862490Sjkhvoid usage __P((void)); 872490Sjkh 882490Sjkhint lflag; 892490Sjkh 902490Sjkhint 912490Sjkhmain(argc, argv) 922490Sjkh int argc; 932490Sjkh char *argv[]; 942490Sjkh{ 952490Sjkh int ch, first; 962490Sjkh char line[256]; 972490Sjkh 982490Sjkh lflag = 0; 9933937Sjkh while ((ch = getopt(argc, argv, "l")) != -1) 1002490Sjkh switch (ch) { 1012490Sjkh case 'l': 1022490Sjkh lflag = 1; 1032490Sjkh break; 1042490Sjkh case '?': 1052490Sjkh default: 1062490Sjkh usage(); 1072490Sjkh } 1082490Sjkh argc -= optind; 1092490Sjkh argv += optind; 1102490Sjkh 1112490Sjkh if (*argv == NULL) 1122490Sjkh for (first = 1; 1132490Sjkh fgets(line, sizeof(line), stdin) != NULL; first = 0) { 1142490Sjkh if (strchr(line, '\n') == NULL) 1152490Sjkh errx(1, "line too long."); 1162490Sjkh if (!first) 1172490Sjkh (void)printf("...\n"); 1182490Sjkh convert(line); 1192490Sjkh } 1202490Sjkh else 1212490Sjkh for (first = 1; *argv != NULL; first = 0, ++argv) { 1222490Sjkh if (!first) 1232490Sjkh (void)printf("...\n"); 1242490Sjkh convert(*argv); 1252490Sjkh } 1262490Sjkh exit(0); 1272490Sjkh} 1282490Sjkh 1292490Sjkhvoid 1302490Sjkhconvert(line) 1312490Sjkh char *line; 1322490Sjkh{ 13353215Smarcel int flen, len, rval; 13453210Sbillf char *p, *fraction; 1352490Sjkh 1362490Sjkh fraction = NULL; 1372490Sjkh for (p = line; *p != '\0' && *p != '\n'; ++p) { 1382490Sjkh if (isblank(*p)) { 1392490Sjkh if (p == line) { 1402490Sjkh ++line; 1412490Sjkh continue; 1422490Sjkh } 1432490Sjkh goto badnum; 1442490Sjkh } 1452490Sjkh if (isdigit(*p)) 1462490Sjkh continue; 1472490Sjkh switch (*p) { 1482490Sjkh case '.': 1492490Sjkh if (fraction != NULL) 1502490Sjkh goto badnum; 1512490Sjkh fraction = p + 1; 1522490Sjkh *p = '\0'; 1532490Sjkh break; 1542490Sjkh case '-': 1552490Sjkh if (p == line) 1562490Sjkh break; 1572490Sjkh /* FALLTHROUGH */ 1582490Sjkh default: 1592490Sjkhbadnum: errx(1, "illegal number: %s", line); 1602490Sjkh break; 1612490Sjkh } 1622490Sjkh } 1632490Sjkh *p = '\0'; 1642490Sjkh 1652490Sjkh if ((len = strlen(line)) > MAXNUM || 1662490Sjkh fraction != NULL && (flen = strlen(fraction)) > MAXNUM) 1672490Sjkh errx(1, "number too large, max %d digits.", MAXNUM); 1682490Sjkh 1692490Sjkh if (*line == '-') { 1702490Sjkh (void)printf("minus%s", lflag ? " " : "\n"); 1712490Sjkh ++line; 17233856Ssteve --len; 1732490Sjkh } 1742490Sjkh 1752490Sjkh rval = len > 0 ? unit(len, line) : 0; 1762490Sjkh if (fraction != NULL && flen != 0) 1772490Sjkh for (p = fraction; *p != '\0'; ++p) 1782490Sjkh if (*p != '0') { 1792490Sjkh if (rval) 1802490Sjkh (void)printf("%sand%s", 1812490Sjkh lflag ? " " : "", 1822490Sjkh lflag ? " " : "\n"); 1832490Sjkh if (unit(flen, fraction)) { 1842490Sjkh if (lflag) 1852490Sjkh (void)printf(" "); 1862490Sjkh pfract(flen); 1872490Sjkh rval = 1; 1882490Sjkh } 1892490Sjkh break; 1902490Sjkh } 1912490Sjkh if (!rval) 1922490Sjkh (void)printf("zero%s", lflag ? "" : ".\n"); 1932490Sjkh if (lflag) 1942490Sjkh (void)printf("\n"); 1952490Sjkh} 1962490Sjkh 1972490Sjkhint 1982490Sjkhunit(len, p) 19953210Sbillf int len; 20053210Sbillf char *p; 2012490Sjkh{ 20253210Sbillf int off, rval; 2032490Sjkh 2042490Sjkh rval = 0; 2052490Sjkh if (len > 3) { 2062490Sjkh if (len % 3) { 2072490Sjkh off = len % 3; 2082490Sjkh len -= off; 2092490Sjkh if (number(p, off)) { 2102490Sjkh rval = 1; 2112490Sjkh (void)printf(" %s%s", 2122490Sjkh name3[len / 3], lflag ? " " : ".\n"); 2132490Sjkh } 2142490Sjkh p += off; 2152490Sjkh } 2162490Sjkh for (; len > 3; p += 3) { 2172490Sjkh len -= 3; 2182490Sjkh if (number(p, 3)) { 2192490Sjkh rval = 1; 2202490Sjkh (void)printf(" %s%s", 2212490Sjkh name3[len / 3], lflag ? " " : ".\n"); 2222490Sjkh } 2232490Sjkh } 2242490Sjkh } 2252490Sjkh if (number(p, len)) { 2262490Sjkh if (!lflag) 2272490Sjkh (void)printf(".\n"); 2282490Sjkh rval = 1; 2292490Sjkh } 2302490Sjkh return (rval); 2312490Sjkh} 2322490Sjkh 2332490Sjkhint 2342490Sjkhnumber(p, len) 23553210Sbillf char *p; 2362490Sjkh int len; 2372490Sjkh{ 23853210Sbillf int val, rval; 2392490Sjkh 2402490Sjkh rval = 0; 2412490Sjkh switch (len) { 2422490Sjkh case 3: 2432490Sjkh if (*p != '0') { 2442490Sjkh rval = 1; 2452490Sjkh (void)printf("%s hundred", name1[*p - '0']); 2462490Sjkh } 2472490Sjkh ++p; 2482490Sjkh /* FALLTHROUGH */ 2492490Sjkh case 2: 2502490Sjkh val = (p[1] - '0') + (p[0] - '0') * 10; 2512490Sjkh if (val) { 2522490Sjkh if (rval) 2532490Sjkh (void)printf(" "); 2542490Sjkh if (val < 20) 2552490Sjkh (void)printf("%s", name1[val]); 2562490Sjkh else { 2572490Sjkh (void)printf("%s", name2[val / 10]); 2582490Sjkh if (val % 10) 2592490Sjkh (void)printf("-%s", name1[val % 10]); 2602490Sjkh } 2612490Sjkh rval = 1; 2622490Sjkh } 2632490Sjkh break; 2642490Sjkh case 1: 2652490Sjkh if (*p != '0') { 2662490Sjkh rval = 1; 2672490Sjkh (void)printf("%s", name1[*p - '0']); 2682490Sjkh } 2692490Sjkh } 2702490Sjkh return (rval); 2712490Sjkh} 2722490Sjkh 2732490Sjkhvoid 2742490Sjkhpfract(len) 2752490Sjkh int len; 2762490Sjkh{ 2772490Sjkh static char *pref[] = { "", "ten-", "hundred-" }; 2782490Sjkh 2792490Sjkh switch(len) { 2802490Sjkh case 1: 2812490Sjkh (void)printf("tenths.\n"); 2822490Sjkh break; 2832490Sjkh case 2: 2842490Sjkh (void)printf("hundredths.\n"); 2852490Sjkh break; 2862490Sjkh default: 2872490Sjkh (void)printf("%s%sths.\n", pref[len % 3], name3[len / 3]); 2882490Sjkh break; 2892490Sjkh } 2902490Sjkh} 2912490Sjkh 2922490Sjkhvoid 2932490Sjkhusage() 2942490Sjkh{ 2952490Sjkh (void)fprintf(stderr, "usage: number [# ...]\n"); 2962490Sjkh exit(1); 2972490Sjkh} 298