2 * Copyright (c) 2007, 2008, 2009, 2010 Zmanda, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published
6 * by the Free Software Foundation.
8 * This program 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 General Public License
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
18 * Sunnyvale, CA 94085, 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
62 XPUSHs(sv_2mortal(newSVpv("Math::BigInt", 0)));
63 XPUSHs(sv_2mortal(newSVpv(num, 0)));
66 count = call_method("new", G_SCALAR);
71 croak("Expected a result from Math::Bigint->new");
84 amglue_newSVi64(gint64 v)
87 g_snprintf(numstr, sizeof(numstr), "%jd", (intmax_t)v);
88 numstr[sizeof(numstr)-1] = '\0';
89 return str2bigint(numstr);
93 amglue_newSVu64(guint64 v)
96 g_snprintf(numstr, sizeof(numstr), "%ju", (uintmax_t)v);
97 numstr[sizeof(numstr)-1] = '\0';
98 return str2bigint(numstr);
105 /* Conversion from Perl values handles BigInts regardless of whether
106 * Perl's IVs are 32- or 64-bit, for completeness' sake.
109 /* Convert a bigint to a signed integer, or croak trying.
111 * @param bigint: the perl object to convert
112 * @returns: signed integer
115 bigint2int64(SV *bigint)
120 gboolean negative = FALSE;
124 /* first, see if it's a BigInt */
125 if (!sv_isobject(bigint) || !sv_derived_from(bigint, "Math::BigInt"))
126 croak("Expected an integer or a Math::BigInt; cannot convert");
132 * strtoull($bigint->bstr()) */
138 count = call_method("Math::BigInt::bstr", G_SCALAR);
143 croak("Expected a result from Math::BigInt::bstr");
146 str = SvPV_nolen(sv);
148 croak("Math::BigInt::bstr did not return a string");
156 absval = g_ascii_strtoull(str, NULL, 0);
157 /* (the last branch of this || depends on G_MININT64 = -G_MAXINT64-1) */
158 if ((absval == G_MAXUINT64 && errno == ERANGE)
159 || (!negative && absval > (guint64)(G_MAXINT64))
160 || (negative && absval > (guint64)(G_MAXINT64)+1))
161 croak("Expected a signed 64-bit value or smaller; value '%s' out of range", str);
163 croak("Math::BigInt->bstr returned invalid number '%s'", str);
169 if (negative) return -absval;
173 /* Convert bigint to an unsigned integer, or croak trying.
175 * @param bigint: the perl object to convert
176 * @returns: unsigned integer
179 bigint2uint64(SV *bigint)
187 /* first, see if it's a BigInt */
188 if (!sv_isobject(bigint) || !sv_derived_from(bigint, "Math::BigInt"))
189 croak("Expected an integer or a Math::BigInt; cannot convert");
194 /* make sure the bigint is positive:
195 * croak(..) unless $bigint->sign() eq "+"; */
201 count = call_method("Math::BigInt::sign", G_SCALAR);
206 croak("Expected a result from Math::BigInt::sign");
209 str = SvPV_nolen(sv);
211 croak("Math::BigInt::sign did not return a string");
213 if (strcmp(str, "+") != 0)
214 croak("Expected a positive number; value out of range");
217 * strtoull($bigint->bstr()) */
223 count = call_method("Math::BigInt::bstr", G_SCALAR);
228 croak("Expected a result from Math::BigInt::bstr");
231 str = SvPV_nolen(sv);
233 croak("Math::BigInt::bstr did not return a string");
236 rv = g_ascii_strtoull(str, NULL, 0);
237 if (rv == G_MAXUINT64 && errno == ERANGE)
238 croak("Expected an unsigned 64-bit value or smaller; value '%s' out of range", str);
240 croak("Math::BigInt->bstr returned invalid number '%s'", str);
249 gint64 amglue_SvI64(SV *sv)
257 } else if (SvNOK(sv)) {
258 double dv = SvNV(sv);
260 /* preprocessor constants seem to have trouble here, so we convert to gint64 and
261 * back, and if the result differs, then we have lost something. Note that this will
262 * also error out on integer truncation .. which is probably OK */
263 gint64 iv = (gint64)dv;
264 if (dv != (double)iv) {
265 croak("Expected a signed 64-bit value or smaller; value '%.0f' out of range", (float)dv);
271 return bigint2int64(sv);
275 guint64 amglue_SvU64(SV *sv)
280 } else if (SvIV(sv) < 0) {
281 croak("Expected an unsigned value, got a negative integer");
284 return (guint64)SvIV(sv);
286 } else if (SvNOK(sv)) {
287 double dv = SvNV(sv);
289 croak("Expected an unsigned value, got a negative integer");
291 } else if (dv > (double)G_MAXUINT64) {
292 croak("Expected an unsigned 64-bit value or smaller; value out of range");
298 return bigint2uint64(sv);
302 gint32 amglue_SvI32(SV *sv)
304 gint64 v64 = amglue_SvI64(sv);
305 if (v64 < G_MININT32 || v64 > G_MAXINT32) {
306 croak("Expected a 32-bit integer; value out of range");
313 guint32 amglue_SvU32(SV *sv)
315 guint64 v64 = amglue_SvU64(sv);
316 if (v64 > G_MAXUINT32) {
317 croak("Expected a 32-bit unsigned integer; value out of range");
324 gint16 amglue_SvI16(SV *sv)
326 gint64 v64 = amglue_SvI64(sv);
327 if (v64 < G_MININT16 || v64 > G_MAXINT16) {
328 croak("Expected a 16-bit integer; value out of range");
335 guint16 amglue_SvU16(SV *sv)
337 guint64 v64 = amglue_SvU64(sv);
338 if (v64 > G_MAXUINT16) {
339 croak("Expected a 16-bit unsigned integer; value out of range");
346 gint8 amglue_SvI8(SV *sv)
348 gint64 v64 = amglue_SvI64(sv);
349 if (v64 < G_MININT8 || v64 > G_MAXINT8) {
350 croak("Expected a 8-bit integer; value out of range");
357 guint8 amglue_SvU8(SV *sv)
359 guint64 v64 = amglue_SvU64(sv);
360 if (v64 > G_MAXUINT8) {
361 croak("Expected a 8-bit unsigned integer; value out of range");