|
Packit Service |
af52df |
#include <gmp.h>
|
|
Packit Service |
af52df |
#include <mpfr.h>
|
|
Packit Service |
af52df |
#include <langinfo.h>
|
|
Packit Service |
af52df |
#include <stdarg.h>
|
|
Packit Service |
af52df |
#include <stdio.h>
|
|
Packit Service |
af52df |
#include <inttypes.h>
|
|
Packit Service |
af52df |
#include <string.h>
|
|
Packit Service |
af52df |
#include <ctype.h>
|
|
Packit Service |
af52df |
#include <limits.h>
|
|
Packit Service |
af52df |
#include <pcre.h>
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
#include "bs_size.h"
|
|
Packit Service |
af52df |
#include "gettext.h"
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
#define _(String) gettext (String)
|
|
Packit Service |
af52df |
#define N_(String) String
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* SECTION: bs_size
|
|
Packit Service |
af52df |
* @title: BSSize
|
|
Packit Service |
af52df |
* @short_description: a class facilitating work with sizes in bytes
|
|
Packit Service |
af52df |
* @include: bs_size.h
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* #BSSize is a type that facilitates work with sizes in bytes by providing
|
|
Packit Service |
af52df |
* functions/methods that are required for parsing users input when entering
|
|
Packit Service |
af52df |
* size, showing size in nice human-readable format, storing sizes bigger than
|
|
Packit Service |
af52df |
* %UINT64_MAX and doing calculations with sizes without loss of
|
|
Packit Service |
af52df |
* precision/information. The class is able to hold negative sizes and do
|
|
Packit Service |
af52df |
* operations on/with them, but some of the (division and multiplication)
|
|
Packit Service |
af52df |
* operations simply ignore the signs of the operands (check the documentation).
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* The reason why some functions take or return a float as a string instead of a
|
|
Packit Service |
af52df |
* float directly is because a string "0.3" can be translated into 0.3 with
|
|
Packit Service |
af52df |
* appropriate precision while 0.3 as float is probably something like
|
|
Packit Service |
af52df |
* 0.294343... with unknown precision.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/***************
|
|
Packit Service |
af52df |
* STATIC DATA *
|
|
Packit Service |
af52df |
***************/
|
|
Packit Service |
af52df |
static char const * const b_units[BS_BUNIT_UNDEF] = {
|
|
Packit Service |
af52df |
/* TRANSLATORS: 'B' for bytes */
|
|
Packit Service |
af52df |
N_("B"),
|
|
Packit Service |
af52df |
/* TRANSLATORS: abbreviation for kibibyte, 2**10 bytes */
|
|
Packit Service |
af52df |
N_("KiB"),
|
|
Packit Service |
af52df |
/* TRANSLATORS: abbreviation for mebibyte, 2**20 bytes */
|
|
Packit Service |
af52df |
N_("MiB"),
|
|
Packit Service |
af52df |
/* TRANSLATORS: abbreviation for gibibyte, 2**30 bytes */
|
|
Packit Service |
af52df |
N_("GiB"),
|
|
Packit Service |
af52df |
/* TRANSLATORS: abbreviation for tebibyte, 2**40 bytes */
|
|
Packit Service |
af52df |
N_("TiB"),
|
|
Packit Service |
af52df |
/* TRANSLATORS: abbreviation for pebibyte, 2**50 bytes */
|
|
Packit Service |
af52df |
N_("PiB"),
|
|
Packit Service |
af52df |
/* TRANSLATORS: abbreviation for exbibyte, 2**60 bytes */
|
|
Packit Service |
af52df |
N_("EiB"),
|
|
Packit Service |
af52df |
/* TRANSLATORS: abbreviation for zebibyte, 2**70 bytes */
|
|
Packit Service |
af52df |
N_("ZiB"),
|
|
Packit Service |
af52df |
/* TRANSLATORS: abbreviation for yobibyte, 2**80 bytes */
|
|
Packit Service |
af52df |
N_("YiB")
|
|
Packit Service |
af52df |
};
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
static char const * const d_units[BS_DUNIT_UNDEF] = {
|
|
Packit Service |
af52df |
/* TRANSLATORS: 'B' for bytes */
|
|
Packit Service |
af52df |
N_("B"),
|
|
Packit Service |
af52df |
/* TRANSLATORS: abbreviation for kilobyte, 10**3 bytes */
|
|
Packit Service |
af52df |
N_("KB"),
|
|
Packit Service |
af52df |
/* TRANSLATORS: abbreviation for megabyte, 10**6 bytes */
|
|
Packit Service |
af52df |
N_("MB"),
|
|
Packit Service |
af52df |
/* TRANSLATORS: abbreviation for gigabyte, 10**9 bytes */
|
|
Packit Service |
af52df |
N_("GB"),
|
|
Packit Service |
af52df |
/* TRANSLATORS: abbreviation for terabyte, 10**12 bytes */
|
|
Packit Service |
af52df |
N_("TB"),
|
|
Packit Service |
af52df |
/* TRANSLATORS: abbreviation for petabyte, 10**15 bytes */
|
|
Packit Service |
af52df |
N_("PB"),
|
|
Packit Service |
af52df |
/* TRANSLATORS: abbreviation for exabyte, 10**18 bytes */
|
|
Packit Service |
af52df |
N_("EB"),
|
|
Packit Service |
af52df |
/* TRANSLATORS: abbreviation for zettabyte, 10**21 bytes */
|
|
Packit Service |
af52df |
N_("ZB"),
|
|
Packit Service |
af52df |
/* TRANSLATORS: abbreviation for yottabyte, 10**24 bytes */
|
|
Packit Service |
af52df |
N_("YB")
|
|
Packit Service |
af52df |
};
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/****************************
|
|
Packit Service |
af52df |
* STRUCT DEFINITIONS *
|
|
Packit Service |
af52df |
****************************/
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* BSSize:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* The BSSize struct contains only private fields and should not be directly
|
|
Packit Service |
af52df |
* accessed.
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
struct _BSSize {
|
|
Packit Service |
af52df |
mpz_t bytes;
|
|
Packit Service |
af52df |
};
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/********************
|
|
Packit Service |
af52df |
* HELPER FUNCTIONS *
|
|
Packit Service |
af52df |
********************/
|
|
Packit Service |
af52df |
static void bs_size_init (BSSize size) {
|
|
Packit Service |
af52df |
/* let's start with 64 bits of space */
|
|
Packit Service |
af52df |
mpz_init2 (size->bytes, (mp_bitcnt_t) 64);
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
static char *strdup_printf (const char *fmt, ...) {
|
|
Packit Service |
af52df |
int num = 0;
|
|
Packit Service |
af52df |
char *ret = NULL;
|
|
Packit Service |
af52df |
va_list ap;
|
|
Packit Service |
af52df |
va_start (ap, fmt);
|
|
Packit Service |
af52df |
num = vasprintf (&ret, fmt, ap);
|
|
Packit Service |
af52df |
va_end (ap);
|
|
Packit Service |
af52df |
if (num <= 0)
|
|
Packit Service |
af52df |
/* make sure we return NULL on error */
|
|
Packit Service |
af52df |
ret = NULL;
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* replace_char_with_str: (skip)
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Replaces all apperances of @char in @str with @new.
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
static char *replace_char_with_str (const char *str, char orig, const char *new) {
|
|
Packit Service |
af52df |
uint64_t offset = 0;
|
|
Packit Service |
af52df |
uint64_t i = 0;
|
|
Packit Service |
af52df |
uint64_t j = 0;
|
|
Packit Service |
af52df |
char *ret = NULL;
|
|
Packit Service |
af52df |
const char *next = NULL;
|
|
Packit Service |
af52df |
uint64_t count = 0;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
if (!str)
|
|
Packit Service |
af52df |
return NULL;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
next = str;
|
|
Packit Service |
af52df |
for (next=strchr (next, orig); next; count++, next=strchr (++next, orig));
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/* allocate space for the string [strlen(str)] with the char replaced by the
|
|
Packit Service |
af52df |
string [strlen(new) - 1] $count times and a \0 byte at the end [ + 1] */
|
|
Packit Service |
af52df |
ret = malloc (sizeof(char) * (strlen(str) + (strlen(new) - 1) * count + 1));
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
for (i=0; str[i]; i++) {
|
|
Packit Service |
af52df |
if (str[i] == orig)
|
|
Packit Service |
af52df |
for (j=0; new[j]; j++) {
|
|
Packit Service |
af52df |
ret[i+offset] = new[j];
|
|
Packit Service |
af52df |
if (new[j+1])
|
|
Packit Service |
af52df |
/* something more to copy over */
|
|
Packit Service |
af52df |
offset++;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
else
|
|
Packit Service |
af52df |
ret[i+offset] = str[i];
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
ret[i+offset] = '\0';
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* replace_str_with_str: (skip)
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Replaces the first appearance of @orig in @str with @new.
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
static char *replace_str_with_str (const char *str, const char *orig, const char *new) {
|
|
Packit Service |
af52df |
char *pos = NULL;
|
|
Packit Service |
af52df |
int str_len = 0;
|
|
Packit Service |
af52df |
int orig_len = 0;
|
|
Packit Service |
af52df |
int new_len = 0;
|
|
Packit Service |
af52df |
char *ret = NULL;
|
|
Packit Service |
af52df |
int ret_size = 0;
|
|
Packit Service |
af52df |
char *dest = NULL;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
pos = strstr (str, orig);
|
|
Packit Service |
af52df |
if (!pos)
|
|
Packit Service |
af52df |
/* nothing to do, just return a copy */
|
|
Packit Service |
af52df |
return strdup (str);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
str_len = strlen (str);
|
|
Packit Service |
af52df |
orig_len = strlen (orig);
|
|
Packit Service |
af52df |
new_len = strlen (new);
|
|
Packit Service |
af52df |
ret_size = str_len + new_len - orig_len + 1;
|
|
Packit Service |
af52df |
ret = malloc (sizeof(char) * ret_size);
|
|
Packit Service |
af52df |
memset (ret, 0, ret_size);
|
|
Packit Service |
af52df |
memcpy (ret, str, pos - str);
|
|
Packit Service |
af52df |
dest = ret + (pos - str);
|
|
Packit Service |
af52df |
memcpy (dest, new, new_len);
|
|
Packit Service |
af52df |
dest = dest + new_len;
|
|
Packit Service |
af52df |
memcpy (dest, pos + orig_len, str_len - (pos - str) - orig_len);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* strstrip: (skip)
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Strips leading and trailing whitespace from the string (**IN-PLACE**)
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
static void strstrip(char *str) {
|
|
Packit Service |
af52df |
int i = 0;
|
|
Packit Service |
af52df |
int begin = 0;
|
|
Packit Service |
af52df |
int end = strlen(str) - 1;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
while (isspace(str[begin]))
|
|
Packit Service |
af52df |
begin++;
|
|
Packit Service |
af52df |
while ((end >= begin) && isspace(str[end]))
|
|
Packit Service |
af52df |
end--;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
for (i=begin; i <= end; i++)
|
|
Packit Service |
af52df |
str[i - begin] = str[i];
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
str[i-begin] = '\0';
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
static bool multiply_size_by_unit (mpfr_t size, char *unit_str) {
|
|
Packit Service |
af52df |
BSBunit bunit = BS_BUNIT_UNDEF;
|
|
Packit Service |
af52df |
BSDunit dunit = BS_DUNIT_UNDEF;
|
|
Packit Service |
af52df |
uint64_t pwr = 0;
|
|
Packit Service |
af52df |
mpfr_t dec_mul;
|
|
Packit Service |
af52df |
size_t unit_str_len = 0;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
unit_str_len = strlen (unit_str);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
for (bunit=BS_BUNIT_B; bunit < BS_BUNIT_UNDEF; bunit++)
|
|
Packit Service |
af52df |
if (strncasecmp (unit_str, b_units[bunit-BS_BUNIT_B], unit_str_len) == 0) {
|
|
Packit Service |
af52df |
pwr = (uint64_t) bunit - BS_BUNIT_B;
|
|
Packit Service |
af52df |
mpfr_mul_2exp (size, size, 10 * pwr, MPFR_RNDN);
|
|
Packit Service |
af52df |
return true;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpfr_init2 (dec_mul, BS_FLOAT_PREC_BITS);
|
|
Packit Service |
af52df |
mpfr_set_ui (dec_mul, 1000, MPFR_RNDN);
|
|
Packit Service |
af52df |
for (dunit=BS_DUNIT_B; dunit < BS_DUNIT_UNDEF; dunit++)
|
|
Packit Service |
af52df |
if (strncasecmp (unit_str, d_units[dunit-BS_DUNIT_B], unit_str_len) == 0) {
|
|
Packit Service |
af52df |
pwr = (uint64_t) (dunit - BS_DUNIT_B);
|
|
Packit Service |
af52df |
mpfr_pow_ui (dec_mul, dec_mul, pwr, MPFR_RNDN);
|
|
Packit Service |
af52df |
mpfr_mul (size, size, dec_mul, MPFR_RNDN);
|
|
Packit Service |
af52df |
mpfr_clear (dec_mul);
|
|
Packit Service |
af52df |
return true;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/* not found among the binary and decimal units, let's try their translated
|
|
Packit Service |
af52df |
verions */
|
|
Packit Service |
af52df |
for (bunit=BS_BUNIT_B; bunit < BS_BUNIT_UNDEF; bunit++)
|
|
Packit Service |
af52df |
if (strncasecmp (unit_str, _(b_units[bunit-BS_BUNIT_B]), unit_str_len) == 0) {
|
|
Packit Service |
af52df |
pwr = (uint64_t) bunit - BS_BUNIT_B;
|
|
Packit Service |
af52df |
mpfr_mul_2exp (size, size, 10 * pwr, MPFR_RNDN);
|
|
Packit Service |
af52df |
return true;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpfr_init2 (dec_mul, BS_FLOAT_PREC_BITS);
|
|
Packit Service |
af52df |
mpfr_set_ui (dec_mul, 1000, MPFR_RNDN);
|
|
Packit Service |
af52df |
for (dunit=BS_DUNIT_B; dunit < BS_DUNIT_UNDEF; dunit++)
|
|
Packit Service |
af52df |
if (strncasecmp (unit_str, _(d_units[dunit-BS_DUNIT_B]), unit_str_len) == 0) {
|
|
Packit Service |
af52df |
pwr = (uint64_t) (dunit - BS_DUNIT_B);
|
|
Packit Service |
af52df |
mpfr_pow_ui (dec_mul, dec_mul, pwr, MPFR_RNDN);
|
|
Packit Service |
af52df |
mpfr_mul (size, size, dec_mul, MPFR_RNDN);
|
|
Packit Service |
af52df |
mpfr_clear (dec_mul);
|
|
Packit Service |
af52df |
return true;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return false;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* set_error: (skip)
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Sets @error to @code and @msg (if not %NULL). **TAKES OVER @msg.**
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
static void set_error (BSError **error, BSErrorCode code, char *msg) {
|
|
Packit Service |
af52df |
*error = (BSError *) malloc (sizeof(BSError));
|
|
Packit Service |
af52df |
(*error)->code = code;
|
|
Packit Service |
af52df |
(*error)->msg = msg;
|
|
Packit Service |
af52df |
return;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
typedef void (*MpzOp) (mpz_t ROP, const mpz_t OP1, unsigned long int OP2);
|
|
Packit Service |
af52df |
static void do_64bit_add_sub (MpzOp op, mpz_t rop, const mpz_t op1, uint64_t op2) {
|
|
Packit Service |
af52df |
uint64_t i = 0;
|
|
Packit Service |
af52df |
uint64_t div = 0;
|
|
Packit Service |
af52df |
uint64_t mod = 0;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/* small enough to just work */
|
|
Packit Service |
af52df |
if (op2 < (uint64_t) ULONG_MAX) {
|
|
Packit Service |
af52df |
op (rop, op1, (unsigned long int) op2);
|
|
Packit Service |
af52df |
return;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpz_set (rop, op1);
|
|
Packit Service |
af52df |
div = op2 / (uint64_t) ULONG_MAX;
|
|
Packit Service |
af52df |
mod = op2 % (uint64_t) ULONG_MAX;
|
|
Packit Service |
af52df |
for (i=0; i < div; i++)
|
|
Packit Service |
af52df |
op (rop, rop, (unsigned long int) ULONG_MAX);
|
|
Packit Service |
af52df |
op (rop, rop, (unsigned long int) mod);
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
static void mul_64bit (mpz_t rop, const mpz_t op1, uint64_t op2) {
|
|
Packit Service |
af52df |
uint64_t i = 0;
|
|
Packit Service |
af52df |
uint64_t div = 0;
|
|
Packit Service |
af52df |
uint64_t mod = 0;
|
|
Packit Service |
af52df |
mpz_t aux;
|
|
Packit Service |
af52df |
mpz_t res;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/* small enough to just work */
|
|
Packit Service |
af52df |
if (op2 < (uint64_t) ULONG_MAX) {
|
|
Packit Service |
af52df |
mpz_mul_ui (rop, op1, (unsigned long int) op2);
|
|
Packit Service |
af52df |
return;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpz_init2 (aux, (mp_bitcnt_t) 64);
|
|
Packit Service |
af52df |
mpz_init2 (res, (mp_bitcnt_t) 64);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpz_set_ui (res, 0);
|
|
Packit Service |
af52df |
div = op2 / (uint64_t) ULONG_MAX;
|
|
Packit Service |
af52df |
mod = op2 % (uint64_t) ULONG_MAX;
|
|
Packit Service |
af52df |
for (i=0; i < div; i++) {
|
|
Packit Service |
af52df |
mpz_mul_ui (aux, op1, (unsigned long int) ULONG_MAX);
|
|
Packit Service |
af52df |
mpz_add (res, res, aux);
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
mpz_mul_ui (aux, op1, (unsigned long int) mod);
|
|
Packit Service |
af52df |
mpz_add (res, res, aux);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpz_set (rop, res);
|
|
Packit Service |
af52df |
mpz_clear (aux);
|
|
Packit Service |
af52df |
mpz_clear (res);
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/***************
|
|
Packit Service |
af52df |
* DESTRUCTORS *
|
|
Packit Service |
af52df |
* *************/
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_free:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Clears @size and frees the allocated resources.
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
void bs_size_free (BSSize size) {
|
|
Packit Service |
af52df |
if (size) {
|
|
Packit Service |
af52df |
mpz_clear (size->bytes);
|
|
Packit Service |
af52df |
free (size);
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
return;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_clear_error:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Clears @error and frees the allocated resources.
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
void bs_clear_error (BSError **error) {
|
|
Packit Service |
af52df |
if (error && *error) {
|
|
Packit Service |
af52df |
free ((*error)->msg);
|
|
Packit Service |
af52df |
free (*error);
|
|
Packit Service |
af52df |
*error = NULL;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
return;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/****************
|
|
Packit Service |
af52df |
* CONSTRUCTORS *
|
|
Packit Service |
af52df |
****************/
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_new: (constructor)
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Creates a new #BSSize instance initialized to 0.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: a new #BSSize initialized to 0.
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_new (void) {
|
|
Packit Service |
af52df |
BSSize ret = (BSSize) malloc (sizeof(struct _BSSize));
|
|
Packit Service |
af52df |
bs_size_init (ret);
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_new_from_bytes: (constructor)
|
|
Packit Service |
af52df |
* @bytes: number of bytes
|
|
Packit Service |
af52df |
* @sgn: sign of the size -- if being -1, the size is initialized to
|
|
Packit Service |
af52df |
* -@bytes, other values are ignored
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Creates a new #BSSize instance.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: a new #BSSize
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_new_from_bytes (uint64_t bytes, int sgn) {
|
|
Packit Service |
af52df |
char *num_str = NULL;
|
|
Packit Service |
af52df |
BSSize ret = bs_size_new ();
|
|
Packit Service |
af52df |
int ok = 0;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
ok = asprintf (&num_str, "%"PRIu64, bytes);
|
|
Packit Service |
af52df |
if (ok == -1)
|
|
Packit Service |
af52df |
/* probably cannot allocate memory, there's nothing more we can do */
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
mpz_set_str (ret->bytes, num_str, 10);
|
|
Packit Service |
af52df |
free (num_str);
|
|
Packit Service |
af52df |
if (sgn == -1)
|
|
Packit Service |
af52df |
mpz_neg (ret->bytes, ret->bytes);
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_new_from_str: (constructor)
|
|
Packit Service |
af52df |
* @size_str: string representing the size as a number and an optional unit
|
|
Packit Service |
af52df |
* (e.g. "1 GiB")
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Creates a new #BSSize instance.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: a new #BSSize
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_new_from_str (const char *size_str, BSError **error) {
|
|
Packit Service |
af52df |
char const * const pattern = "^\\s* # white space \n" \
|
|
Packit Service |
af52df |
"(?P<numeric> # the numeric part consists of three parts, below \n" \
|
|
Packit Service |
af52df |
" (-|\\+)? # optional sign character \n" \
|
|
Packit Service |
af52df |
" (?P<base>([0-9\\.%s]+)) # base \n" \
|
|
Packit Service |
af52df |
" (?P<exp>(e|E)(-|\\+)[0-9]+)?) # exponent \n" \
|
|
Packit Service |
af52df |
"\\s* # white space \n" \
|
|
Packit Service |
af52df |
"(?P<rest>[^\\s]*)\\s*$ # unit specification";
|
|
Packit Service |
af52df |
char *real_pattern = NULL;
|
|
Packit Service |
af52df |
pcre *regex = NULL;
|
|
Packit Service |
af52df |
const char *error_msg = NULL;
|
|
Packit Service |
af52df |
int erroffset;
|
|
Packit Service |
af52df |
int str_len = 0;
|
|
Packit Service |
af52df |
int ovector[30]; /* should be a multiple of 3 */
|
|
Packit Service |
af52df |
int str_count = 0;
|
|
Packit Service |
af52df |
char *num_str = NULL;
|
|
Packit Service |
af52df |
const char *radix_char = NULL;
|
|
Packit Service |
af52df |
char *loc_size_str = NULL;
|
|
Packit Service |
af52df |
mpf_t parsed_size;
|
|
Packit Service |
af52df |
mpfr_t size;
|
|
Packit Service |
af52df |
int status = 0;
|
|
Packit Service |
af52df |
char *unit_str = NULL;
|
|
Packit Service |
af52df |
BSSize ret = NULL;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
radix_char = nl_langinfo (RADIXCHAR);
|
|
Packit Service |
af52df |
if (strncmp (radix_char, ".", 1) != 0)
|
|
Packit Service |
af52df |
real_pattern = strdup_printf (pattern, radix_char);
|
|
Packit Service |
af52df |
else
|
|
Packit Service |
af52df |
real_pattern = strdup_printf (pattern, "");
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
regex = pcre_compile (real_pattern, PCRE_EXTENDED, &error_msg, &erroffset, NULL);
|
|
Packit Service |
af52df |
free (real_pattern);
|
|
Packit Service |
af52df |
if (!regex) {
|
|
Packit Service |
af52df |
/* TODO: populate error */
|
|
Packit Service |
af52df |
return NULL;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
loc_size_str = replace_char_with_str (size_str, '.', radix_char);
|
|
Packit Service |
af52df |
str_len = strlen (loc_size_str);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
str_count = pcre_exec (regex, NULL, loc_size_str, str_len,
|
|
Packit Service |
af52df |
0, 0, ovector, 30);
|
|
Packit Service |
af52df |
if (str_count < 0) {
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_INVALID_SPEC, strdup_printf ("Failed to parse size spec: %s", size_str));
|
|
Packit Service |
af52df |
pcre_free (regex);
|
|
Packit Service |
af52df |
free (loc_size_str);
|
|
Packit Service |
af52df |
return NULL;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
status = pcre_get_named_substring (regex, loc_size_str, ovector, str_count, "numeric", (const char **)&num_str);
|
|
Packit Service |
af52df |
if (status < 0) {
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_INVALID_SPEC, strdup_printf ("Failed to parse size spec: %s", size_str));
|
|
Packit Service |
af52df |
pcre_free (regex);
|
|
Packit Service |
af52df |
free (loc_size_str);
|
|
Packit Service |
af52df |
return NULL;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/* parse the number using GMP because it knows how to handle localization
|
|
Packit Service |
af52df |
much better than MPFR */
|
|
Packit Service |
af52df |
mpf_init2 (parsed_size, BS_FLOAT_PREC_BITS);
|
|
Packit Service |
af52df |
status = mpf_set_str (parsed_size, *num_str == '+' ? num_str+1 : num_str, 10);
|
|
Packit Service |
af52df |
free (num_str);
|
|
Packit Service |
af52df |
if (status != 0) {
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_INVALID_SPEC, strdup_printf ("Failed to parse size spec: %s", size_str));
|
|
Packit Service |
af52df |
pcre_free (regex);
|
|
Packit Service |
af52df |
free (loc_size_str);
|
|
Packit Service |
af52df |
mpf_clear (parsed_size);
|
|
Packit Service |
af52df |
return NULL;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
/* but use MPFR from now on because GMP thinks 0.1*1000 = 99 */
|
|
Packit Service |
af52df |
mpfr_init2 (size, BS_FLOAT_PREC_BITS);
|
|
Packit Service |
af52df |
mpfr_set_f (size, parsed_size, MPFR_RNDN);
|
|
Packit Service |
af52df |
mpf_clear (parsed_size);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
status = pcre_get_named_substring (regex, loc_size_str, ovector, str_count, "rest", (const char **)&unit_str);
|
|
Packit Service |
af52df |
if ((status >= 0) && strncmp (unit_str, "", 1) != 0) {
|
|
Packit Service |
af52df |
strstrip (unit_str);
|
|
Packit Service |
af52df |
if (!multiply_size_by_unit (size, unit_str)) {
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_INVALID_SPEC, strdup_printf ("Failed to recognize unit from the spec: %s", size_str));
|
|
Packit Service |
af52df |
free (unit_str);
|
|
Packit Service |
af52df |
pcre_free (regex);
|
|
Packit Service |
af52df |
free (loc_size_str);
|
|
Packit Service |
af52df |
mpfr_clear (size);
|
|
Packit Service |
af52df |
return NULL;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
free (unit_str);
|
|
Packit Service |
af52df |
pcre_free (regex);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
ret = bs_size_new ();
|
|
Packit Service |
af52df |
mpfr_get_z (ret->bytes, size, MPFR_RNDZ);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
free (loc_size_str);
|
|
Packit Service |
af52df |
mpfr_clear (size);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_new_from_size: (constructor)
|
|
Packit Service |
af52df |
* @size: the size to create a new instance from (a copy of)
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Creates a new instance of #BSSize.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer full): a new #BSSize instance which is copy of @size.
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_new_from_size (const BSSize size) {
|
|
Packit Service |
af52df |
BSSize ret = NULL;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
ret = bs_size_new ();
|
|
Packit Service |
af52df |
mpz_set (ret->bytes, size->bytes);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/*****************
|
|
Packit Service |
af52df |
* QUERY METHODS *
|
|
Packit Service |
af52df |
*****************/
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_get_bytes:
|
|
Packit Service |
af52df |
* @sgn: (allow-none) (out): sign of the @size - -1, 0 or 1 for negative, zero or positive
|
|
Packit Service |
af52df |
* size respectively
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Get the number of bytes of the @size.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: the @size in a number of bytes
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
uint64_t bs_size_get_bytes (const BSSize size, int *sgn, BSError **error) {
|
|
Packit Service |
af52df |
char *num_str = NULL;
|
|
Packit Service |
af52df |
mpz_t max;
|
|
Packit Service |
af52df |
uint64_t ret = 0;
|
|
Packit Service |
af52df |
int ok = 0;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpz_init2 (max, (mp_bitcnt_t) 64);
|
|
Packit Service |
af52df |
ok = asprintf (&num_str, "%"PRIu64, UINT64_MAX);
|
|
Packit Service |
af52df |
if (ok == -1) {
|
|
Packit Service |
af52df |
/* we probably cannot allocate memory so we are doomed */
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_FAIL, strdup("Failed to allocate memory"));
|
|
Packit Service |
af52df |
mpz_clear (max);
|
|
Packit Service |
af52df |
return 0;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
mpz_set_str (max, num_str, 10);
|
|
Packit Service |
af52df |
free (num_str);
|
|
Packit Service |
af52df |
if (mpz_cmp (size->bytes, max) > 0) {
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_OVER, strdup("The size is too big, cannot be returned as a 64bit number of bytes"));
|
|
Packit Service |
af52df |
return 0;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
mpz_clear (max);
|
|
Packit Service |
af52df |
if (sgn)
|
|
Packit Service |
af52df |
*sgn = mpz_sgn (size->bytes);
|
|
Packit Service |
af52df |
if (mpz_cmp_ui (size->bytes, UINT64_MAX) <= 0)
|
|
Packit Service |
af52df |
return (uint64_t) mpz_get_ui (size->bytes);
|
|
Packit Service |
af52df |
else {
|
|
Packit Service |
af52df |
num_str = bs_size_get_bytes_str (size);
|
|
Packit Service |
af52df |
ret = strtoull (num_str, NULL, 10);
|
|
Packit Service |
af52df |
free (num_str);
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_sgn:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Get the sign of the size.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: -1, 0 or 1 if @size is negative, zero or positive, respectively
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
int bs_size_sgn (const BSSize size) {
|
|
Packit Service |
af52df |
return mpz_sgn (size->bytes);
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_get_bytes_str:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Get the number of bytes in @size as a string. This way, the caller doesn't
|
|
Packit Service |
af52df |
* have to care about the limitations of some particular integer type.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer full): the string representing the @size as a number of bytes.
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
char* bs_size_get_bytes_str (const BSSize size) {
|
|
Packit Service |
af52df |
return mpz_get_str (NULL, 10, size->bytes);
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_convert_to:
|
|
Packit Service |
af52df |
* @unit: the unit to convert @size to
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Get the @size converted to @unit as a string representing a floating-point
|
|
Packit Service |
af52df |
* number.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer full): a string representing the floating-point number
|
|
Packit Service |
af52df |
* that equals to @size converted to @unit
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
char* bs_size_convert_to (const BSSize size, BSUnit unit, BSError **error) {
|
|
Packit Service |
af52df |
BSBunit b_unit = BS_BUNIT_B;
|
|
Packit Service |
af52df |
BSDunit d_unit = BS_DUNIT_B;
|
|
Packit Service |
af52df |
mpf_t divisor;
|
|
Packit Service |
af52df |
mpf_t result;
|
|
Packit Service |
af52df |
bool found_match = false;
|
|
Packit Service |
af52df |
char *ret = NULL;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpf_init2 (divisor, BS_FLOAT_PREC_BITS);
|
|
Packit Service |
af52df |
for (b_unit = BS_BUNIT_B; !found_match && b_unit != BS_BUNIT_UNDEF; b_unit++) {
|
|
Packit Service |
af52df |
if (unit.bunit == b_unit) {
|
|
Packit Service |
af52df |
found_match = true;
|
|
Packit Service |
af52df |
mpf_set_ui (divisor, 1);
|
|
Packit Service |
af52df |
mpf_mul_2exp (divisor, divisor, 10 * (b_unit - BS_BUNIT_B));
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
for (d_unit = BS_DUNIT_B; !found_match && d_unit != BS_DUNIT_UNDEF; d_unit++) {
|
|
Packit Service |
af52df |
if (unit.dunit == d_unit) {
|
|
Packit Service |
af52df |
found_match = true;
|
|
Packit Service |
af52df |
mpf_set_ui (divisor, 1000);
|
|
Packit Service |
af52df |
mpf_pow_ui (divisor, divisor, (d_unit - BS_DUNIT_B));
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
if (!found_match) {
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_INVALID_SPEC, "Invalid unit spec given");
|
|
Packit Service |
af52df |
mpf_clear (divisor);
|
|
Packit Service |
af52df |
return NULL;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpf_init2 (result, BS_FLOAT_PREC_BITS);
|
|
Packit Service |
af52df |
mpf_set_z (result, size->bytes);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpf_div (result, result, divisor);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
gmp_asprintf (&ret, "%.*Fg", BS_FLOAT_PREC_BITS/3, result);
|
|
Packit Service |
af52df |
mpf_clears (divisor, result, NULL);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_human_readable:
|
|
Packit Service |
af52df |
* @min_unit: the smallest unit the returned representation should use
|
|
Packit Service |
af52df |
* @max_places: maximum number of decimal places the representation should use
|
|
Packit Service |
af52df |
* @xlate: whether to try to translate the representation or not
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Get a human-readable representation of @size.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer full): a string which is human-readable representation of
|
|
Packit Service |
af52df |
* @size according to the restrictions given by the
|
|
Packit Service |
af52df |
* other parameters
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
char* bs_size_human_readable (const BSSize size, BSBunit min_unit, int max_places, bool xlate) {
|
|
Packit Service |
af52df |
mpf_t cur_val;
|
|
Packit Service |
af52df |
char *num_str = NULL;
|
|
Packit Service |
af52df |
char *ret = NULL;
|
|
Packit Service |
af52df |
int len = 0;
|
|
Packit Service |
af52df |
char *zero = NULL;
|
|
Packit Service |
af52df |
char *radix_char = NULL;
|
|
Packit Service |
af52df |
int sign = 0;
|
|
Packit Service |
af52df |
char *loc_num_str = NULL;
|
|
Packit Service |
af52df |
bool at_radix = false;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpf_init2 (cur_val, BS_FLOAT_PREC_BITS);
|
|
Packit Service |
af52df |
mpf_set_z (cur_val, size->bytes);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
if (min_unit == BS_BUNIT_UNDEF)
|
|
Packit Service |
af52df |
min_unit = BS_BUNIT_B;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
sign = mpf_sgn (cur_val);
|
|
Packit Service |
af52df |
mpf_abs (cur_val, cur_val);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpf_div_2exp (cur_val, cur_val, 10 * (min_unit - BS_BUNIT_B));
|
|
Packit Service |
af52df |
while ((mpf_cmp_ui (cur_val, 1024) > 0) && min_unit != BS_BUNIT_YiB) {
|
|
Packit Service |
af52df |
mpf_div_2exp (cur_val, cur_val, 10);
|
|
Packit Service |
af52df |
min_unit++;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
if (sign == -1)
|
|
Packit Service |
af52df |
mpf_neg (cur_val, cur_val);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
len = gmp_asprintf (&num_str, "%.*Ff", max_places >= 0 ? max_places : BS_FLOAT_PREC_BITS,
|
|
Packit Service |
af52df |
cur_val);
|
|
Packit Service |
af52df |
mpf_clear (cur_val);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/* should use the proper radix char according to @xlate */
|
|
Packit Service |
af52df |
radix_char = nl_langinfo (RADIXCHAR);
|
|
Packit Service |
af52df |
if (!xlate) {
|
|
Packit Service |
af52df |
loc_num_str = replace_str_with_str (num_str, radix_char, ".");
|
|
Packit Service |
af52df |
free (num_str);
|
|
Packit Service |
af52df |
radix_char = ".";
|
|
Packit Service |
af52df |
} else
|
|
Packit Service |
af52df |
loc_num_str = num_str;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/* remove trailing zeros and the radix char */
|
|
Packit Service |
af52df |
/* if max_places == 0, there can't be anything trailing */
|
|
Packit Service |
af52df |
if (max_places != 0) {
|
|
Packit Service |
af52df |
zero = loc_num_str + (len - 1);
|
|
Packit Service |
af52df |
while ((zero != loc_num_str) && ((*zero == '0') || (*zero == *radix_char)) && !at_radix) {
|
|
Packit Service |
af52df |
at_radix = *zero == *radix_char;
|
|
Packit Service |
af52df |
zero--;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
zero[1] = '\0';
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
ret = strdup_printf ("%s %s", loc_num_str, xlate ? _(b_units[min_unit - BS_BUNIT_B]) : b_units[min_unit - BS_BUNIT_B]);
|
|
Packit Service |
af52df |
free (loc_num_str);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/***************
|
|
Packit Service |
af52df |
* ARITHMETIC *
|
|
Packit Service |
af52df |
***************/
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_add:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Add two sizes.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer full): a new instance of #BSSize which is a sum of @size1 and @size2
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_add (const BSSize size1, const BSSize size2) {
|
|
Packit Service |
af52df |
BSSize ret = bs_size_new ();
|
|
Packit Service |
af52df |
mpz_add (ret->bytes, size1->bytes, size2->bytes);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_grow:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Grows @size1 by @size2. IOW, adds @size2 to @size1 in-place (modifying
|
|
Packit Service |
af52df |
* @size1).
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Basically an in-place variant of bs_size_add().
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer none): @size1 modified by adding @size2 to it
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_grow (BSSize size1, const BSSize size2) {
|
|
Packit Service |
af52df |
mpz_add (size1->bytes, size1->bytes, size2->bytes);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return size1;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_add_bytes:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Add @bytes to the @size. To add a negative number of bytes use
|
|
Packit Service |
af52df |
* bs_size_sub_bytes().
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer full): a new instance of #BSSize which is a sum of @size and @bytes
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_add_bytes (const BSSize size, uint64_t bytes) {
|
|
Packit Service |
af52df |
BSSize ret = bs_size_new ();
|
|
Packit Service |
af52df |
do_64bit_add_sub (mpz_add_ui, ret->bytes, size->bytes, bytes);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_grow_bytes:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Grows @size by @bytes. IOW, adds @bytes to @size in-place (modifying @size).
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Basically an in-place variant of bs_size_add_bytes().
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer none): @size modified by adding @bytes to it
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_grow_bytes (BSSize size, const uint64_t bytes) {
|
|
Packit Service |
af52df |
do_64bit_add_sub (mpz_add_ui, size->bytes, size->bytes, bytes);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return size;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_sub:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Subtract @size2 from @size1.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer full): a new instance of #BSSize which is equals to @size1 - @size2
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_sub (const BSSize size1, const BSSize size2) {
|
|
Packit Service |
af52df |
BSSize ret = bs_size_new ();
|
|
Packit Service |
af52df |
mpz_sub (ret->bytes, size1->bytes, size2->bytes);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_shrink:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Shrinks @size1 by @size2. IOW, subtracts @size2 from @size1 in-place
|
|
Packit Service |
af52df |
* (modifying @size1).
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Basically an in-place variant of bs_size_sub().
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer none): @size1 modified by subtracting @size2 from it
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_shrink (BSSize size1, const BSSize size2) {
|
|
Packit Service |
af52df |
mpz_sub (size1->bytes, size1->bytes, size2->bytes);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return size1;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_sub_bytes:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Subtract @bytes from the @size. To subtract a negative number of bytes use
|
|
Packit Service |
af52df |
* bs_size_add_bytes().
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer full): a new instance of #BSSize which equals to @size - @bytes
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_sub_bytes (const BSSize size, uint64_t bytes) {
|
|
Packit Service |
af52df |
BSSize ret = bs_size_new ();
|
|
Packit Service |
af52df |
do_64bit_add_sub (mpz_sub_ui, ret->bytes, size->bytes, bytes);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_shrink_bytes:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Shrinks @size by @bytes. IOW, subtracts @bytes from @size in-place
|
|
Packit Service |
af52df |
* (modifying @size). To shrink by a negative number of bytes use
|
|
Packit Service |
af52df |
* bs_size_grow_bytes().
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Basically an in-place variant of bs_size_sub_bytes().
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer none): @size modified by subtracting @bytes from it
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_shrink_bytes (BSSize size, uint64_t bytes) {
|
|
Packit Service |
af52df |
do_64bit_add_sub (mpz_sub_ui, size->bytes, size->bytes, bytes);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return size;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_mul_int:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Multiply @size by @times.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer full): a new instance of #BSSize which equals to @size * @times
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_mul_int (const BSSize size, uint64_t times) {
|
|
Packit Service |
af52df |
BSSize ret = bs_size_new ();
|
|
Packit Service |
af52df |
mul_64bit (ret->bytes, size->bytes, times);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_grow_mul_int:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Grow @size @times times. IOW, multiply @size by @times in-place.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Basically an in-place variant of bs_size_mul_int().
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer none): @size modified by growing it @times times
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_grow_mul_int (BSSize size, uint64_t times) {
|
|
Packit Service |
af52df |
mul_64bit (size->bytes, size->bytes, times);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return size;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_mul_float_str:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Multiply @size by the floating-point number @float_str represents.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer full): a new #BSSize instance which equals to
|
|
Packit Service |
af52df |
* @size * @times_str
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_mul_float_str (const BSSize size, const char *float_str, BSError **error) {
|
|
Packit Service |
af52df |
mpf_t op1, op2;
|
|
Packit Service |
af52df |
int status = 0;
|
|
Packit Service |
af52df |
BSSize ret = NULL;
|
|
Packit Service |
af52df |
const char *radix_char = NULL;
|
|
Packit Service |
af52df |
char *loc_float_str = NULL;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
radix_char = nl_langinfo (RADIXCHAR);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpf_init2 (op1, BS_FLOAT_PREC_BITS);
|
|
Packit Service |
af52df |
mpf_init2 (op2, BS_FLOAT_PREC_BITS);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpf_set_z (op1, size->bytes);
|
|
Packit Service |
af52df |
loc_float_str = replace_char_with_str (float_str, '.', radix_char);
|
|
Packit Service |
af52df |
status = mpf_set_str (op2, loc_float_str, 10);
|
|
Packit Service |
af52df |
if (status != 0) {
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_INVALID_SPEC, strdup_printf ("'%s' is not a valid floating point number string", loc_float_str));
|
|
Packit Service |
af52df |
free (loc_float_str);
|
|
Packit Service |
af52df |
mpf_clears (op1, op2, NULL);
|
|
Packit Service |
af52df |
return NULL;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
free (loc_float_str);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpf_mul (op1, op1, op2);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
ret = bs_size_new ();
|
|
Packit Service |
af52df |
mpz_set_f (ret->bytes, op1);
|
|
Packit Service |
af52df |
mpf_clears (op1, op2, NULL);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_grow_mul_float_str:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Grow @size by the floating-point number @float_str represents times. IOW,
|
|
Packit Service |
af52df |
* multiply @size by @float_str in-place.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Basically an in-place variant of bs_size_grow_mul_float_str().
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer none): @size modified by growing it @float_str times.
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_grow_mul_float_str (BSSize size, const char *float_str, BSError **error) {
|
|
Packit Service |
af52df |
mpf_t op1, op2;
|
|
Packit Service |
af52df |
int status = 0;
|
|
Packit Service |
af52df |
const char *radix_char = NULL;
|
|
Packit Service |
af52df |
char *loc_float_str = NULL;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
radix_char = nl_langinfo (RADIXCHAR);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpf_init2 (op1, BS_FLOAT_PREC_BITS);
|
|
Packit Service |
af52df |
mpf_init2 (op2, BS_FLOAT_PREC_BITS);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpf_set_z (op1, size->bytes);
|
|
Packit Service |
af52df |
loc_float_str = replace_char_with_str (float_str, '.', radix_char);
|
|
Packit Service |
af52df |
status = mpf_set_str (op2, loc_float_str, 10);
|
|
Packit Service |
af52df |
if (status != 0) {
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_INVALID_SPEC, strdup_printf ("'%s' is not a valid floating point number string", loc_float_str));
|
|
Packit Service |
af52df |
free (loc_float_str);
|
|
Packit Service |
af52df |
mpf_clears (op1, op2, NULL);
|
|
Packit Service |
af52df |
return NULL;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
free (loc_float_str);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpf_mul (op1, op1, op2);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpz_set_f (size->bytes, op1);
|
|
Packit Service |
af52df |
mpf_clears (op1, op2, NULL);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return size;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_div:
|
|
Packit Service |
af52df |
* @sgn: (allow-none) (out): sign of the result
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Divide @size1 by @size2. Gives the answer to the question "How many times
|
|
Packit Service |
af52df |
* does @size2 fit in @size1?".
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: integer number x so that x * @size1 < @size2 and (x+1) * @size1 > @size2
|
|
Packit Service |
af52df |
* (IOW, @size1 / @size2 using integer division)
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
uint64_t bs_size_div (const BSSize size1, const BSSize size2, int *sgn, BSError **error) {
|
|
Packit Service |
af52df |
mpz_t result;
|
|
Packit Service |
af52df |
uint64_t ret = 0;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
if (mpz_cmp_ui (size2->bytes, 0) == 0) {
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_ZERO_DIV, strdup_printf ("Division by zero"));
|
|
Packit Service |
af52df |
return 0;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
if (sgn)
|
|
Packit Service |
af52df |
*sgn = mpz_sgn (size1->bytes) * mpz_sgn (size2->bytes);
|
|
Packit Service |
af52df |
mpz_init (result);
|
|
Packit Service |
af52df |
mpz_tdiv_q (result, size1->bytes, size2->bytes);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
if (mpz_cmp_ui (result, UINT64_MAX) > 0) {
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_OVER, strdup_printf ("The size is too big, cannot be returned as a 64bit number"));
|
|
Packit Service |
af52df |
mpz_clear (result);
|
|
Packit Service |
af52df |
return 0;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
ret = (uint64_t) mpz_get_ui (result);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpz_clear (result);
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_div_int:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Divide @size by @divisor. Gives the answer to the question "What is the size
|
|
Packit Service |
af52df |
* of each chunk if @size is split into a @divisor number of pieces?"
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Note: Due to the limitations of the current implementation the maximum value
|
|
Packit Service |
af52df |
* @divisor is ULONG_MAX (which can differ from UINT64_MAX). An error
|
|
Packit Service |
af52df |
* (BS_ERROR_OVER) is returned if overflow happens.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer full): a #BSSize instance x so that x * @divisor = @size,
|
|
Packit Service |
af52df |
* rounded to a number of bytes
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_div_int (const BSSize size, uint64_t divisor, BSError **error) {
|
|
Packit Service |
af52df |
BSSize ret = NULL;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
if (divisor == 0) {
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_ZERO_DIV, strdup_printf ("Division by zero"));
|
|
Packit Service |
af52df |
return NULL;
|
|
Packit Service |
af52df |
} else if (divisor > ULONG_MAX) {
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_OVER, strdup_printf ("Divisor too big, must be less or equal to %lu", ULONG_MAX));
|
|
Packit Service |
af52df |
return NULL;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
ret = bs_size_new ();
|
|
Packit Service |
af52df |
mpz_tdiv_q_ui (ret->bytes, size->bytes, divisor);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_shrink_div_int:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Shrink @size by dividing by @divisor. IOW, divide @size by @divisor in-place.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Basically an in-place variant of bs_size_div_int().
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Note: Due to the limitations of the current implementation the maximum value
|
|
Packit Service |
af52df |
* @divisor is ULONG_MAX (which can differ from UINT64_MAX). An error
|
|
Packit Service |
af52df |
* (BS_ERROR_OVER) is returned if overflow happens.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer none): @size modified by division by @divisor
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_shrink_div_int (BSSize size, uint64_t divisor, BSError **error) {
|
|
Packit Service |
af52df |
if (divisor == 0) {
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_ZERO_DIV, strdup_printf ("Division by zero"));
|
|
Packit Service |
af52df |
return NULL;
|
|
Packit Service |
af52df |
} else if (divisor > ULONG_MAX) {
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_OVER, strdup_printf ("Divisor too big, must be less or equal to %lu", ULONG_MAX));
|
|
Packit Service |
af52df |
return NULL;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpz_tdiv_q_ui (size->bytes, size->bytes, divisor);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return size;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_true_div:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Divides @size1 by @size2.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer full): a string representing the floating-point number
|
|
Packit Service |
af52df |
* that equals to @size1 / @size2
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
char* bs_size_true_div (const BSSize size1, const BSSize size2, BSError **error) {
|
|
Packit Service |
af52df |
mpf_t op1;
|
|
Packit Service |
af52df |
mpf_t op2;
|
|
Packit Service |
af52df |
char *ret = NULL;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
if (mpz_cmp_ui (size2->bytes, 0) == 0) {
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_ZERO_DIV, strdup_printf("Division by zero"));
|
|
Packit Service |
af52df |
return 0;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpf_init2 (op1, BS_FLOAT_PREC_BITS);
|
|
Packit Service |
af52df |
mpf_init2 (op2, BS_FLOAT_PREC_BITS);
|
|
Packit Service |
af52df |
mpf_set_z (op1, size1->bytes);
|
|
Packit Service |
af52df |
mpf_set_z (op2, size2->bytes);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpf_div (op1, op1, op2);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
gmp_asprintf (&ret, "%.*Fg", BS_FLOAT_PREC_BITS/3, op1);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpf_clears (op1, op2, NULL);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_true_div_int:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Divides @size by @divisor.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Note: Due to the limitations of the current implementation the maximum value
|
|
Packit Service |
af52df |
* @divisor is ULONG_MAX (which can differ from UINT64_MAX). An error
|
|
Packit Service |
af52df |
* (BS_ERROR_OVER) is returned if overflow happens.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer full): a string representing the floating-point number
|
|
Packit Service |
af52df |
* that equals to @size / @divisor
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
char* bs_size_true_div_int (const BSSize size, uint64_t divisor, BSError **error) {
|
|
Packit Service |
af52df |
mpf_t op1;
|
|
Packit Service |
af52df |
char *ret = NULL;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
if (divisor == 0) {
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_ZERO_DIV, strdup_printf ("Division by zero"));
|
|
Packit Service |
af52df |
return 0;
|
|
Packit Service |
af52df |
} else if (divisor > ULONG_MAX) {
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_OVER, strdup_printf ("Divisor too big, must be less or equal to %lu", ULONG_MAX));
|
|
Packit Service |
af52df |
return NULL;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpf_init2 (op1, BS_FLOAT_PREC_BITS);
|
|
Packit Service |
af52df |
mpf_set_z (op1, size->bytes);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpf_div_ui (op1, op1, divisor);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
gmp_asprintf (&ret, "%.*Fg", BS_FLOAT_PREC_BITS/3, op1);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpf_clear (op1);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_mod:
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Gives @size1 modulo @size2 (i.e. the remainder of integer division @size1 /
|
|
Packit Service |
af52df |
* @size2). Gives the answer to the question "If I split @size1 into chunks of
|
|
Packit Service |
af52df |
* size @size2, what will be the remainder?"
|
|
Packit Service |
af52df |
* **This function ignores the signs of the sizes.**
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer full): a #BSSize instance that is a remainder of
|
|
Packit Service |
af52df |
* @size1 / @size2 using integer division
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_mod (const BSSize size1, const BSSize size2, BSError **error) {
|
|
Packit Service |
af52df |
mpz_t aux;
|
|
Packit Service |
af52df |
BSSize ret = NULL;
|
|
Packit Service |
af52df |
if (mpz_cmp_ui (size2->bytes, 0) == 0) {
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_ZERO_DIV, strdup_printf ("Division by zero"));
|
|
Packit Service |
af52df |
return 0;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpz_init (aux);
|
|
Packit Service |
af52df |
mpz_set (aux, size1->bytes);
|
|
Packit Service |
af52df |
if (mpz_sgn (size1->bytes) == -1)
|
|
Packit Service |
af52df |
/* negative @size1, get the absolute value so that we get results
|
|
Packit Service |
af52df |
matching the specification/documentation of this function */
|
|
Packit Service |
af52df |
mpz_neg (aux, aux);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
ret = bs_size_new ();
|
|
Packit Service |
af52df |
mpz_mod (ret->bytes, aux, size2->bytes);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_round_to_nearest:
|
|
Packit Service |
af52df |
* @round_to: to a multiple of what to round @size
|
|
Packit Service |
af52df |
* @dir: %BS_ROUND_DIR_UP to round up (to the nearest multiple of @round_to
|
|
Packit Service |
af52df |
* bigger than @size) or %BS_ROUND_DIR_DOWN to round down (to the
|
|
Packit Service |
af52df |
* nearest multiple of @round_to smaller than @size)
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Round @size to the nearest multiple of @round_to according to the direction
|
|
Packit Service |
af52df |
* given by @dir.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: (transfer full): a new instance of #BSSize that is @size rounded to
|
|
Packit Service |
af52df |
* a multiple of @round_to according to @dir
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
BSSize bs_size_round_to_nearest (const BSSize size, const BSSize round_to, BSRoundDir dir, BSError **error) {
|
|
Packit Service |
af52df |
BSSize ret = NULL;
|
|
Packit Service |
af52df |
mpz_t q;
|
|
Packit Service |
af52df |
mpz_t aux_size;
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
if (mpz_cmp_ui (round_to->bytes, 0) == 0) {
|
|
Packit Service |
af52df |
set_error (error, BS_ERROR_ZERO_DIV, strdup_printf ("Division by zero"));
|
|
Packit Service |
af52df |
return NULL;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpz_init (q);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
if (dir == BS_ROUND_DIR_UP) {
|
|
Packit Service |
af52df |
mpz_cdiv_q (q, size->bytes, round_to->bytes);
|
|
Packit Service |
af52df |
} else if (dir == BS_ROUND_DIR_HALF_UP) {
|
|
Packit Service |
af52df |
/* round half up == add half of what to round to and round down */
|
|
Packit Service |
af52df |
mpz_init (aux_size);
|
|
Packit Service |
af52df |
mpz_fdiv_q_ui (aux_size, round_to->bytes, 2);
|
|
Packit Service |
af52df |
mpz_add (aux_size, aux_size, size->bytes);
|
|
Packit Service |
af52df |
mpz_fdiv_q (q, aux_size, round_to->bytes);
|
|
Packit Service |
af52df |
mpz_clear (aux_size);
|
|
Packit Service |
af52df |
} else
|
|
Packit Service |
af52df |
mpz_fdiv_q (q, size->bytes, round_to->bytes);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
ret = bs_size_new ();
|
|
Packit Service |
af52df |
mpz_mul (ret->bytes, q, round_to->bytes);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
mpz_clear (q);
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/***************
|
|
Packit Service |
af52df |
* COMPARISONS *
|
|
Packit Service |
af52df |
***************/
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_cmp:
|
|
Packit Service |
af52df |
* @abs: whether to compare absolute values of @size1 and @size2 instead
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Compare @size1 and @size2. This function behaves like the standard *cmp*()
|
|
Packit Service |
af52df |
* functions.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: -1, 0, or 1 if @size1 is smaller, equal to or bigger than
|
|
Packit Service |
af52df |
* @size2 respectively comparing absolute values if @abs is %true
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
int bs_size_cmp (const BSSize size1, const BSSize size2, bool abs) {
|
|
Packit Service |
af52df |
int ret = 0;
|
|
Packit Service |
af52df |
if (abs)
|
|
Packit Service |
af52df |
ret = mpz_cmpabs (size1->bytes, size2->bytes);
|
|
Packit Service |
af52df |
else
|
|
Packit Service |
af52df |
ret = mpz_cmp (size1->bytes, size2->bytes);
|
|
Packit Service |
af52df |
/* make sure we don't return things like 2 or -2 (which GMP can give us) */
|
|
Packit Service |
af52df |
if (ret > 0)
|
|
Packit Service |
af52df |
ret = 1;
|
|
Packit Service |
af52df |
else if (ret < 0)
|
|
Packit Service |
af52df |
ret = -1;
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|
|
Packit Service |
af52df |
|
|
Packit Service |
af52df |
/**
|
|
Packit Service |
af52df |
* bs_size_cmp_bytes:
|
|
Packit Service |
af52df |
* @abs: whether to compare absolute values of @size and @bytes instead.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Compare @size and @bytes, i.e. the number of bytes @size has with
|
|
Packit Service |
af52df |
* @bytes. This function behaves like the standard *cmp*() functions.
|
|
Packit Service |
af52df |
*
|
|
Packit Service |
af52df |
* Returns: -1, 0, or 1 if @size is smaller, equal to or bigger than
|
|
Packit Service |
af52df |
* @bytes respectively comparing absolute values if @abs is %true
|
|
Packit Service |
af52df |
*/
|
|
Packit Service |
af52df |
int bs_size_cmp_bytes (const BSSize size, uint64_t bytes, bool abs) {
|
|
Packit Service |
af52df |
int ret = 0;
|
|
Packit Service |
af52df |
if (abs)
|
|
Packit Service |
af52df |
ret = mpz_cmpabs_ui (size->bytes, bytes);
|
|
Packit Service |
af52df |
else
|
|
Packit Service |
af52df |
ret = mpz_cmp_ui (size->bytes, bytes);
|
|
Packit Service |
af52df |
/* make sure we don't return things like 2 or -2 (which GMP can give us) */
|
|
Packit Service |
af52df |
if (ret > 0)
|
|
Packit Service |
af52df |
ret = 1;
|
|
Packit Service |
af52df |
else if (ret < 0)
|
|
Packit Service |
af52df |
ret = -1;
|
|
Packit Service |
af52df |
return ret;
|
|
Packit Service |
af52df |
}
|