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