dc313be9941a455a140d2cf862b90c43c73e7ec1
[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 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 #ifndef LONG
71 #  define LONG  long
72 #  define UNSIGNED_LONG unsigned long
73 #endif
74
75 /* `unsigned long' (or unsigned long long) to string conversion for a given
76    base.  The caller passes the output buffer and the size.  This should
77    check for buffer underflow, but currently does not. */
78 char *
79 fmtulong (ui, base, buf, len, flags)
80      UNSIGNED_LONG ui;
81      int base;
82      char *buf;
83      size_t len;
84      int flags;
85 {
86   char *p;
87   int sign;
88   LONG si;
89
90   if (base == 0)
91     base = 10;
92
93   if (base < 2 || base > 64)
94     {
95 #if 1
96       strncpy (buf, "invalid base", len - 1);
97       buf[len] = '\0';
98       errno = EINVAL;
99       return (p = buf);
100 #else
101       base = 10;
102 #endif
103     }
104
105   sign = 0;
106   if ((flags & FL_UNSIGNED) == 0 && (LONG)ui < 0)
107     {
108       ui = -ui;
109       sign = '-';
110     }
111
112   p = buf + len - 2;
113   p[1] = '\0';
114
115   /* handle common cases explicitly */
116   switch (base)
117     {
118     case 10:
119       if (ui < 10)
120         {
121           *p-- = TOCHAR (ui);
122           break;
123         }
124       /* Favor signed arithmetic over unsigned arithmetic; it is faster on
125          many machines. */
126       if ((LONG)ui < 0)
127         {
128           *p-- = TOCHAR (ui % 10);
129           si = ui / 10;
130         }
131       else
132         si = ui;
133       do
134         *p-- = TOCHAR (si % 10);
135       while (si /= 10);
136       break;
137
138     case 8:
139       do
140         *p-- = TOCHAR (ui & 7);
141       while (ui >>= 3);
142       break;
143
144     case 16:
145       do
146         *p-- = (flags & FL_HEXUPPER) ? X_digs[ui & 15] : x_digs[ui & 15];
147       while (ui >>= 4);
148       break;
149
150     case 2:
151       do
152         *p-- = TOCHAR (ui & 1);
153       while (ui >>= 1);
154       break;
155
156     default:
157       do
158         *p-- = FMTCHAR (ui % base);
159       while (ui /= base);
160       break;
161     }
162
163   if ((flags & FL_PREFIX) && (base == 8 || base == 16))
164     {
165       if (base == 16)
166         {
167           *p-- = (flags & FL_HEXUPPER) ? 'X' : 'x';
168           *p-- = '0';
169         }
170       else if (p[1] != '0')
171         *p-- = '0';
172     }
173   else if ((flags & FL_ADDBASE) && base != 10)
174     {
175       *p-- = '#';
176       *p-- = TOCHAR (base % 10);
177       if (base > 10)
178         *p-- = TOCHAR (base / 10);
179     }
180
181   if (sign)
182     *p-- = '-';
183
184   return (p + 1);
185 }