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