2 * Copyright (c) 2005-2008 Zmanda Inc. All Rights Reserved.
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 2.1 as
6 * published by the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
11 * License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17 * Contact information: Zmanda Inc., 465 S Mathlida Ave, Suite 300
18 * Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
28 /* these functions are only needed if Perl has 32-bit IV's */
29 /* Make sure Math::BigInt is loaded
32 load_Math_BigInt(void)
34 static int loaded = 0;
38 eval_pv("use Math::BigInt; use Amanda::BigIntCompat;", 1);
42 /* Given a string, create a Math::BigInt representing its value.
44 * @param num: string representation of a number
45 * @returns: BigInt representation of the same number
60 XPUSHs(sv_2mortal(newSVpv("Math::BigInt", 0)));
61 XPUSHs(sv_2mortal(newSVpv(num, 0)));
64 count = call_method("Math::BigInt::new", G_SCALAR);
69 croak("Expected a result from Math::Bigint->new");
82 amglue_newSVi64(gint64 v)
85 g_snprintf(numstr, sizeof(numstr), "%jd", (intmax_t)v);
86 numstr[sizeof(numstr)-1] = '\0';
87 return str2bigint(numstr);
91 amglue_newSVu64(guint64 v)
94 g_snprintf(numstr, sizeof(numstr), "%ju", (uintmax_t)v);
95 numstr[sizeof(numstr)-1] = '\0';
96 return str2bigint(numstr);
103 /* Conversion from Perl values handles BigInts regardless of whether
104 * Perl's IVs are 32- or 64-bit, for completeness' sake.
107 /* Convert a bigint to a signed integer, or croak trying.
109 * @param bigint: the perl object to convert
110 * @returns: signed integer
113 bigint2int64(SV *bigint)
118 gboolean negative = FALSE;
122 /* first, see if it's a BigInt */
123 if (!sv_isobject(bigint) || !sv_derived_from(bigint, "Math::BigInt"))
124 croak("Expected an integer or a Math::BigInt; cannot convert");
130 * strtoull($bigint->bstr()) */
136 count = call_method("Math::BigInt::bstr", G_SCALAR);
141 croak("Expected a result from Math::BigInt::bstr");
144 str = SvPV_nolen(sv);
146 croak("Math::BigInt::bstr did not return a string");
154 absval = g_ascii_strtoull(str, NULL, 0);
155 /* (the last branch of this || depends on G_MININT64 = -G_MAXINT64-1) */
156 if ((absval == G_MAXUINT64 && errno == ERANGE)
157 || (!negative && absval > (guint64)(G_MAXINT64))
158 || (negative && absval > (guint64)(G_MAXINT64)+1))
159 croak("Expected a signed 64-bit value or smaller; value '%s' out of range", str);
161 croak("Math::BigInt->bstr returned invalid number '%s'", str);
167 if (negative) return -absval;
171 /* Convert bigint to an unsigned integer, or croak trying.
173 * @param bigint: the perl object to convert
174 * @returns: unsigned integer
177 bigint2uint64(SV *bigint)
185 /* first, see if it's a BigInt */
186 if (!sv_isobject(bigint) || !sv_derived_from(bigint, "Math::BigInt"))
187 croak("Expected an integer or a Math::BigInt; cannot convert");
192 /* make sure the bigint is positive:
193 * croak(..) unless $bigint->sign() eq "+"; */
199 count = call_method("Math::BigInt::sign", G_SCALAR);
204 croak("Expected a result from Math::BigInt::sign");
207 str = SvPV_nolen(sv);
209 croak("Math::BigInt::sign did not return a string");
211 if (strcmp(str, "+") != 0)
212 croak("Expected a positive number; value out of range");
215 * strtoull($bigint->bstr()) */
221 count = call_method("Math::BigInt::bstr", G_SCALAR);
226 croak("Expected a result from Math::BigInt::bstr");
229 str = SvPV_nolen(sv);
231 croak("Math::BigInt::bstr did not return a string");
234 rv = g_ascii_strtoull(str, NULL, 0);
235 if (rv == G_MAXUINT64 && errno == ERANGE)
236 croak("Expected an unsigned 64-bit value or smaller; value '%s' out of range", str);
238 croak("Math::BigInt->bstr returned invalid number '%s'", str);
247 gint64 amglue_SvI64(SV *sv)
255 } else if (SvNOK(sv)) {
256 double dv = SvNV(sv);
258 /* preprocessor constants seem to have trouble here, so we convert to gint64 and
259 * back, and if the result differs, then we have lost something. Note that this will
260 * also error out on integer truncation .. which is probably OK */
261 gint64 iv = (gint64)dv;
262 if (dv != (double)iv) {
263 croak("Expected a signed 64-bit value or smaller; value '%.0f' out of range", (float)dv);
269 return bigint2int64(sv);
273 guint64 amglue_SvU64(SV *sv)
278 } else if (SvIV(sv) < 0) {
279 croak("Expected an unsigned value, got a negative integer");
282 return (guint64)SvIV(sv);
284 } else if (SvNOK(sv)) {
285 double dv = SvNV(sv);
287 croak("Expected an unsigned value, got a negative integer");
289 } else if (dv > (double)G_MAXUINT64) {
290 croak("Expected an unsigned 64-bit value or smaller; value out of range");
296 return bigint2uint64(sv);
300 gint32 amglue_SvI32(SV *sv)
302 gint64 v64 = amglue_SvI64(sv);
303 if (v64 < G_MININT32 || v64 > G_MAXINT32) {
304 croak("Expected a 32-bit integer; value out of range");
311 guint32 amglue_SvU32(SV *sv)
313 guint64 v64 = amglue_SvU64(sv);
314 if (v64 > G_MAXUINT32) {
315 croak("Expected a 32-bit unsigned integer; value out of range");
322 gint16 amglue_SvI16(SV *sv)
324 gint64 v64 = amglue_SvI64(sv);
325 if (v64 < G_MININT16 || v64 > G_MAXINT16) {
326 croak("Expected a 16-bit integer; value out of range");
333 guint16 amglue_SvU16(SV *sv)
335 guint64 v64 = amglue_SvU64(sv);
336 if (v64 > G_MAXUINT16) {
337 croak("Expected a 16-bit unsigned integer; value out of range");
344 gint8 amglue_SvI8(SV *sv)
346 gint64 v64 = amglue_SvI64(sv);
347 if (v64 < G_MININT8 || v64 > G_MAXINT8) {
348 croak("Expected a 8-bit integer; value out of range");
355 guint8 amglue_SvU8(SV *sv)
357 guint64 v64 = amglue_SvU64(sv);
358 if (v64 > G_MAXUINT8) {
359 croak("Expected a 8-bit unsigned integer; value out of range");