summaryrefslogtreecommitdiffstats
path: root/lib/sh/fmtulong.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sh/fmtulong.c')
-rw-r--r--lib/sh/fmtulong.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/lib/sh/fmtulong.c b/lib/sh/fmtulong.c
new file mode 100644
index 0000000..0ccc22b
--- /dev/null
+++ b/lib/sh/fmtulong.c
@@ -0,0 +1,191 @@
+/* fmtulong.c -- Convert unsigned long int to string. */
+
+/* Copyright (C) 1998-2011 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#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
+ /* XXX - truncation possible with long translation */
+ strncpy (buf, _("invalid base"), len - 1);
+ buf[len-1] = '\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);
+}