1/* mpz_get_str (string, base, mp_src) -- Convert the multiple precision
2   number MP_SRC to a string STRING of base BASE.  If STRING is NULL
3   allocate space for the result.  In any case, return a pointer to the
4   result.  If STRING is not NULL, the caller must ensure enough space is
5   available to store the result.
6
7Copyright 1991, 1993, 1994, 1996, 2000, 2001, 2002, 2005 Free Software
8Foundation, Inc.
9
10This file is part of the GNU MP Library.
11
12The GNU MP Library is free software; you can redistribute it and/or modify
13it under the terms of the GNU Lesser General Public License as published by
14the Free Software Foundation; either version 3 of the License, or (at your
15option) any later version.
16
17The GNU MP Library is distributed in the hope that it will be useful, but
18WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
20License for more details.
21
22You should have received a copy of the GNU Lesser General Public License
23along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
24
25#include <string.h> /* for strlen */
26#include "gmp.h"
27#include "gmp-impl.h"
28#include "longlong.h"
29
30char *
31mpz_get_str (char *res_str, int base, mpz_srcptr x)
32{
33  mp_ptr xp;
34  mp_size_t x_size = x->_mp_size;
35  char *str;
36  char *return_str;
37  size_t str_size;
38  size_t alloc_size = 0;
39  char *num_to_text;
40  int i;
41  TMP_DECL;
42
43  if (base >= 0)
44    {
45      num_to_text = "0123456789abcdefghijklmnopqrstuvwxyz";
46      if (base == 0)
47	base = 10;
48      else if (base > 36)
49	{
50	  num_to_text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
51	  if (base > 62)
52	    return NULL;
53	}
54    }
55  else
56    {
57      base = -base;
58      num_to_text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
59    }
60
61  /* allocate string for the user if necessary */
62  if (res_str == NULL)
63    {
64      /* digits, null terminator, possible minus sign */
65      MPN_SIZEINBASE (alloc_size, PTR(x), ABS(x_size), base);
66      alloc_size += 1 + (x_size<0);
67      res_str = (char *) (*__gmp_allocate_func) (alloc_size);
68    }
69  return_str = res_str;
70
71  if (x_size < 0)
72    {
73      *res_str++ = '-';
74      x_size = -x_size;
75    }
76
77  /* mpn_get_str clobbers its input on non power-of-2 bases */
78  TMP_MARK;
79  xp = x->_mp_d;
80  if (! POW2_P (base))
81    {
82      xp = TMP_ALLOC_LIMBS (x_size + 1);  /* +1 in case x_size==0 */
83      MPN_COPY (xp, x->_mp_d, x_size);
84    }
85
86  str_size = mpn_get_str ((unsigned char *) res_str, base, xp, x_size);
87  ASSERT (alloc_size == 0 || str_size <= alloc_size - (SIZ(x) < 0));
88
89  /* might have a leading zero, skip it */
90  str = res_str;
91  if (*res_str == 0 && str_size != 1)
92    {
93      str_size--;
94      str++;
95      ASSERT (*str != 0);  /* at most one leading zero */
96    }
97
98  /* Convert result to printable chars, and move down if there was a leading
99     zero.  */
100  for (i = 0; i < str_size; i++)
101    res_str[i] = num_to_text[(int) str[i]];
102  res_str[str_size] = 0;
103
104  TMP_FREE;
105
106  /* if allocated then resize down to the actual space required */
107  if (alloc_size != 0)
108    {
109      size_t  actual_size = str_size + 1 + (res_str - return_str);
110      ASSERT (actual_size == strlen (return_str) + 1);
111      __GMP_REALLOCATE_FUNC_MAYBE_TYPE (return_str, alloc_size, actual_size,
112                                        char);
113    }
114  return return_str;
115}
116