214b1466a50ad8a8a188111af768e8c0984b9d7f
[platform/upstream/bash.git] / lib / sh / fmtulong.c
1 /* fmtulong.c -- Convert unsigned long int to string. */
2
3 /* Copyright (C) 1998-2002 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       strncpy (buf, _("invalid base"), len - 1);
102       buf[len] = '\0';
103       errno = EINVAL;
104       return (p = buf);
105 #else
106       base = 10;
107 #endif
108     }
109
110   sign = 0;
111   if ((flags & FL_UNSIGNED) == 0 && (LONG)ui < 0)
112     {
113       ui = -ui;
114       sign = '-';
115     }
116
117   p = buf + len - 2;
118   p[1] = '\0';
119
120   /* handle common cases explicitly */
121   switch (base)
122     {
123     case 10:
124       if (ui < 10)
125         {
126           *p-- = TOCHAR (ui);
127           break;
128         }
129       /* Favor signed arithmetic over unsigned arithmetic; it is faster on
130          many machines. */
131       if ((LONG)ui < 0)
132         {
133           *p-- = TOCHAR (ui % 10);
134           si = ui / 10;
135         }
136       else
137         si = ui;
138       do
139         *p-- = TOCHAR (si % 10);
140       while (si /= 10);
141       break;
142
143     case 8:
144       do
145         *p-- = TOCHAR (ui & 7);
146       while (ui >>= 3);
147       break;
148
149     case 16:
150       do
151         *p-- = (flags & FL_HEXUPPER) ? X_digs[ui & 15] : x_digs[ui & 15];
152       while (ui >>= 4);
153       break;
154
155     case 2:
156       do
157         *p-- = TOCHAR (ui & 1);
158       while (ui >>= 1);
159       break;
160
161     default:
162       do
163         *p-- = FMTCHAR (ui % base);
164       while (ui /= base);
165       break;
166     }
167
168   if ((flags & FL_PREFIX) && (base == 8 || base == 16))
169     {
170       if (base == 16)
171         {
172           *p-- = (flags & FL_HEXUPPER) ? 'X' : 'x';
173           *p-- = '0';
174         }
175       else if (p[1] != '0')
176         *p-- = '0';
177     }
178   else if ((flags & FL_ADDBASE) && base != 10)
179     {
180       *p-- = '#';
181       *p-- = TOCHAR (base % 10);
182       if (base > 10)
183         *p-- = TOCHAR (base / 10);
184     }
185
186   if (sign)
187     *p-- = '-';
188
189   return (p + 1);
190 }