⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bigint.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
字号:
/* * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 2.1 as * published by the Free Software Foundation. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA. * * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com */#include "amglue.h"/* * C -> Perl *//* these functions are only needed if Perl has 32-bit IV's *//* Make sure Math::BigInt is loaded */static voidload_Math_BigInt(void){    static int loaded = 0;    if (loaded) return;    eval_pv("use Math::BigInt;", 1);    loaded = 1;}/* Given a string, create a Math::BigInt representing its value. * * @param num: string representation of a number * @returns: BigInt representation of the same number */static SV *str2bigint(char *num){    int count;    SV *rv;    dSP;    load_Math_BigInt();    ENTER;    SAVETMPS;    PUSHMARK(SP);    XPUSHs(sv_2mortal(newSVpv("Math::BigInt", 0)));    XPUSHs(sv_2mortal(newSVpv(num, 0)));    PUTBACK;    count = call_method("Math::BigInt::new", G_SCALAR);    SPAGAIN;    if (count != 1)	croak("Expected a result from Math::Bigint->new");    rv = POPs;    SvREFCNT_inc(rv);    PUTBACK;    FREETMPS;    LEAVE;    return rv;}SV *amglue_newSVi64(gint64 v){    char numstr[25];    g_snprintf(numstr, sizeof(numstr), "%jd", (intmax_t)v);    numstr[sizeof(numstr)-1] = '\0';    return str2bigint(numstr);}SV *amglue_newSVu64(guint64 v){    char numstr[25];    g_snprintf(numstr, sizeof(numstr), "%ju", (uintmax_t)v);    numstr[sizeof(numstr)-1] = '\0';    return str2bigint(numstr);}/* * Perl -> C *//* Conversion from Perl values handles BigInts regardless of whether * Perl's IVs are 32- or 64-bit, for completeness' sake. *//* Convert a bigint to a signed integer, or croak trying. * * @param bigint: the perl object to convert * @returns: signed integer */static gint64bigint2int64(SV *bigint){    SV *sv;    char *str;    guint64 absval;    gboolean negative = FALSE;    int count;    dSP;    /* first, see if it's a BigInt */    if (!sv_isobject(bigint) || !sv_derived_from(bigint, "Math::BigInt"))	croak("Expected an integer or a Math::BigInt; cannot convert");    ENTER;    SAVETMPS;    /* get the value:     * strtoull($bigint->bstr()) */    PUSHMARK(SP);    XPUSHs(bigint);    PUTBACK;    count = call_method("Math::BigInt::bstr", G_SCALAR);    SPAGAIN;    if (count != 1)	croak("Expected a result from Math::BigInt::bstr");    sv = POPs;    str = SvPV_nolen(sv);    if (!str)	croak("Math::BigInt::bstr did not return a string");    if (str[0] == '-') {	negative = TRUE;	str++;    }    errno = 0;    absval = g_ascii_strtoull(str, NULL, 0);    /* (the last branch of this || depends on G_MININT64 = -G_MAXINT64-1) */    if ((absval == G_MAXUINT64 && errno == ERANGE)        || (!negative && absval > (guint64)(G_MAXINT64))	|| (negative && absval > (guint64)(G_MAXINT64)+1))	croak("Expected a signed 64-bit value or smaller; value '%s' out of range", str);    if (errno)	croak("Math::BigInt->bstr returned invalid number '%s'", str);    PUTBACK;    FREETMPS;    LEAVE;    if (negative) return -absval;    return absval;}/* Convert bigint to an unsigned integer, or croak trying. * * @param bigint: the perl object to convert * @returns: unsigned integer */static guint64bigint2uint64(SV *bigint){    SV *sv;    char *str;    guint64 rv;    int count;    dSP;    /* first, see if it's a BigInt */    if (!sv_isobject(bigint) || !sv_derived_from(bigint, "Math::BigInt"))	croak("Expected an integer or a Math::BigInt; cannot convert");    ENTER;    SAVETMPS;    /* make sure the bigint is positive:     * croak(..) unless $bigint->sign() eq "+"; */    PUSHMARK(SP);    XPUSHs(bigint);    PUTBACK;    count = call_method("Math::BigInt::sign", G_SCALAR);    SPAGAIN;    if (count != 1)	croak("Expected a result from Math::BigInt::sign");    sv = POPs;    str = SvPV_nolen(sv);    if (!str)	croak("Math::BigInt::sign did not return a string");    if (strcmp(str, "+") != 0)	croak("Expected a positive number; value out of range");    /* get the value:     * strtoull($bigint->bstr()) */    PUSHMARK(SP);    XPUSHs(bigint);    PUTBACK;    count = call_method("Math::BigInt::bstr", G_SCALAR);    SPAGAIN;    if (count != 1)	croak("Expected a result from Math::BigInt::bstr");    sv = POPs;    str = SvPV_nolen(sv);    if (!str)	croak("Math::BigInt::bstr did not return a string");    errno = 0;    rv = g_ascii_strtoull(str, NULL, 0);    if (rv == G_MAXUINT64 && errno == ERANGE)	croak("Expected an unsigned 64-bit value or smaller; value '%s' out of range", str);    if (errno)	croak("Math::BigInt->bstr returned invalid number '%s'", str);    PUTBACK;    FREETMPS;    LEAVE;    return rv;}gint64 amglue_SvI64(SV *sv){    if (SvIOK(sv)) {	if (SvIsUV(sv)) {	    return SvUV(sv);	} else {	    return SvIV(sv);	}    } else if (SvNOK(sv)) {	double dv = SvNV(sv);	/* preprocessor constants seem to have trouble here, so we convert to gint64 and	 * back, and if the result differs, then we have lost something.  Note that this will	 * also error out on integer truncation .. which is probably OK */	gint64 iv = (gint64)dv;	if (dv != (double)iv) {	    croak("Expected a signed 64-bit value or smaller; value '%.0f' out of range", (float)dv);	    return 0;	} else {	    return iv;	}    } else {	return bigint2int64(sv);    }}guint64 amglue_SvU64(SV *sv){    if (SvIOK(sv)) {	if (SvIsUV(sv)) {	    return SvUV(sv);	} else if (SvIV(sv) < 0) {	    croak("Expected an unsigned value, got a negative integer");	    return 0;	} else {	    return (guint64)SvIV(sv);	}    } else if (SvNOK(sv)) {	double dv = SvNV(sv);	if (dv < 0.0) {	    croak("Expected an unsigned value, got a negative integer");	    return 0;	} else if (dv > (double)G_MAXUINT64) {	    croak("Expected an unsigned 64-bit value or smaller; value out of range");	    return 0;	} else {	    return (guint64)dv;	}    } else {	return bigint2uint64(sv);    }}gint32 amglue_SvI32(SV *sv){    gint64 v64 = amglue_SvI64(sv);    if (v64 < G_MININT32 || v64 > G_MAXINT32) {	croak("Expected a 32-bit integer; value out of range");	return 0;    } else {	return (gint32)v64;    }}guint32 amglue_SvU32(SV *sv){    guint64 v64 = amglue_SvU64(sv);    if (v64 > G_MAXUINT32) {	croak("Expected a 32-bit unsigned integer; value out of range");	return 0;    } else {	return (guint32)v64;    }}gint16 amglue_SvI16(SV *sv){    gint64 v64 = amglue_SvI64(sv);    if (v64 < G_MININT16 || v64 > G_MAXINT16) {	croak("Expected a 16-bit integer; value out of range");	return 0;    } else {	return (gint16)v64;    }}guint16 amglue_SvU16(SV *sv){    guint64 v64 = amglue_SvU64(sv);    if (v64 > G_MAXUINT16) {	croak("Expected a 16-bit unsigned integer; value out of range");	return 0;    } else {	return (guint16)v64;    }}gint8 amglue_SvI8(SV *sv){    gint64 v64 = amglue_SvI64(sv);    if (v64 < G_MININT8 || v64 > G_MAXINT8) {	croak("Expected a 8-bit integer; value out of range");	return 0;    } else {	return (gint8)v64;    }}guint8 amglue_SvU8(SV *sv){    guint64 v64 = amglue_SvU64(sv);    if (v64 > G_MAXUINT8) {	croak("Expected a 8-bit unsigned integer; value out of range");	return 0;    } else {	return (guint8)v64;    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -