1 /********************************************************************\
2  * gnc-euro.c -- utilities for EURO currency                        *
3  *                                                                  *
4  * Copyright (C) 2000 Herbert Thoma                                 *
5  *                                                                  *
6  * This program is free software; you can redistribute it and/or    *
7  * modify it under the terms of the GNU General Public License as   *
8  * published by the Free Software Foundation; either version 2 of   *
9  * the License, or (at your option) any later version.              *
10  *                                                                  *
11  * This program is distributed in the hope that it will be useful,  *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
14  * GNU General Public License for more details.                     *
15  *                                                                  *
16  * You should have received a copy of the GNU General Public License*
17  * along with this program; if not, write to the Free Software      *
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.        *
19  *                                                                  *
20 \********************************************************************/
21 
22 #include <config.h>
23 
24 #include "gnc-euro.h"
25 
26 #include <glib/gi18n.h>
27 #include <math.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include "gnc-ui-util.h"
32 
33 /* local structs */
34 typedef struct
35 {
36     const char *currency;
37     double rate;
38 } gnc_euro_rate_struct;
39 
40 
41 /* This array MUST be sorted ! */
42 /* The rates are per EURO */
43 static gnc_euro_rate_struct gnc_euro_rates[] =
44 {
45     { "ATS",  13.7603 },  /* austrian schilling */
46     { "BEF",  40.3399 },  /* belgian franc */
47     { "BFR",  40.3399 },  /* belgian franc */
48     { "CYP",  .585274 },  /* cyprus pound */
49     { "DEM",  1.95583 },  /* german mark */
50     { "DM",   1.95583 },  /* german mark */
51     { "EEK",  15.6466 },  /* Estonian Kroon */
52     { "ESC",  200.482 },  /* portuguese escudo */
53     { "ESP",  166.386 },  /* spanish peseta */
54     { "EUR",  1.00000 },  /* euro */
55     { "EURO", 1.00000 },  /* euro */
56     { "FF",   6.55957 },  /* french franc */
57     { "FIM",  5.94573 },  /* finnmark */
58     { "FMK",  5.94573 },  /* finnmark */
59     { "FRF",  6.55957 },  /* french franc */
60     { "GRD",  340.750 },  /* greek drachma */
61     { "HFL",  2.20371 },  /* netherland gulden */
62     { "IEP",  .787564 },  /* irish pound */
63     { "IRP",  .787564 },  /* irish pound */
64     { "ITL",  1936.27 },  /* italian lira */
65     { "LFR",  40.3399 },  /* luxembourg franc */
66     { "LIT",  1936.27 },  /* italian lira */
67     { "LUF",  40.3399 },  /* luxembourg franc */
68     { "LVL",  .702804 },  /* latvian lats */
69     { "MTL",  .429300 },  /* maltese lira */
70     { "NLG",  2.20371 },  /* netherland gulden */
71     { "PTA",  166.386 },  /* spanish peseta */
72     { "PTE",  200.482 },  /* portuguese escudo */
73     { "S",    13.7603 },  /* austrian schilling */
74     { "SCH",  13.7603 },  /* austrian schilling */
75     { "SIT",  239.640 },  /* slovenian tolar */
76     { "SKK",  30.1260 }   /* slovak koruna */
77 };
78 
79 static int
gnc_euro_rate_compare(const void * key,const void * value)80 gnc_euro_rate_compare (const void * key, const void * value)
81 {
82     const gnc_commodity * curr = key;
83     const gnc_euro_rate_struct * euro = value;
84 
85     if (!key || !value)
86         return -1;
87 
88     return g_ascii_strcasecmp(gnc_commodity_get_mnemonic(curr), euro->currency);
89 }
90 
91 #if 0 /* Not Used */
92 static int
93 gnc_euro_rate_compare_code (const void * key, const void * value)
94 {
95     const char *code = key;
96     const gnc_euro_rate_struct * euro = value;
97 
98     if (!key || !value)
99         return -1;
100 
101     return g_ascii_strcasecmp (code, euro->currency);
102 }
103 #endif
104 
105 /* ------------------------------------------------------ */
106 
107 gboolean
gnc_is_euro_currency(const gnc_commodity * currency)108 gnc_is_euro_currency(const gnc_commodity * currency)
109 {
110     gnc_euro_rate_struct *result;
111 
112     if (currency == NULL)
113         return FALSE;
114 
115     if (!gnc_commodity_is_iso(currency))
116         return FALSE;
117 
118     result = bsearch(currency,
119                      gnc_euro_rates,
120                      sizeof(gnc_euro_rates) / sizeof(gnc_euro_rate_struct),
121                      sizeof(gnc_euro_rate_struct),
122                      gnc_euro_rate_compare);
123 
124     if (result == NULL)
125         return FALSE;
126 
127     return TRUE;
128 }
129 
130 /* ------------------------------------------------------ */
131 
132 gnc_numeric
gnc_convert_to_euro(const gnc_commodity * currency,gnc_numeric value)133 gnc_convert_to_euro(const gnc_commodity * currency, gnc_numeric value)
134 {
135     gnc_euro_rate_struct *result;
136 
137     if (currency == NULL)
138         return gnc_numeric_zero ();
139 
140     if (!gnc_commodity_is_iso(currency))
141         return gnc_numeric_zero ();
142 
143     result = bsearch(currency,
144                      gnc_euro_rates,
145                      sizeof(gnc_euro_rates) / sizeof(gnc_euro_rate_struct),
146                      sizeof(gnc_euro_rate_struct),
147                      gnc_euro_rate_compare);
148 
149     if (result == NULL)
150         return gnc_numeric_zero ();
151 
152     /* round to 2 decimal places */
153     {
154         gnc_numeric rate;
155 
156         rate = double_to_gnc_numeric (result->rate, 100000, GNC_HOW_RND_ROUND_HALF_UP);
157 
158         /* EC Regulation 1103/97 states we should use "Round half away from zero"
159          * See http://europa.eu/legislation_summaries/economic_and_monetary_affairs/institutional_and_economic_framework/l25025_en.htm */
160         return gnc_numeric_div (value, rate, 100, GNC_HOW_RND_ROUND_HALF_UP);
161     }
162 }
163 
164 /* ------------------------------------------------------ */
165 
166 gnc_numeric
gnc_convert_from_euro(const gnc_commodity * currency,gnc_numeric value)167 gnc_convert_from_euro(const gnc_commodity * currency, gnc_numeric value)
168 {
169     gnc_euro_rate_struct * result;
170 
171     if (currency == NULL)
172         return gnc_numeric_zero ();
173 
174     if (!gnc_commodity_is_iso(currency))
175         return gnc_numeric_zero ();
176 
177     result = bsearch(currency,
178                      gnc_euro_rates,
179                      sizeof(gnc_euro_rates) / sizeof(gnc_euro_rate_struct),
180                      sizeof(gnc_euro_rate_struct),
181                      gnc_euro_rate_compare);
182 
183     if (result == NULL)
184         return gnc_numeric_zero ();
185 
186     {
187         gnc_numeric rate;
188 
189         rate = double_to_gnc_numeric (result->rate, 100000, GNC_HOW_RND_ROUND_HALF_UP);
190 
191         /* EC Regulation 1103/97 states we should use "Round half away from zero"
192          * See http://europa.eu/legislation_summaries/economic_and_monetary_affairs/institutional_and_economic_framework/l25025_en.htm */
193         return gnc_numeric_mul (value, rate, gnc_commodity_get_fraction (currency),
194                                 GNC_HOW_RND_ROUND_HALF_UP);
195     }
196 }
197 
198 /* ------------------------------------------------------ */
199 
200 gnc_numeric
gnc_euro_currency_get_rate(const gnc_commodity * currency)201 gnc_euro_currency_get_rate (const gnc_commodity *currency)
202 {
203     gnc_euro_rate_struct * result;
204 
205     if (currency == NULL)
206         return gnc_numeric_zero ();
207 
208     if (!gnc_commodity_is_iso(currency))
209         return gnc_numeric_zero ();
210 
211     result = bsearch(currency,
212                      gnc_euro_rates,
213                      sizeof(gnc_euro_rates) / sizeof(gnc_euro_rate_struct),
214                      sizeof(gnc_euro_rate_struct),
215                      gnc_euro_rate_compare);
216 
217     if (result == NULL)
218         return gnc_numeric_zero ();
219 
220     return double_to_gnc_numeric (result->rate, GNC_DENOM_AUTO,
221                                   GNC_HOW_RND_ROUND_HALF_UP);
222 }
223 
224 /* ------------------------------------------------------ */
225 
226 gnc_commodity *
gnc_get_euro(void)227 gnc_get_euro (void)
228 {
229     gnc_commodity_table *table;
230 
231     table = gnc_commodity_table_get_table (gnc_get_current_book ());
232 
233     return gnc_commodity_table_lookup (table, GNC_COMMODITY_NS_CURRENCY, "EUR");
234 }
235