1/* Decimal context module for the decNumber C Library.
2   Copyright (C) 2005 Free Software Foundation, Inc.
3   Contributed by IBM Corporation.  Author Mike Cowlishaw.
4
5   This file is part of GCC.
6
7   GCC is free software; you can redistribute it and/or modify it under
8   the terms of the GNU General Public License as published by the Free
9   Software Foundation; either version 2, or (at your option) any later
10   version.
11
12   In addition to the permissions in the GNU General Public License,
13   the Free Software Foundation gives you unlimited permission to link
14   the compiled version of this file into combinations with other
15   programs, and to distribute those combinations without any
16   restriction coming from the use of this file.  (The General Public
17   License restrictions do apply in other respects; for example, they
18   cover modification of the file, and distribution when not linked
19   into a combine executable.)
20
21   GCC is distributed in the hope that it will be useful, but WITHOUT ANY
22   WARRANTY; without even the implied warranty of MERCHANTABILITY or
23   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
24   for more details.
25
26   You should have received a copy of the GNU General Public License
27   along with GCC; see the file COPYING.  If not, write to the Free
28   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
29   02110-1301, USA.  */
30
31/*  This module compirises the routines for handling the arithmetic
32    context structures. */
33
34#include <string.h>		/* for strcmp */
35#include "config.h"
36#include "decContext.h"		/* context and base types */
37#include "decNumberLocal.h"	/* decNumber local types, etc. */
38
39/* ------------------------------------------------------------------ */
40/* decContextDefault -- initialize a context structure                */
41/*                                                                    */
42/*  context is the structure to be initialized                        */
43/*  kind selects the required set of default values, one of:          */
44/*      DEC_INIT_BASE       -- select ANSI X3-274 defaults            */
45/*      DEC_INIT_DECIMAL32  -- select IEEE 754r defaults, 32-bit      */
46/*      DEC_INIT_DECIMAL64  -- select IEEE 754r defaults, 64-bit      */
47/*      DEC_INIT_DECIMAL128 -- select IEEE 754r defaults, 128-bit     */
48/*      For any other value a valid context is returned, but with     */
49/*      Invalid_operation set in the status field.                    */
50/*  returns a context structure with the appropriate initial values.  */
51/* ------------------------------------------------------------------ */
52decContext *
53decContextDefault (decContext * context, Int kind)
54{
55  /* set defaults... */
56  context->digits = 9;		/* 9 digits */
57  context->emax = DEC_MAX_EMAX;	/* 9-digit exponents */
58  context->emin = DEC_MIN_EMIN;	/* .. balanced */
59  context->round = DEC_ROUND_HALF_UP;	/* 0.5 rises */
60  context->traps = DEC_Errors;	/* all but informational */
61  context->status = 0;		/* cleared */
62  context->clamp = 0;		/* no clamping */
63#if DECSUBSET
64  context->extended = 0;	/* cleared */
65#endif
66  switch (kind)
67    {
68    case DEC_INIT_BASE:
69      /* [use defaults] */
70      break;
71    case DEC_INIT_DECIMAL32:
72      context->digits = 7;	/* digits */
73      context->emax = 96;	/* Emax */
74      context->emin = -95;	/* Emin */
75      context->round = DEC_ROUND_HALF_EVEN;	/* 0.5 to nearest even */
76      context->traps = 0;	/* no traps set */
77      context->clamp = 1;	/* clamp exponents */
78#if DECSUBSET
79      context->extended = 1;	/* set */
80#endif
81      break;
82    case DEC_INIT_DECIMAL64:
83      context->digits = 16;	/* digits */
84      context->emax = 384;	/* Emax */
85      context->emin = -383;	/* Emin */
86      context->round = DEC_ROUND_HALF_EVEN;	/* 0.5 to nearest even */
87      context->traps = 0;	/* no traps set */
88      context->clamp = 1;	/* clamp exponents */
89#if DECSUBSET
90      context->extended = 1;	/* set */
91#endif
92      break;
93    case DEC_INIT_DECIMAL128:
94      context->digits = 34;	/* digits */
95      context->emax = 6144;	/* Emax */
96      context->emin = -6143;	/* Emin */
97      context->round = DEC_ROUND_HALF_EVEN;	/* 0.5 to nearest even */
98      context->traps = 0;	/* no traps set */
99      context->clamp = 1;	/* clamp exponents */
100#if DECSUBSET
101      context->extended = 1;	/* set */
102#endif
103      break;
104
105    default:			/* invalid Kind */
106      /* use defaults, and .. */
107      decContextSetStatus (context, DEC_Invalid_operation);	/* trap */
108    }
109  return context;
110}				/* decContextDefault */
111
112/* ------------------------------------------------------------------ */
113/* decContextStatusToString -- convert status flags to a string       */
114/*                                                                    */
115/*  context is a context with valid status field                      */
116/*                                                                    */
117/*  returns a constant string describing the condition.  If multiple  */
118/*    (or no) flags are set, a generic constant message is returned.  */
119/* ------------------------------------------------------------------ */
120const char *
121decContextStatusToString (const decContext * context)
122{
123  Int status = context->status;
124  if (status == DEC_Conversion_syntax)
125    return DEC_Condition_CS;
126  if (status == DEC_Division_by_zero)
127    return DEC_Condition_DZ;
128  if (status == DEC_Division_impossible)
129    return DEC_Condition_DI;
130  if (status == DEC_Division_undefined)
131    return DEC_Condition_DU;
132  if (status == DEC_Inexact)
133    return DEC_Condition_IE;
134  if (status == DEC_Insufficient_storage)
135    return DEC_Condition_IS;
136  if (status == DEC_Invalid_context)
137    return DEC_Condition_IC;
138  if (status == DEC_Invalid_operation)
139    return DEC_Condition_IO;
140#if DECSUBSET
141  if (status == DEC_Lost_digits)
142    return DEC_Condition_LD;
143#endif
144  if (status == DEC_Overflow)
145    return DEC_Condition_OV;
146  if (status == DEC_Clamped)
147    return DEC_Condition_PA;
148  if (status == DEC_Rounded)
149    return DEC_Condition_RO;
150  if (status == DEC_Subnormal)
151    return DEC_Condition_SU;
152  if (status == DEC_Underflow)
153    return DEC_Condition_UN;
154  if (status == 0)
155    return DEC_Condition_ZE;
156  return DEC_Condition_MU;	/* Multiple errors */
157}				/* decContextStatusToString */
158
159/* ------------------------------------------------------------------ */
160/* decContextSetStatusFromString -- set status from a string          */
161/*                                                                    */
162/*  context is the controlling context                                */
163/*  string is a string exactly equal to one that might be returned    */
164/*            by decContextStatusToString                             */
165/*                                                                    */
166/*  The status bit corresponding to the string is set, and a trap     */
167/*  is raised if appropriate.                                         */
168/*                                                                    */
169/*  returns the context structure, unless the string is equal to      */
170/*    DEC_Condition_MU or is not recognized.  In these cases NULL is  */
171/*    returned.                                                       */
172/* ------------------------------------------------------------------ */
173decContext *
174decContextSetStatusFromString (decContext * context, const char *string)
175{
176  if (strcmp (string, DEC_Condition_CS) == 0)
177    return decContextSetStatus (context, DEC_Conversion_syntax);
178  if (strcmp (string, DEC_Condition_DZ) == 0)
179    return decContextSetStatus (context, DEC_Division_by_zero);
180  if (strcmp (string, DEC_Condition_DI) == 0)
181    return decContextSetStatus (context, DEC_Division_impossible);
182  if (strcmp (string, DEC_Condition_DU) == 0)
183    return decContextSetStatus (context, DEC_Division_undefined);
184  if (strcmp (string, DEC_Condition_IE) == 0)
185    return decContextSetStatus (context, DEC_Inexact);
186  if (strcmp (string, DEC_Condition_IS) == 0)
187    return decContextSetStatus (context, DEC_Insufficient_storage);
188  if (strcmp (string, DEC_Condition_IC) == 0)
189    return decContextSetStatus (context, DEC_Invalid_context);
190  if (strcmp (string, DEC_Condition_IO) == 0)
191    return decContextSetStatus (context, DEC_Invalid_operation);
192#if DECSUBSET
193  if (strcmp (string, DEC_Condition_LD) == 0)
194    return decContextSetStatus (context, DEC_Lost_digits);
195#endif
196  if (strcmp (string, DEC_Condition_OV) == 0)
197    return decContextSetStatus (context, DEC_Overflow);
198  if (strcmp (string, DEC_Condition_PA) == 0)
199    return decContextSetStatus (context, DEC_Clamped);
200  if (strcmp (string, DEC_Condition_RO) == 0)
201    return decContextSetStatus (context, DEC_Rounded);
202  if (strcmp (string, DEC_Condition_SU) == 0)
203    return decContextSetStatus (context, DEC_Subnormal);
204  if (strcmp (string, DEC_Condition_UN) == 0)
205    return decContextSetStatus (context, DEC_Underflow);
206  if (strcmp (string, DEC_Condition_ZE) == 0)
207    return context;
208  return NULL;			/* Multiple status, or unknown */
209}				/* decContextSetStatusFromString */
210
211/* ------------------------------------------------------------------ */
212/* decContextSetStatus -- set status and raise trap if appropriate    */
213/*                                                                    */
214/*  context is the controlling context                                */
215/*  status  is the DEC_ exception code                                */
216/*  returns the context structure                                     */
217/*                                                                    */
218/* Control may never return from this routine, if there is a signal   */
219/* handler and it takes a long jump.                                  */
220/* ------------------------------------------------------------------ */
221decContext *
222decContextSetStatus (decContext * context, uInt status)
223{
224  context->status |= status;
225  if (status & context->traps)
226    raise (SIGFPE);
227  return context;
228}				/* decContextSetStatus */
229