| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | /* fmtulong.c -- Convert unsigned long int to string. */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | /* Copyright (C) 1998-2002 Free Software Foundation, Inc.
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |    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
 | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | #ifdef HAVE_INTTYPES_H
 | 
					
						
							|  |  |  | #  include <inttypes.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #include <chartypes.h>
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | #include <bashintl.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #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
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | #ifndef LONG
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #  define LONG	long
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | #  define UNSIGNED_LONG unsigned long
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #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) | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |      UNSIGNED_LONG ui; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |      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
 | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |       strncpy (buf, _("invalid base"), len - 1); | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |       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. */ | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |       if ((LONG)ui < 0) | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 	  *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); | 
					
						
							|  |  |  | } |