Imported Upstream version 1.10
[platform/upstream/gdbm.git] / tests / num2word.c
1 /* This file is part of GDBM test suite.
2    Copyright (C) 2011 Free Software Foundation, Inc.
3
4    GDBM is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    GDBM is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with GDBM. If not, see <http://www.gnu.org/licenses/>.
16 */
17 #include "autoconf.h"
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <errno.h>
23
24 const char *progname;
25
26 const char *nstr[][10] = {
27   { "zero", 
28     "one",
29     "two",
30     "three",
31     "four",
32     "five",
33     "six",
34     "seven",
35     "eight",
36     "nine"
37   },
38   { "ten",
39     "eleven",
40     "twelve",
41     "thirteen",
42     "fourteen",  
43     "fifteen",   
44     "sixteen",   
45     "seventeen", 
46     "eighteen",  
47     "nineteen"
48   },
49   { NULL,
50     NULL,
51     "twenty",
52     "thirty",
53     "fourty",
54     "fifty",
55     "sixty",
56     "seventy",
57     "eighty",
58     "ninety"
59   }
60 };
61
62 const char *short_scale[] = {
63   "one",
64   "thousand",
65   "million",
66   "billion"
67   /* End of range for 32-bit unsigned long */
68 };
69 size_t short_scale_max = sizeof (short_scale) / sizeof (short_scale[0]);
70
71 char buffer[1024];
72 size_t bufsize = sizeof(buffer);
73 size_t bufoff;
74 int delim = 0;
75
76 void
77 copy (const char *str, int dch)
78 {
79   size_t len = strlen (str);
80   if (len + !!dch > bufoff)
81     abort ();
82   if (dch)
83     buffer[--bufoff] = dch;
84   bufoff -= len;
85   memcpy (buffer + bufoff, str, len);
86   delim = ' ';
87 }
88
89 void
90 format_100 (unsigned long num)
91 {
92   if (num == 0)
93     ;
94   else if (num < 10)
95     copy (nstr[0][num], delim);
96   else if (num < 20)
97     copy (nstr[1][num-10], delim);
98   else 
99     {
100       unsigned long tens = num / 10;
101       num %= 10;
102       if (num)
103         {
104           copy (nstr[0][num], delim);
105           copy ("-", 0);
106           copy (nstr[2][tens], 0);
107         }
108       else
109         copy (nstr[2][tens], delim);
110     }
111 }
112
113 void
114 format_1000 (unsigned long num, int more)
115 {
116   size_t n = num % 100;
117   num /= 100;
118   format_100 (n);
119   more |= num != 0;
120   if (n && more)
121     copy ("and", delim);
122   if (num)
123     {
124       copy ("hundred", delim);
125       copy (nstr[0][num], delim);
126     }
127 }
128
129
130 void
131 format_number (unsigned long num)
132 {
133   int s = 0;
134   size_t off;
135
136   bufoff = bufsize;
137   buffer[--bufoff] = 0;
138   off = bufoff;
139   delim = 0;
140   
141   do
142     {
143       unsigned long n = num % 1000;
144
145       num /= 1000;
146       
147       if (s > 0 && ((n && off > bufoff) || num == 0))
148         copy (short_scale[s], delim);
149       s++;
150       
151       if (s > short_scale_max)
152         abort ();
153       
154       format_1000 (n, num != 0);
155     }
156   while (num);
157   
158   if (bufoff + 1 == bufsize)
159     copy (nstr[0][0], 0);
160 }
161       
162
163 void
164 print_number (unsigned long num)
165 {
166   format_number (num);
167   printf ("%lu\t%s\n", num, buffer + bufoff);
168 }
169
170 void
171 print_range (unsigned long num, unsigned long to)
172 {
173   for (; num <= to; num++)
174     print_number (num);
175 }
176
177 unsigned long
178 xstrtoul (char *arg, char **endp)
179 {
180   unsigned long num;
181   char *p;
182
183   errno = 0;
184   num = strtoul (arg, &p, 10);
185   if (errno)
186     {
187       fprintf (stderr, "%s: invalid number: ", progname);
188       perror (arg);
189       exit (2);
190     }
191   if (endp)
192     *endp = p;
193   else if (*p)
194     {
195       fprintf (stderr, "%s: invalid number (near %s)\n",
196                progname, p);
197       exit (2);
198     }
199     
200   return num;
201 }
202
203 int
204 main (int argc, char **argv)
205 {
206   progname = argv[0];
207   
208   if (argc == 1 || strcmp (argv[1], "-h") == 0)
209     {
210       printf ("usage: %s NUM [NUM...]\n", progname);
211       printf ("where NUM is a decimal number, NUM:COUNT or NUM-NUM\n");
212       exit (0);
213     }
214
215   while (--argc)
216     {
217       char *arg = *++argv;
218       unsigned long num, num2;
219       char *p;
220
221       num = xstrtoul (arg, &p);
222       if (*p == 0)
223         print_number (num);
224       else if (*p == ':')
225         {
226           *p++ = 0;
227           num2 = xstrtoul (p, NULL);
228           if (num2 == 0)
229             {
230               fprintf (stderr, "%s: invalid count\n", progname);
231               exit (2);
232             }
233           print_range (num, num + num2 - 1);
234         }
235       else if (*p == '-')
236         {
237           *p++ = 0;
238           num2 = xstrtoul (p, NULL);
239           if (num2 < num)
240             {
241               fprintf (stderr, "%s: invalid range: %lu-%lu\n",
242                        progname, num, num2);
243               exit (2);
244             }
245             
246           print_range (num, num2);
247         }
248       else
249         {
250           fprintf (stderr, "%s: invalid argument\n", progname);
251           exit (2);
252         }
253     }
254   exit (0);
255 }