Bash-4.3 distribution sources and documentation
[platform/upstream/bash.git] / lib / sh / fmtulong.c
1 /* fmtulong.c -- Convert unsigned long int to string. */
2
3 /* Copyright (C) 1998-2011 Free Software Foundation, Inc.
4
5    This file is part of GNU Bash, the Bourne Again SHell.
6
7    Bash is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11
12    Bash is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
24
25 #if defined (HAVE_UNISTD_H)
26 #  include <unistd.h>
27 #endif
28
29 #if defined (HAVE_LIMITS_H)
30 #  include <limits.h>
31 #endif
32
33 #include <bashansi.h>
34 #ifdef HAVE_STDDEF_H
35 #  include <stddef.h>
36 #endif
37
38 #ifdef HAVE_STDINT_H
39 #  include <stdint.h>
40 #endif
41 #ifdef HAVE_INTTYPES_H
42 #  include <inttypes.h>
43 #endif
44 #include <chartypes.h>
45 #include <errno.h>
46
47 #include <bashintl.h>
48
49 #include "stdc.h"
50
51 #include <typemax.h>
52
53 #ifndef errno
54 extern int errno;
55 #endif
56
57 #define x_digs  "0123456789abcdef"
58 #define X_digs  "0123456789ABCDEF"
59
60 /* XXX -- assumes uppercase letters, lowercase letters, and digits are
61    contiguous */
62 #define FMTCHAR(x) \
63   ((x) < 10) ? (x) + '0' \
64              : (((x) < 36) ? (x) - 10 + 'a' \
65                            : (((x) < 62) ? (x) - 36 + 'A' \
66                                          : (((x) == 62) ? '@' : '_')))
67
68 #ifndef FL_PREFIX
69 #  define FL_PREFIX     0x01    /* add 0x, 0X, or 0 prefix as appropriate */
70 #  define FL_ADDBASE    0x02    /* add base# prefix to converted value */
71 #  define FL_HEXUPPER   0x04    /* use uppercase when converting to hex */
72 #  define FL_UNSIGNED   0x08    /* don't add any sign */
73 #endif
74
75 #ifndef LONG
76 #  define LONG  long
77 #  define UNSIGNED_LONG unsigned long
78 #endif
79
80 /* `unsigned long' (or unsigned long long) to string conversion for a given
81    base.  The caller passes the output buffer and the size.  This should
82    check for buffer underflow, but currently does not. */
83 char *
84 fmtulong (ui, base, buf, len, flags)
85      UNSIGNED_LONG ui;
86      int base;
87      char *buf;
88      size_t len;
89      int flags;
90 {
91   char *p;
92   int sign;
93   LONG si;
94
95   if (base == 0)
96     base = 10;
97
98   if (base < 2 || base > 64)
99     {
100 #if 1
101       /* XXX - truncation possible with long translation */
102       strncpy (buf, _("invalid base"), len - 1);
103       buf[len-1] = '\0';
104       errno = EINVAL;
105       return (p = buf);
106 #else
107       base = 10;
108 #endif
109     }
110
111   sign = 0;
112   if ((flags & FL_UNSIGNED) == 0 && (LONG)ui < 0)
113     {
114       ui = -ui;
115       sign = '-';
116     }
117
118   p = buf + len - 2;
119   p[1] = '\0';
120
121   /* handle common cases explicitly */
122   switch (base)
123     {
124     case 10:
125       if (ui < 10)
126         {
127           *p-- = TOCHAR (ui);
128           break;
129         }
130       /* Favor signed arithmetic over unsigned arithmetic; it is faster on
131          many machines. */
132       if ((LONG)ui < 0)
133         {
134           *p-- = TOCHAR (ui % 10);
135           si = ui / 10;
136         }
137       else
138         si = ui;
139       do
140         *p-- = TOCHAR (si % 10);
141       while (si /= 10);
142       break;
143
144     case 8:
145       do
146         *p-- = TOCHAR (ui & 7);
147       while (ui >>= 3);
148       break;
149
150     case 16:
151       do
152         *p-- = (flags & FL_HEXUPPER) ? X_digs[ui & 15] : x_digs[ui & 15];
153       while (ui >>= 4);
154       break;
155
156     case 2:
157       do
158         *p-- = TOCHAR (ui & 1);
159       while (ui >>= 1);
160       break;
161
162     default:
163       do
164         *p-- = FMTCHAR (ui % base);
165       while (ui /= base);
166       break;
167     }
168
169   if ((flags & FL_PREFIX) && (base == 8 || base == 16))
170     {
171       if (base == 16)
172         {
173           *p-- = (flags & FL_HEXUPPER) ? 'X' : 'x';
174           *p-- = '0';
175         }
176       else if (p[1] != '0')
177         *p-- = '0';
178     }
179   else if ((flags & FL_ADDBASE) && base != 10)
180     {
181       *p-- = '#';
182       *p-- = TOCHAR (base % 10);
183       if (base > 10)
184         *p-- = TOCHAR (base / 10);
185     }
186
187   if (sign)
188     *p-- = '-';
189
190   return (p + 1);
191 }