17db96d56Sopenharmony_ci/*
27db96d56Sopenharmony_ci * Copyright (c) 2008-2020 Stefan Krah. All rights reserved.
37db96d56Sopenharmony_ci *
47db96d56Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
57db96d56Sopenharmony_ci * modification, are permitted provided that the following conditions
67db96d56Sopenharmony_ci * are met:
77db96d56Sopenharmony_ci *
87db96d56Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
97db96d56Sopenharmony_ci *    notice, this list of conditions and the following disclaimer.
107db96d56Sopenharmony_ci *
117db96d56Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
127db96d56Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
137db96d56Sopenharmony_ci *    documentation and/or other materials provided with the distribution.
147db96d56Sopenharmony_ci *
157db96d56Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
167db96d56Sopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
177db96d56Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
187db96d56Sopenharmony_ci * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
197db96d56Sopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
207db96d56Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
217db96d56Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
227db96d56Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
237db96d56Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
247db96d56Sopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
257db96d56Sopenharmony_ci * SUCH DAMAGE.
267db96d56Sopenharmony_ci */
277db96d56Sopenharmony_ci
287db96d56Sopenharmony_ci
297db96d56Sopenharmony_ci#include "mpdecimal.h"
307db96d56Sopenharmony_ci
317db96d56Sopenharmony_ci#include <signal.h>
327db96d56Sopenharmony_ci#include <stdio.h>
337db96d56Sopenharmony_ci#include <string.h>
347db96d56Sopenharmony_ci
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_civoid
377db96d56Sopenharmony_cimpd_dflt_traphandler(mpd_context_t *ctx)
387db96d56Sopenharmony_ci{
397db96d56Sopenharmony_ci    (void)ctx;
407db96d56Sopenharmony_ci    raise(SIGFPE);
417db96d56Sopenharmony_ci}
427db96d56Sopenharmony_ci
437db96d56Sopenharmony_civoid (* mpd_traphandler)(mpd_context_t *) = mpd_dflt_traphandler;
447db96d56Sopenharmony_ci
457db96d56Sopenharmony_ci
467db96d56Sopenharmony_ci/* Set guaranteed minimum number of coefficient words. The function may
477db96d56Sopenharmony_ci   be used once at program start. Setting MPD_MINALLOC to out-of-bounds
487db96d56Sopenharmony_ci   values is a catastrophic error, so in that case the function exits rather
497db96d56Sopenharmony_ci   than relying on the user to check a return value. */
507db96d56Sopenharmony_civoid
517db96d56Sopenharmony_cimpd_setminalloc(mpd_ssize_t n)
527db96d56Sopenharmony_ci{
537db96d56Sopenharmony_ci    static int minalloc_is_set = 0;
547db96d56Sopenharmony_ci
557db96d56Sopenharmony_ci    if (minalloc_is_set) {
567db96d56Sopenharmony_ci        mpd_err_warn("mpd_setminalloc: ignoring request to set "
577db96d56Sopenharmony_ci                     "MPD_MINALLOC a second time\n");
587db96d56Sopenharmony_ci        return;
597db96d56Sopenharmony_ci    }
607db96d56Sopenharmony_ci    if (n < MPD_MINALLOC_MIN || n > MPD_MINALLOC_MAX) {
617db96d56Sopenharmony_ci        mpd_err_fatal("illegal value for MPD_MINALLOC"); /* GCOV_NOT_REACHED */
627db96d56Sopenharmony_ci    }
637db96d56Sopenharmony_ci    MPD_MINALLOC = n;
647db96d56Sopenharmony_ci    minalloc_is_set = 1;
657db96d56Sopenharmony_ci}
667db96d56Sopenharmony_ci
677db96d56Sopenharmony_civoid
687db96d56Sopenharmony_cimpd_init(mpd_context_t *ctx, mpd_ssize_t prec)
697db96d56Sopenharmony_ci{
707db96d56Sopenharmony_ci    mpd_ssize_t ideal_minalloc;
717db96d56Sopenharmony_ci
727db96d56Sopenharmony_ci    mpd_defaultcontext(ctx);
737db96d56Sopenharmony_ci
747db96d56Sopenharmony_ci    if (!mpd_qsetprec(ctx, prec)) {
757db96d56Sopenharmony_ci        mpd_addstatus_raise(ctx, MPD_Invalid_context);
767db96d56Sopenharmony_ci        return;
777db96d56Sopenharmony_ci    }
787db96d56Sopenharmony_ci
797db96d56Sopenharmony_ci    ideal_minalloc = 2 * ((prec+MPD_RDIGITS-1) / MPD_RDIGITS);
807db96d56Sopenharmony_ci    if (ideal_minalloc < MPD_MINALLOC_MIN) ideal_minalloc = MPD_MINALLOC_MIN;
817db96d56Sopenharmony_ci    if (ideal_minalloc > MPD_MINALLOC_MAX) ideal_minalloc = MPD_MINALLOC_MAX;
827db96d56Sopenharmony_ci
837db96d56Sopenharmony_ci    mpd_setminalloc(ideal_minalloc);
847db96d56Sopenharmony_ci}
857db96d56Sopenharmony_ci
867db96d56Sopenharmony_civoid
877db96d56Sopenharmony_cimpd_maxcontext(mpd_context_t *ctx)
887db96d56Sopenharmony_ci{
897db96d56Sopenharmony_ci    ctx->prec=MPD_MAX_PREC;
907db96d56Sopenharmony_ci    ctx->emax=MPD_MAX_EMAX;
917db96d56Sopenharmony_ci    ctx->emin=MPD_MIN_EMIN;
927db96d56Sopenharmony_ci    ctx->round=MPD_ROUND_HALF_EVEN;
937db96d56Sopenharmony_ci    ctx->traps=MPD_Traps;
947db96d56Sopenharmony_ci    ctx->status=0;
957db96d56Sopenharmony_ci    ctx->newtrap=0;
967db96d56Sopenharmony_ci    ctx->clamp=0;
977db96d56Sopenharmony_ci    ctx->allcr=1;
987db96d56Sopenharmony_ci}
997db96d56Sopenharmony_ci
1007db96d56Sopenharmony_civoid
1017db96d56Sopenharmony_cimpd_defaultcontext(mpd_context_t *ctx)
1027db96d56Sopenharmony_ci{
1037db96d56Sopenharmony_ci    ctx->prec=2*MPD_RDIGITS;
1047db96d56Sopenharmony_ci    ctx->emax=MPD_MAX_EMAX;
1057db96d56Sopenharmony_ci    ctx->emin=MPD_MIN_EMIN;
1067db96d56Sopenharmony_ci    ctx->round=MPD_ROUND_HALF_UP;
1077db96d56Sopenharmony_ci    ctx->traps=MPD_Traps;
1087db96d56Sopenharmony_ci    ctx->status=0;
1097db96d56Sopenharmony_ci    ctx->newtrap=0;
1107db96d56Sopenharmony_ci    ctx->clamp=0;
1117db96d56Sopenharmony_ci    ctx->allcr=1;
1127db96d56Sopenharmony_ci}
1137db96d56Sopenharmony_ci
1147db96d56Sopenharmony_civoid
1157db96d56Sopenharmony_cimpd_basiccontext(mpd_context_t *ctx)
1167db96d56Sopenharmony_ci{
1177db96d56Sopenharmony_ci    ctx->prec=9;
1187db96d56Sopenharmony_ci    ctx->emax=MPD_MAX_EMAX;
1197db96d56Sopenharmony_ci    ctx->emin=MPD_MIN_EMIN;
1207db96d56Sopenharmony_ci    ctx->round=MPD_ROUND_HALF_UP;
1217db96d56Sopenharmony_ci    ctx->traps=MPD_Traps|MPD_Clamped;
1227db96d56Sopenharmony_ci    ctx->status=0;
1237db96d56Sopenharmony_ci    ctx->newtrap=0;
1247db96d56Sopenharmony_ci    ctx->clamp=0;
1257db96d56Sopenharmony_ci    ctx->allcr=1;
1267db96d56Sopenharmony_ci}
1277db96d56Sopenharmony_ci
1287db96d56Sopenharmony_ciint
1297db96d56Sopenharmony_cimpd_ieee_context(mpd_context_t *ctx, int bits)
1307db96d56Sopenharmony_ci{
1317db96d56Sopenharmony_ci    if (bits <= 0 || bits > MPD_IEEE_CONTEXT_MAX_BITS || bits % 32) {
1327db96d56Sopenharmony_ci        return -1;
1337db96d56Sopenharmony_ci    }
1347db96d56Sopenharmony_ci
1357db96d56Sopenharmony_ci    ctx->prec = 9 * (bits/32) - 2;
1367db96d56Sopenharmony_ci    ctx->emax = 3 * ((mpd_ssize_t)1<<(bits/16+3));
1377db96d56Sopenharmony_ci    ctx->emin = 1 - ctx->emax;
1387db96d56Sopenharmony_ci    ctx->round=MPD_ROUND_HALF_EVEN;
1397db96d56Sopenharmony_ci    ctx->traps=0;
1407db96d56Sopenharmony_ci    ctx->status=0;
1417db96d56Sopenharmony_ci    ctx->newtrap=0;
1427db96d56Sopenharmony_ci    ctx->clamp=1;
1437db96d56Sopenharmony_ci    ctx->allcr=1;
1447db96d56Sopenharmony_ci
1457db96d56Sopenharmony_ci    return 0;
1467db96d56Sopenharmony_ci}
1477db96d56Sopenharmony_ci
1487db96d56Sopenharmony_cimpd_ssize_t
1497db96d56Sopenharmony_cimpd_getprec(const mpd_context_t *ctx)
1507db96d56Sopenharmony_ci{
1517db96d56Sopenharmony_ci    return ctx->prec;
1527db96d56Sopenharmony_ci}
1537db96d56Sopenharmony_ci
1547db96d56Sopenharmony_cimpd_ssize_t
1557db96d56Sopenharmony_cimpd_getemax(const mpd_context_t *ctx)
1567db96d56Sopenharmony_ci{
1577db96d56Sopenharmony_ci    return ctx->emax;
1587db96d56Sopenharmony_ci}
1597db96d56Sopenharmony_ci
1607db96d56Sopenharmony_cimpd_ssize_t
1617db96d56Sopenharmony_cimpd_getemin(const mpd_context_t *ctx)
1627db96d56Sopenharmony_ci{
1637db96d56Sopenharmony_ci    return ctx->emin;
1647db96d56Sopenharmony_ci}
1657db96d56Sopenharmony_ci
1667db96d56Sopenharmony_ciint
1677db96d56Sopenharmony_cimpd_getround(const mpd_context_t *ctx)
1687db96d56Sopenharmony_ci{
1697db96d56Sopenharmony_ci    return ctx->round;
1707db96d56Sopenharmony_ci}
1717db96d56Sopenharmony_ci
1727db96d56Sopenharmony_ciuint32_t
1737db96d56Sopenharmony_cimpd_gettraps(const mpd_context_t *ctx)
1747db96d56Sopenharmony_ci{
1757db96d56Sopenharmony_ci    return ctx->traps;
1767db96d56Sopenharmony_ci}
1777db96d56Sopenharmony_ci
1787db96d56Sopenharmony_ciuint32_t
1797db96d56Sopenharmony_cimpd_getstatus(const mpd_context_t *ctx)
1807db96d56Sopenharmony_ci{
1817db96d56Sopenharmony_ci    return ctx->status;
1827db96d56Sopenharmony_ci}
1837db96d56Sopenharmony_ci
1847db96d56Sopenharmony_ciint
1857db96d56Sopenharmony_cimpd_getclamp(const mpd_context_t *ctx)
1867db96d56Sopenharmony_ci{
1877db96d56Sopenharmony_ci    return ctx->clamp;
1887db96d56Sopenharmony_ci}
1897db96d56Sopenharmony_ci
1907db96d56Sopenharmony_ciint
1917db96d56Sopenharmony_cimpd_getcr(const mpd_context_t *ctx)
1927db96d56Sopenharmony_ci{
1937db96d56Sopenharmony_ci    return ctx->allcr;
1947db96d56Sopenharmony_ci}
1957db96d56Sopenharmony_ci
1967db96d56Sopenharmony_ci
1977db96d56Sopenharmony_ciint
1987db96d56Sopenharmony_cimpd_qsetprec(mpd_context_t *ctx, mpd_ssize_t prec)
1997db96d56Sopenharmony_ci{
2007db96d56Sopenharmony_ci    if (prec <= 0 || prec > MPD_MAX_PREC) {
2017db96d56Sopenharmony_ci        return 0;
2027db96d56Sopenharmony_ci    }
2037db96d56Sopenharmony_ci    ctx->prec = prec;
2047db96d56Sopenharmony_ci    return 1;
2057db96d56Sopenharmony_ci}
2067db96d56Sopenharmony_ci
2077db96d56Sopenharmony_ciint
2087db96d56Sopenharmony_cimpd_qsetemax(mpd_context_t *ctx, mpd_ssize_t emax)
2097db96d56Sopenharmony_ci{
2107db96d56Sopenharmony_ci    if (emax < 0 || emax > MPD_MAX_EMAX) {
2117db96d56Sopenharmony_ci        return 0;
2127db96d56Sopenharmony_ci    }
2137db96d56Sopenharmony_ci    ctx->emax = emax;
2147db96d56Sopenharmony_ci    return 1;
2157db96d56Sopenharmony_ci}
2167db96d56Sopenharmony_ci
2177db96d56Sopenharmony_ciint
2187db96d56Sopenharmony_cimpd_qsetemin(mpd_context_t *ctx, mpd_ssize_t emin)
2197db96d56Sopenharmony_ci{
2207db96d56Sopenharmony_ci    if (emin > 0 || emin < MPD_MIN_EMIN) {
2217db96d56Sopenharmony_ci        return 0;
2227db96d56Sopenharmony_ci    }
2237db96d56Sopenharmony_ci    ctx->emin = emin;
2247db96d56Sopenharmony_ci    return 1;
2257db96d56Sopenharmony_ci}
2267db96d56Sopenharmony_ci
2277db96d56Sopenharmony_ciint
2287db96d56Sopenharmony_cimpd_qsetround(mpd_context_t *ctx, int round)
2297db96d56Sopenharmony_ci{
2307db96d56Sopenharmony_ci    if (!(0 <= round && round < MPD_ROUND_GUARD)) {
2317db96d56Sopenharmony_ci        return 0;
2327db96d56Sopenharmony_ci    }
2337db96d56Sopenharmony_ci    ctx->round = round;
2347db96d56Sopenharmony_ci    return 1;
2357db96d56Sopenharmony_ci}
2367db96d56Sopenharmony_ci
2377db96d56Sopenharmony_ciint
2387db96d56Sopenharmony_cimpd_qsettraps(mpd_context_t *ctx, uint32_t flags)
2397db96d56Sopenharmony_ci{
2407db96d56Sopenharmony_ci    if (flags > MPD_Max_status) {
2417db96d56Sopenharmony_ci        return 0;
2427db96d56Sopenharmony_ci    }
2437db96d56Sopenharmony_ci    ctx->traps = flags;
2447db96d56Sopenharmony_ci    return 1;
2457db96d56Sopenharmony_ci}
2467db96d56Sopenharmony_ci
2477db96d56Sopenharmony_ciint
2487db96d56Sopenharmony_cimpd_qsetstatus(mpd_context_t *ctx, uint32_t flags)
2497db96d56Sopenharmony_ci{
2507db96d56Sopenharmony_ci    if (flags > MPD_Max_status) {
2517db96d56Sopenharmony_ci        return 0;
2527db96d56Sopenharmony_ci    }
2537db96d56Sopenharmony_ci    ctx->status = flags;
2547db96d56Sopenharmony_ci    return 1;
2557db96d56Sopenharmony_ci}
2567db96d56Sopenharmony_ci
2577db96d56Sopenharmony_ciint
2587db96d56Sopenharmony_cimpd_qsetclamp(mpd_context_t *ctx, int c)
2597db96d56Sopenharmony_ci{
2607db96d56Sopenharmony_ci    if (c != 0 && c != 1) {
2617db96d56Sopenharmony_ci        return 0;
2627db96d56Sopenharmony_ci    }
2637db96d56Sopenharmony_ci    ctx->clamp = c;
2647db96d56Sopenharmony_ci    return 1;
2657db96d56Sopenharmony_ci}
2667db96d56Sopenharmony_ci
2677db96d56Sopenharmony_ciint
2687db96d56Sopenharmony_cimpd_qsetcr(mpd_context_t *ctx, int c)
2697db96d56Sopenharmony_ci{
2707db96d56Sopenharmony_ci    if (c != 0 && c != 1) {
2717db96d56Sopenharmony_ci        return 0;
2727db96d56Sopenharmony_ci    }
2737db96d56Sopenharmony_ci    ctx->allcr = c;
2747db96d56Sopenharmony_ci    return 1;
2757db96d56Sopenharmony_ci}
2767db96d56Sopenharmony_ci
2777db96d56Sopenharmony_ci
2787db96d56Sopenharmony_civoid
2797db96d56Sopenharmony_cimpd_addstatus_raise(mpd_context_t *ctx, uint32_t flags)
2807db96d56Sopenharmony_ci{
2817db96d56Sopenharmony_ci    ctx->status |= flags;
2827db96d56Sopenharmony_ci    if (flags&ctx->traps) {
2837db96d56Sopenharmony_ci        ctx->newtrap = (flags&ctx->traps);
2847db96d56Sopenharmony_ci        mpd_traphandler(ctx);
2857db96d56Sopenharmony_ci    }
2867db96d56Sopenharmony_ci}
287