diff options
Diffstat (limited to 'lib/sh/fmtulong.c')
-rw-r--r-- | lib/sh/fmtulong.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/lib/sh/fmtulong.c b/lib/sh/fmtulong.c new file mode 100644 index 0000000..43fdffd --- /dev/null +++ b/lib/sh/fmtulong.c @@ -0,0 +1,190 @@ +/* fmtulong.c -- Convert unsigned long int to string. */ + +/* Copyright (C) 1998-2002 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2, or (at your option) any later + version. + + Bash is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with Bash; see the file COPYING. If not, write to the Free Software + Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#if defined (HAVE_LIMITS_H) +# include <limits.h> +#endif + +#include <bashansi.h> +#ifdef HAVE_STDDEF_H +# include <stddef.h> +#endif + +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif +#ifdef HAVE_INTTYPES_H +# include <inttypes.h> +#endif +#include <chartypes.h> +#include <errno.h> + +#include <bashintl.h> + +#include "stdc.h" + +#include <typemax.h> + +#ifndef errno +extern int errno; +#endif + +#define x_digs "0123456789abcdef" +#define X_digs "0123456789ABCDEF" + +/* XXX -- assumes uppercase letters, lowercase letters, and digits are + contiguous */ +#define FMTCHAR(x) \ + ((x) < 10) ? (x) + '0' \ + : (((x) < 36) ? (x) - 10 + 'a' \ + : (((x) < 62) ? (x) - 36 + 'A' \ + : (((x) == 62) ? '@' : '_'))) + +#ifndef FL_PREFIX +# define FL_PREFIX 0x01 /* add 0x, 0X, or 0 prefix as appropriate */ +# define FL_ADDBASE 0x02 /* add base# prefix to converted value */ +# define FL_HEXUPPER 0x04 /* use uppercase when converting to hex */ +# define FL_UNSIGNED 0x08 /* don't add any sign */ +#endif + +#ifndef LONG +# define LONG long +# define UNSIGNED_LONG unsigned long +#endif + +/* `unsigned long' (or unsigned long long) to string conversion for a given + base. The caller passes the output buffer and the size. This should + check for buffer underflow, but currently does not. */ +char * +fmtulong (ui, base, buf, len, flags) + UNSIGNED_LONG ui; + int base; + char *buf; + size_t len; + int flags; +{ + char *p; + int sign; + LONG si; + + if (base == 0) + base = 10; + + if (base < 2 || base > 64) + { +#if 1 + strncpy (buf, _("invalid base"), len - 1); + buf[len] = '\0'; + errno = EINVAL; + return (p = buf); +#else + base = 10; +#endif + } + + sign = 0; + if ((flags & FL_UNSIGNED) == 0 && (LONG)ui < 0) + { + ui = -ui; + sign = '-'; + } + + p = buf + len - 2; + p[1] = '\0'; + + /* handle common cases explicitly */ + switch (base) + { + case 10: + if (ui < 10) + { + *p-- = TOCHAR (ui); + break; + } + /* Favor signed arithmetic over unsigned arithmetic; it is faster on + many machines. */ + if ((LONG)ui < 0) + { + *p-- = TOCHAR (ui % 10); + si = ui / 10; + } + else + si = ui; + do + *p-- = TOCHAR (si % 10); + while (si /= 10); + break; + + case 8: + do + *p-- = TOCHAR (ui & 7); + while (ui >>= 3); + break; + + case 16: + do + *p-- = (flags & FL_HEXUPPER) ? X_digs[ui & 15] : x_digs[ui & 15]; + while (ui >>= 4); + break; + + case 2: + do + *p-- = TOCHAR (ui & 1); + while (ui >>= 1); + break; + + default: + do + *p-- = FMTCHAR (ui % base); + while (ui /= base); + break; + } + + if ((flags & FL_PREFIX) && (base == 8 || base == 16)) + { + if (base == 16) + { + *p-- = (flags & FL_HEXUPPER) ? 'X' : 'x'; + *p-- = '0'; + } + else if (p[1] != '0') + *p-- = '0'; + } + else if ((flags & FL_ADDBASE) && base != 10) + { + *p-- = '#'; + *p-- = TOCHAR (base % 10); + if (base > 10) + *p-- = TOCHAR (base / 10); + } + + if (sign) + *p-- = '-'; + + return (p + 1); +} |