1169695Skan/* Decimal context module for the decNumber C Library.
2169695Skan   Copyright (C) 2005 Free Software Foundation, Inc.
3169695Skan   Contributed by IBM Corporation.  Author Mike Cowlishaw.
4169695Skan
5169695Skan   This file is part of GCC.
6169695Skan
7169695Skan   GCC is free software; you can redistribute it and/or modify it under
8169695Skan   the terms of the GNU General Public License as published by the Free
9169695Skan   Software Foundation; either version 2, or (at your option) any later
10169695Skan   version.
11169695Skan
12169695Skan   In addition to the permissions in the GNU General Public License,
13169695Skan   the Free Software Foundation gives you unlimited permission to link
14169695Skan   the compiled version of this file into combinations with other
15169695Skan   programs, and to distribute those combinations without any
16169695Skan   restriction coming from the use of this file.  (The General Public
17169695Skan   License restrictions do apply in other respects; for example, they
18169695Skan   cover modification of the file, and distribution when not linked
19169695Skan   into a combine executable.)
20169695Skan
21169695Skan   GCC is distributed in the hope that it will be useful, but WITHOUT ANY
22169695Skan   WARRANTY; without even the implied warranty of MERCHANTABILITY or
23169695Skan   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
24169695Skan   for more details.
25169695Skan
26169695Skan   You should have received a copy of the GNU General Public License
27169695Skan   along with GCC; see the file COPYING.  If not, write to the Free
28169695Skan   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
29169695Skan   02110-1301, USA.  */
30169695Skan
31169695Skan/*  This module compirises the routines for handling the arithmetic
32169695Skan    context structures. */
33169695Skan
34169695Skan#include <string.h>		/* for strcmp */
35169695Skan#include "config.h"
36169695Skan#include "decContext.h"		/* context and base types */
37169695Skan#include "decNumberLocal.h"	/* decNumber local types, etc. */
38169695Skan
39169695Skan/* ------------------------------------------------------------------ */
40169695Skan/* decContextDefault -- initialize a context structure                */
41169695Skan/*                                                                    */
42169695Skan/*  context is the structure to be initialized                        */
43169695Skan/*  kind selects the required set of default values, one of:          */
44169695Skan/*      DEC_INIT_BASE       -- select ANSI X3-274 defaults            */
45169695Skan/*      DEC_INIT_DECIMAL32  -- select IEEE 754r defaults, 32-bit      */
46169695Skan/*      DEC_INIT_DECIMAL64  -- select IEEE 754r defaults, 64-bit      */
47169695Skan/*      DEC_INIT_DECIMAL128 -- select IEEE 754r defaults, 128-bit     */
48169695Skan/*      For any other value a valid context is returned, but with     */
49169695Skan/*      Invalid_operation set in the status field.                    */
50169695Skan/*  returns a context structure with the appropriate initial values.  */
51169695Skan/* ------------------------------------------------------------------ */
52169695SkandecContext *
53169695SkandecContextDefault (decContext * context, Int kind)
54169695Skan{
55169695Skan  /* set defaults... */
56169695Skan  context->digits = 9;		/* 9 digits */
57169695Skan  context->emax = DEC_MAX_EMAX;	/* 9-digit exponents */
58169695Skan  context->emin = DEC_MIN_EMIN;	/* .. balanced */
59169695Skan  context->round = DEC_ROUND_HALF_UP;	/* 0.5 rises */
60169695Skan  context->traps = DEC_Errors;	/* all but informational */
61169695Skan  context->status = 0;		/* cleared */
62169695Skan  context->clamp = 0;		/* no clamping */
63169695Skan#if DECSUBSET
64169695Skan  context->extended = 0;	/* cleared */
65169695Skan#endif
66169695Skan  switch (kind)
67169695Skan    {
68169695Skan    case DEC_INIT_BASE:
69169695Skan      /* [use defaults] */
70169695Skan      break;
71169695Skan    case DEC_INIT_DECIMAL32:
72169695Skan      context->digits = 7;	/* digits */
73169695Skan      context->emax = 96;	/* Emax */
74169695Skan      context->emin = -95;	/* Emin */
75169695Skan      context->round = DEC_ROUND_HALF_EVEN;	/* 0.5 to nearest even */
76169695Skan      context->traps = 0;	/* no traps set */
77169695Skan      context->clamp = 1;	/* clamp exponents */
78169695Skan#if DECSUBSET
79169695Skan      context->extended = 1;	/* set */
80169695Skan#endif
81169695Skan      break;
82169695Skan    case DEC_INIT_DECIMAL64:
83169695Skan      context->digits = 16;	/* digits */
84169695Skan      context->emax = 384;	/* Emax */
85169695Skan      context->emin = -383;	/* Emin */
86169695Skan      context->round = DEC_ROUND_HALF_EVEN;	/* 0.5 to nearest even */
87169695Skan      context->traps = 0;	/* no traps set */
88169695Skan      context->clamp = 1;	/* clamp exponents */
89169695Skan#if DECSUBSET
90169695Skan      context->extended = 1;	/* set */
91169695Skan#endif
92169695Skan      break;
93169695Skan    case DEC_INIT_DECIMAL128:
94169695Skan      context->digits = 34;	/* digits */
95169695Skan      context->emax = 6144;	/* Emax */
96169695Skan      context->emin = -6143;	/* Emin */
97169695Skan      context->round = DEC_ROUND_HALF_EVEN;	/* 0.5 to nearest even */
98169695Skan      context->traps = 0;	/* no traps set */
99169695Skan      context->clamp = 1;	/* clamp exponents */
100169695Skan#if DECSUBSET
101169695Skan      context->extended = 1;	/* set */
102169695Skan#endif
103169695Skan      break;
104169695Skan
105169695Skan    default:			/* invalid Kind */
106169695Skan      /* use defaults, and .. */
107169695Skan      decContextSetStatus (context, DEC_Invalid_operation);	/* trap */
108169695Skan    }
109169695Skan  return context;
110169695Skan}				/* decContextDefault */
111169695Skan
112169695Skan/* ------------------------------------------------------------------ */
113169695Skan/* decContextStatusToString -- convert status flags to a string       */
114169695Skan/*                                                                    */
115169695Skan/*  context is a context with valid status field                      */
116169695Skan/*                                                                    */
117169695Skan/*  returns a constant string describing the condition.  If multiple  */
118169695Skan/*    (or no) flags are set, a generic constant message is returned.  */
119169695Skan/* ------------------------------------------------------------------ */
120169695Skanconst char *
121169695SkandecContextStatusToString (const decContext * context)
122169695Skan{
123169695Skan  Int status = context->status;
124169695Skan  if (status == DEC_Conversion_syntax)
125169695Skan    return DEC_Condition_CS;
126169695Skan  if (status == DEC_Division_by_zero)
127169695Skan    return DEC_Condition_DZ;
128169695Skan  if (status == DEC_Division_impossible)
129169695Skan    return DEC_Condition_DI;
130169695Skan  if (status == DEC_Division_undefined)
131169695Skan    return DEC_Condition_DU;
132169695Skan  if (status == DEC_Inexact)
133169695Skan    return DEC_Condition_IE;
134169695Skan  if (status == DEC_Insufficient_storage)
135169695Skan    return DEC_Condition_IS;
136169695Skan  if (status == DEC_Invalid_context)
137169695Skan    return DEC_Condition_IC;
138169695Skan  if (status == DEC_Invalid_operation)
139169695Skan    return DEC_Condition_IO;
140169695Skan#if DECSUBSET
141169695Skan  if (status == DEC_Lost_digits)
142169695Skan    return DEC_Condition_LD;
143169695Skan#endif
144169695Skan  if (status == DEC_Overflow)
145169695Skan    return DEC_Condition_OV;
146169695Skan  if (status == DEC_Clamped)
147169695Skan    return DEC_Condition_PA;
148169695Skan  if (status == DEC_Rounded)
149169695Skan    return DEC_Condition_RO;
150169695Skan  if (status == DEC_Subnormal)
151169695Skan    return DEC_Condition_SU;
152169695Skan  if (status == DEC_Underflow)
153169695Skan    return DEC_Condition_UN;
154169695Skan  if (status == 0)
155169695Skan    return DEC_Condition_ZE;
156169695Skan  return DEC_Condition_MU;	/* Multiple errors */
157169695Skan}				/* decContextStatusToString */
158169695Skan
159169695Skan/* ------------------------------------------------------------------ */
160169695Skan/* decContextSetStatusFromString -- set status from a string          */
161169695Skan/*                                                                    */
162169695Skan/*  context is the controlling context                                */
163169695Skan/*  string is a string exactly equal to one that might be returned    */
164169695Skan/*            by decContextStatusToString                             */
165169695Skan/*                                                                    */
166169695Skan/*  The status bit corresponding to the string is set, and a trap     */
167169695Skan/*  is raised if appropriate.                                         */
168169695Skan/*                                                                    */
169169695Skan/*  returns the context structure, unless the string is equal to      */
170169695Skan/*    DEC_Condition_MU or is not recognized.  In these cases NULL is  */
171169695Skan/*    returned.                                                       */
172169695Skan/* ------------------------------------------------------------------ */
173169695SkandecContext *
174169695SkandecContextSetStatusFromString (decContext * context, const char *string)
175169695Skan{
176169695Skan  if (strcmp (string, DEC_Condition_CS) == 0)
177169695Skan    return decContextSetStatus (context, DEC_Conversion_syntax);
178169695Skan  if (strcmp (string, DEC_Condition_DZ) == 0)
179169695Skan    return decContextSetStatus (context, DEC_Division_by_zero);
180169695Skan  if (strcmp (string, DEC_Condition_DI) == 0)
181169695Skan    return decContextSetStatus (context, DEC_Division_impossible);
182169695Skan  if (strcmp (string, DEC_Condition_DU) == 0)
183169695Skan    return decContextSetStatus (context, DEC_Division_undefined);
184169695Skan  if (strcmp (string, DEC_Condition_IE) == 0)
185169695Skan    return decContextSetStatus (context, DEC_Inexact);
186169695Skan  if (strcmp (string, DEC_Condition_IS) == 0)
187169695Skan    return decContextSetStatus (context, DEC_Insufficient_storage);
188169695Skan  if (strcmp (string, DEC_Condition_IC) == 0)
189169695Skan    return decContextSetStatus (context, DEC_Invalid_context);
190169695Skan  if (strcmp (string, DEC_Condition_IO) == 0)
191169695Skan    return decContextSetStatus (context, DEC_Invalid_operation);
192169695Skan#if DECSUBSET
193169695Skan  if (strcmp (string, DEC_Condition_LD) == 0)
194169695Skan    return decContextSetStatus (context, DEC_Lost_digits);
195169695Skan#endif
196169695Skan  if (strcmp (string, DEC_Condition_OV) == 0)
197169695Skan    return decContextSetStatus (context, DEC_Overflow);
198169695Skan  if (strcmp (string, DEC_Condition_PA) == 0)
199169695Skan    return decContextSetStatus (context, DEC_Clamped);
200169695Skan  if (strcmp (string, DEC_Condition_RO) == 0)
201169695Skan    return decContextSetStatus (context, DEC_Rounded);
202169695Skan  if (strcmp (string, DEC_Condition_SU) == 0)
203169695Skan    return decContextSetStatus (context, DEC_Subnormal);
204169695Skan  if (strcmp (string, DEC_Condition_UN) == 0)
205169695Skan    return decContextSetStatus (context, DEC_Underflow);
206169695Skan  if (strcmp (string, DEC_Condition_ZE) == 0)
207169695Skan    return context;
208169695Skan  return NULL;			/* Multiple status, or unknown */
209169695Skan}				/* decContextSetStatusFromString */
210169695Skan
211169695Skan/* ------------------------------------------------------------------ */
212169695Skan/* decContextSetStatus -- set status and raise trap if appropriate    */
213169695Skan/*                                                                    */
214169695Skan/*  context is the controlling context                                */
215169695Skan/*  status  is the DEC_ exception code                                */
216169695Skan/*  returns the context structure                                     */
217169695Skan/*                                                                    */
218169695Skan/* Control may never return from this routine, if there is a signal   */
219169695Skan/* handler and it takes a long jump.                                  */
220169695Skan/* ------------------------------------------------------------------ */
221169695SkandecContext *
222169695SkandecContextSetStatus (decContext * context, uInt status)
223169695Skan{
224169695Skan  context->status |= status;
225169695Skan  if (status & context->traps)
226169695Skan    raise (SIGFPE);
227169695Skan  return context;
228169695Skan}				/* decContextSetStatus */
229