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