Exemplo n.º 1
0
void
mpd_rescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, mpd_context_t *ctx)
{
	uint32_t status = 0;
	mpd_qrescale(result, a, exp, ctx, &status);
	mpd_addstatus_raise(ctx, status);
}
Exemplo n.º 2
0
/*
 * Return the string representation of an mpd_t, formatted according to 'spec'.
 * The format specification is assumed to be valid. Memory errors are indicated
 * as usual. This function is quiet.
 */
char *
mpd_qformat_spec(const mpd_t *dec, const mpd_spec_t *spec,
                 const mpd_context_t *ctx, uint32_t *status)
{
    mpd_uint_t dt[MPD_MINALLOC_MAX];
    mpd_t tmp = {MPD_STATIC|MPD_STATIC_DATA,0,0,0,MPD_MINALLOC_MAX,dt};
    mpd_ssize_t dplace = MPD_DEFAULT_DOTPLACE;
    mpd_mbstr_t result;
    mpd_spec_t stackspec;
    char type = spec->type;
    int flags = 0;


    if (spec->min_width > MPD_MAX_PREC) {
        *status |= MPD_Invalid_operation;
        return NULL;
    }

    if (isupper((uchar)type)) {
        type = tolower((uchar)type);
        flags |= MPD_FMT_UPPER;
    }
    if (spec->sign == ' ') {
        flags |= MPD_FMT_SIGN_SPACE;
    }
    else if (spec->sign == '+') {
        flags |= MPD_FMT_SIGN_PLUS;
    }

    if (mpd_isspecial(dec)) {
        if (spec->align == 'z') {
            stackspec = *spec;
            stackspec.fill[0] = ' ';
            stackspec.fill[1] = '\0';
            stackspec.align = '>';
            spec = &stackspec;
        }
    }
    else {
        uint32_t workstatus = 0;
        mpd_ssize_t prec;

        switch (type) {
        case 'g': flags |= MPD_FMT_TOSCI; break;
        case 'e': flags |= MPD_FMT_EXP; break;
        case '%': flags |= MPD_FMT_PERCENT;
                  if (!mpd_qcopy(&tmp, dec, status)) {
                      return NULL;
                  }
                  tmp.exp += 2;
                  dec = &tmp;
                  type = 'f'; /* fall through */
        case 'f': flags |= MPD_FMT_FIXED; break;
        default: abort(); /* debug: GCOV_NOT_REACHED */
        }

        if (spec->prec >= 0) {
            if (spec->prec > MPD_MAX_PREC) {
                *status |= MPD_Invalid_operation;
                goto error;
            }

            switch (type) {
            case 'g':
                prec = (spec->prec == 0) ? 1 : spec->prec;
                if (dec->digits > prec) {
                    _mpd_round(&tmp, dec, prec, ctx,
                               &workstatus);
                    dec = &tmp;
                }
                break;
            case 'e':
                if (mpd_iszero(dec)) {
                    dplace = 1-spec->prec;
                }
                else {
                    _mpd_round(&tmp, dec, spec->prec+1, ctx,
                               &workstatus);
                    dec = &tmp;
                }
                break;
            case 'f':
                mpd_qrescale(&tmp, dec, -spec->prec, ctx,
                             &workstatus);
                dec = &tmp;
                break;
            }
        }

        if (type == 'f') {
            if (mpd_iszero(dec) && dec->exp > 0) {
                mpd_qrescale(&tmp, dec, 0, ctx, &workstatus);
                dec = &tmp;
            }
        }

        if (workstatus&MPD_Errors) {
            *status |= (workstatus&MPD_Errors);
            goto error;
        }
    }

    /*
     * At this point, for all scaled or non-scaled decimals:
     *   1) 1 <= digits <= MAX_PREC+1
     *   2) adjexp(scaled) = adjexp(orig) [+1]
     *   3)   case 'g': MIN_ETINY <= exp <= MAX_EMAX+1
     *        case 'e': MIN_ETINY-MAX_PREC <= exp <= MAX_EMAX+1
     *        case 'f': MIN_ETINY <= exp <= MAX_EMAX+1
     *   4) max memory alloc in _mpd_to_string:
     *        case 'g': MAX_PREC+36
     *        case 'e': MAX_PREC+36
     *        case 'f': 2*MPD_MAX_PREC+30
     */
    result.nbytes = _mpd_to_string(&result.data, dec, flags, dplace);
    result.nchars = result.nbytes;
    if (result.nbytes < 0) {
        *status |= MPD_Malloc_error;
        goto error;
    }

    if (*spec->dot != '\0' && !mpd_isspecial(dec)) {
        if (result.nchars > MPD_MAX_PREC+36) {
            /* Since a group length of one is not explicitly
             * disallowed, ensure that it is always possible to
             * insert a four byte separator after each digit. */
            *status |= MPD_Invalid_operation;
            mpd_free(result.data);
            goto error;
        }
        if (!_mpd_apply_lconv(&result, spec, status)) {
            goto error;
        }
    }

    if (spec->min_width) {
        if (!_mpd_add_pad(&result, spec, status)) {
            goto error;
        }
    }

    mpd_del(&tmp);
    return result.data;

error:
    mpd_del(&tmp);
    return NULL;
}