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