/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
/*
* This file is part of The Croco Library
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* Author: Dodji Seketeli
* See COPYRIGHTS file for copyrights information.
*/
/**
*@CRNum:
*
*The definition
*of the #CRNum class.
*/
#include "cr-num.h"
#include "string.h"
/**
* cr_num_new:
*
*#CRNum.
*
*Returns the newly built instance of
*#CRNum.
*/
CRNum *
cr_num_new (void)
{
CRNum *result = NULL;
result = g_try_malloc (sizeof (CRNum));
if (result == NULL) {
cr_utils_trace_info ("Out of memory");
return NULL;
}
memset (result, 0, sizeof (CRNum));
return result;
}
/**
* cr_num_new_with_val:
* @a_val: the numerical value of the number.
* @a_type: the type of number.
*
* A constructor of #CRNum.
*
* Returns the newly built instance of #CRNum or
* NULL if an error arises.
*/
CRNum *
cr_num_new_with_val (gdouble a_val, enum CRNumType a_type)
{
CRNum *result = NULL;
result = cr_num_new ();
g_return_val_if_fail (result, NULL);
result->val = a_val;
result->type = a_type;
return result;
}
/**
* cr_num_to_string:
*@a_this: the current instance of #CRNum.
*
*Returns the newly built string representation
*of the current instance of #CRNum. The returned
*string is NULL terminated. The caller *must*
*free the returned string.
*/
guchar *
cr_num_to_string (CRNum const * a_this)
{
gdouble test_val = 0.0;
guchar *tmp_char1 = NULL,
*tmp_char2 = NULL,
*result = NULL;
g_return_val_if_fail (a_this, NULL);
test_val = a_this->val - (glong) a_this->val;
if (!test_val) {
tmp_char1 = (guchar *) g_strdup_printf ("%ld", (glong) a_this->val);
} else {
/* We can't use g_ascii_dtostr, because that sometimes uses
e notation (which wouldn't be a valid number in CSS). */
size_t const buflen = 35; /* fairly arbitrary. */
tmp_char1 = (guchar *)g_malloc (buflen);
g_ascii_formatd ((gchar *)tmp_char1, buflen, "%.17f", a_this->val);
}
g_return_val_if_fail (tmp_char1, NULL);
switch (a_this->type) {
case NUM_LENGTH_EM:
tmp_char2 = (guchar *) "em";
break;
case NUM_LENGTH_EX:
tmp_char2 = (guchar *) "ex";
break;
case NUM_LENGTH_PX:
tmp_char2 = (guchar *) "px";
break;
case NUM_LENGTH_IN:
tmp_char2 = (guchar *) "in";
break;
case NUM_LENGTH_CM:
tmp_char2 = (guchar *) "cm";
break;
case NUM_LENGTH_MM:
tmp_char2 = (guchar *) "mm";
break;
case NUM_LENGTH_PT:
tmp_char2 = (guchar *) "pt";
break;
case NUM_LENGTH_PC:
tmp_char2 = (guchar *) "pc";
break;
case NUM_ANGLE_DEG:
tmp_char2 = (guchar *) "deg";
break;
case NUM_ANGLE_RAD:
tmp_char2 = (guchar *) "rad";
break;
case NUM_ANGLE_GRAD:
tmp_char2 = (guchar *) "grad";
break;
case NUM_TIME_MS:
tmp_char2 = (guchar *) "ms";
break;
case NUM_TIME_S:
tmp_char2 = (guchar *) "s";
break;
case NUM_FREQ_HZ:
tmp_char2 = (guchar *) "Hz";
break;
case NUM_FREQ_KHZ:
tmp_char2 = (guchar *) "KHz";
break;
case NUM_PERCENTAGE:
tmp_char2 = (guchar *) "%";
break;
case NUM_INHERIT:
tmp_char2 = (guchar *) "inherit";
break ;
case NUM_AUTO:
tmp_char2 = (guchar *) "auto";
break ;
case NUM_GENERIC:
tmp_char2 = NULL ;
break ;
default:
tmp_char2 = (guchar *) "unknown";
break;
}
if (tmp_char2) {
result = (guchar *) g_strconcat ((gchar *) tmp_char1, tmp_char2, NULL);
g_free (tmp_char1);
} else {
result = tmp_char1;
}
return result;
}
/**
* cr_num_copy:
*@a_src: the instance of #CRNum to copy.
*Must be non NULL.
*@a_dest: the destination of the copy.
*Must be non NULL
*
*Copies an instance of #CRNum.
*
*Returns CR_OK upon successful completion, an
*error code otherwise.
*/
enum CRStatus
cr_num_copy (CRNum * a_dest, CRNum const * a_src)
{
g_return_val_if_fail (a_dest && a_src, CR_BAD_PARAM_ERROR);
memcpy (a_dest, a_src, sizeof (CRNum));
return CR_OK;
}
/**
* cr_num_dup:
*@a_this: the instance of #CRNum to duplicate.
*
*Duplicates an instance of #CRNum
*
*Returns the newly created (duplicated) instance of #CRNum.
*Must be freed by cr_num_destroy().
*/
CRNum *
cr_num_dup (CRNum const * a_this)
{
CRNum *result = NULL;
enum CRStatus status = CR_OK;
g_return_val_if_fail (a_this, NULL);
result = cr_num_new ();
g_return_val_if_fail (result, NULL);
status = cr_num_copy (result, a_this);
g_return_val_if_fail (status == CR_OK, NULL);
return result;
}
/**
* cr_num_set:
*Sets an instance of #CRNum.
*@a_this: the current instance of #CRNum to be set.
*@a_val: the new numerical value to be hold by the current
*instance of #CRNum
*@a_type: the new type of #CRNum.
*
* Returns CR_OK upon succesful completion, an error code otherwise.
*/
enum CRStatus
cr_num_set (CRNum * a_this, gdouble a_val, enum CRNumType a_type)
{
g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
a_this->val = a_val;
a_this->type = a_type;
return CR_OK;
}
/**
* cr_num_is_fixed_length:
* @a_this: the current instance of #CRNum .
*
*Tests if the current instance of #CRNum is a fixed
*length value or not. Typically a fixed length value
*is anything from NUM_LENGTH_EM to NUM_LENGTH_PC.
*See the definition of #CRNumType to see what we mean.
*
*Returns TRUE if the instance of #CRNum is a fixed length number,
*FALSE otherwise.
*/
gboolean
cr_num_is_fixed_length (CRNum const * a_this)
{
gboolean result = FALSE;
g_return_val_if_fail (a_this, FALSE);
if (a_this->type >= NUM_LENGTH_EM
&& a_this->type <= NUM_LENGTH_PC) {
result = TRUE ;
}
return result ;
}
/**
* cr_num_destroy:
*@a_this: the this pointer of
*the current instance of #CRNum.
*
*The destructor of #CRNum.
*/
void
cr_num_destroy (CRNum * a_this)
{
g_return_if_fail (a_this);
g_free (a_this);
}