1 /* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
3 /*
4 * This file is part of The Croco Library
5 *
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2.1 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
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 Lesser General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 * USA
20 *
21 * Author: Dodji Seketeli
22 * See COPYRIGHTS file for copyrights information.
23 */
25 /**
26 *@file
27 *The definition
28 *of the #CRNum class.
29 */
31 #include "cr-num.h"
32 #include "string.h"
34 /**
35 *The default constructor of
36 *#CRNum.
37 *@return the newly built instance of
38 *#CRNum.
39 */
40 CRNum *
41 cr_num_new (void)
42 {
43 CRNum *result = (CRNum *)g_try_malloc (sizeof (CRNum));
45 if (result == NULL) {
46 cr_utils_trace_info ("Out of memory");
47 return NULL;
48 }
50 memset (result, 0, sizeof (CRNum));
52 return result;
53 }
55 /**
56 *A constructor of #CRNum.
57 *@param a_is_natural indicates whether the intance of #CRNum is
58 *a natural number or not.
59 *@param a_integer_part the integer part of the instance
60 *of #CRNum
61 *@param a_decimal_part in case the instance of #CRNum
62 *natural number (but a decimal one) this parameter
63 *is the decimal part of the instance of #CRNum.
64 *@return the newly built instance of #CRNum or
65 *NULL if an error arises.
66 */
67 CRNum *
68 cr_num_new_with_val (gdouble a_val, enum CRNumType a_type)
69 {
70 CRNum *result = NULL;
72 result = cr_num_new ();
74 g_return_val_if_fail (result, NULL);
76 result->val = a_val;
77 result->type = a_type;
79 return result;
80 }
82 /**
83 *Returns the string representation of the
84 *current instance of #CRNum.
85 *@param a_this the current instance of #CRNum.
86 *@return the newly built string representation
87 *of the current instance of #CRNum. The returned
88 *string is NULL terminated. The caller *must*
89 *free the returned string.
90 */
91 guchar *
92 cr_num_to_string (CRNum * a_this)
93 {
94 gdouble test_val = 0.0;
96 guchar *tmp_char1 = NULL,
97 *tmp_char2 = NULL,
98 *result = NULL;
100 g_return_val_if_fail (a_this, NULL);
102 test_val = a_this->val - (glong) a_this->val;
104 if (!test_val) {
105 tmp_char1 = (guchar *)g_strdup_printf ("%ld", (glong) a_this->val);
106 } else {
107 /* We can't use g_ascii_dtostr, because that sometimes uses
108 e notation (which wouldn't be a valid number in CSS). */
109 size_t const buflen = 35; /* fairly arbitrary. */
110 tmp_char1 = (guchar *)g_malloc (buflen);
111 g_ascii_formatd ((gchar *)tmp_char1, buflen, "%.17f", a_this->val);
112 }
114 g_return_val_if_fail (tmp_char1, NULL);
116 switch (a_this->type) {
117 case NUM_LENGTH_EM:
118 tmp_char2 = (guchar *) "em";
119 break;
121 case NUM_LENGTH_EX:
122 tmp_char2 = (guchar *) "ex";
123 break;
125 case NUM_LENGTH_PX:
126 tmp_char2 = (guchar *) "px";
127 break;
129 case NUM_LENGTH_IN:
130 tmp_char2 = (guchar *) "in";
131 break;
133 case NUM_LENGTH_CM:
134 tmp_char2 = (guchar *) "cm";
135 break;
137 case NUM_LENGTH_MM:
138 tmp_char2 = (guchar *) "mm";
139 break;
141 case NUM_LENGTH_PT:
142 tmp_char2 = (guchar *) "pt";
143 break;
145 case NUM_LENGTH_PC:
146 tmp_char2 = (guchar *) "pc";
147 break;
149 case NUM_ANGLE_DEG:
150 tmp_char2 = (guchar *) "deg";
151 break;
153 case NUM_ANGLE_RAD:
154 tmp_char2 = (guchar *) "rad";
155 break;
157 case NUM_ANGLE_GRAD:
158 tmp_char2 = (guchar *) "grad";
159 break;
161 case NUM_TIME_MS:
162 tmp_char2 = (guchar *) "ms";
163 break;
165 case NUM_TIME_S:
166 tmp_char2 = (guchar *) "s";
167 break;
169 case NUM_FREQ_HZ:
170 tmp_char2 = (guchar *) "Hz";
171 break;
173 case NUM_FREQ_KHZ:
174 tmp_char2 = (guchar *) "KHz";
175 break;
177 case NUM_PERCENTAGE:
178 tmp_char2 = (guchar *) "%";
179 break;
180 case NUM_INHERIT:
181 tmp_char2 = (guchar *) "inherit";
182 break ;
183 case NUM_AUTO:
184 tmp_char2 = (guchar *) "auto";
185 break ;
186 case NUM_GENERIC:
187 tmp_char2 = NULL ;
188 break ;
189 default:
190 tmp_char2 = (guchar *) "unknown";
191 break;
192 }
194 if (tmp_char2) {
195 result = (guchar *)g_strconcat (
196 (gchar *)tmp_char1, (gchar *)tmp_char2, NULL);
197 g_free (tmp_char1);
198 } else {
199 result = tmp_char1;
200 }
202 return result;
203 }
205 /**
206 *Copies an instance of #CRNum.
207 *@param a_src the instance of #CRNum to copy.
208 *Must be non NULL.
209 *@param a_dst the destination of the copy.
210 *Must be non NULL
211 *@return CR_OK upon successful completion, an
212 *error code otherwise.
213 */
214 enum CRStatus
215 cr_num_copy (CRNum * a_dest, CRNum * a_src)
216 {
217 g_return_val_if_fail (a_dest && a_src, CR_BAD_PARAM_ERROR);
219 memcpy (a_dest, a_src, sizeof (CRNum));
221 return CR_OK;
222 }
224 /**
225 *Duplicates an instance of #CRNum
226 *@param a_this the instance of #CRNum to duplicate.
227 *@return the newly created (duplicated) instance of #CRNum.
228 *Must be freed by cr_num_destroy().
229 */
230 CRNum *
231 cr_num_dup (CRNum * a_this)
232 {
233 CRNum *result = NULL;
234 enum CRStatus status = CR_OK;
236 g_return_val_if_fail (a_this, NULL);
238 result = cr_num_new ();
239 g_return_val_if_fail (result, NULL);
241 status = cr_num_copy (result, a_this);
242 g_return_val_if_fail (status == CR_OK, NULL);
244 return result;
245 }
247 /**
248 *Sets an instance of #CRNum.
249 *@param a_this the current instance of #CRNum to be set.
250 *@param a_val the new numerical value to be hold by the current
251 *instance of #CRNum
252 *@param a_type the new type of #CRNum.
253 */
254 enum CRStatus
255 cr_num_set (CRNum * a_this, gdouble a_val, enum CRNumType a_type)
256 {
257 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
259 a_this->val = a_val;
260 a_this->type = a_type;
262 return CR_OK;
263 }
265 /**
266 *Tests if the current instance of #CRNum is a fixed
267 *length value or not. Typically a fixed length value
268 *is anything from NUM_LENGTH_EM to NUM_LENGTH_PC.
269 *See the definition of #CRNumType to see what we mean.
270 *@return TRUE if the instance of #CRNum is a fixed length number,
271 *FALSE otherwise.
272 */
273 gboolean
274 cr_num_is_fixed_length (CRNum * a_this)
275 {
276 gboolean result = FALSE;
278 g_return_val_if_fail (a_this, FALSE);
280 if (a_this->type >= NUM_LENGTH_EM
281 && a_this->type <= NUM_LENGTH_PC) {
282 result = TRUE ;
283 }
284 return result ;
285 }
287 /**
288 *The destructor of #CRNum.
289 *@param a_this the this pointer of
290 *the current instance of #CRNum.
291 */
292 void
293 cr_num_destroy (CRNum * a_this)
294 {
295 g_return_if_fail (a_this);
297 g_free (a_this);
298 }