blob: 6feda41ed44c6ead82a790cbc5748601304b7db1 [file] [log] [blame]
Jari Aaltof73dda02001-11-13 17:56:06 +00001/* fmtulong.c -- Convert unsigned long int to string. */
2
Chet Rameyac50fba2014-02-26 09:36:43 -05003/* Copyright (C) 1998-2011 Free Software Foundation, Inc.
Jari Aaltof73dda02001-11-13 17:56:06 +00004
5 This file is part of GNU Bash, the Bourne Again SHell.
6
Jari Aalto31859422009-01-12 13:36:28 +00007 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.
Jari Aaltof73dda02001-11-13 17:56:06 +000011
Jari Aalto31859422009-01-12 13:36:28 +000012 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.
Jari Aaltof73dda02001-11-13 17:56:06 +000016
Jari Aalto31859422009-01-12 13:36:28 +000017 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*/
Jari Aaltof73dda02001-11-13 17:56:06 +000020
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
Jari Aaltob80f6442004-07-27 13:29:18 +000041#ifdef HAVE_INTTYPES_H
42# include <inttypes.h>
43#endif
Jari Aaltof73dda02001-11-13 17:56:06 +000044#include <chartypes.h>
45#include <errno.h>
46
Jari Aaltob80f6442004-07-27 13:29:18 +000047#include <bashintl.h>
48
Jari Aaltof73dda02001-11-13 17:56:06 +000049#include "stdc.h"
50
51#include <typemax.h>
52
53#ifndef errno
Ricardo Cerqueiraa02fbff2013-07-25 22:35:34 +010054#include <errno.h>
Jari Aaltof73dda02001-11-13 17:56:06 +000055#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
Jari Aalto7117c2d2002-07-17 14:10:11 +000075#ifndef LONG
Jari Aaltof73dda02001-11-13 17:56:06 +000076# define LONG long
Jari Aalto7117c2d2002-07-17 14:10:11 +000077# define UNSIGNED_LONG unsigned long
Jari Aaltof73dda02001-11-13 17:56:06 +000078#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. */
83char *
84fmtulong (ui, base, buf, len, flags)
Jari Aalto7117c2d2002-07-17 14:10:11 +000085 UNSIGNED_LONG ui;
Jari Aaltof73dda02001-11-13 17:56:06 +000086 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
Chet Rameyac50fba2014-02-26 09:36:43 -0500101 /* XXX - truncation possible with long translation */
Jari Aaltob80f6442004-07-27 13:29:18 +0000102 strncpy (buf, _("invalid base"), len - 1);
Chet Rameyac50fba2014-02-26 09:36:43 -0500103 buf[len-1] = '\0';
Jari Aaltof73dda02001-11-13 17:56:06 +0000104 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. */
Jari Aalto7117c2d2002-07-17 14:10:11 +0000132 if ((LONG)ui < 0)
Jari Aaltof73dda02001-11-13 17:56:06 +0000133 {
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}