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