1997-11-01 01:39:32 +00:00
|
|
|
/********************************************************************\
|
|
|
|
|
* util.c -- utility functions that are used everywhere else for *
|
|
|
|
|
* xacc (X-Accountant) *
|
|
|
|
|
* Copyright (C) 1997 Robin D. Clark *
|
2000-05-14 20:54:20 +00:00
|
|
|
* Copyright (C) 1997-2000 Linas Vepstas <linas@linas.org> *
|
1997-11-01 01:39:32 +00:00
|
|
|
* *
|
|
|
|
|
* This program is free software; you can redistribute it and/or *
|
|
|
|
|
* modify it under the terms of the GNU General Public License as *
|
|
|
|
|
* published by the Free Software Foundation; either version 2 of *
|
|
|
|
|
* the License, or (at your option) any later version. *
|
|
|
|
|
* *
|
|
|
|
|
* 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 General Public License*
|
2000-04-24 21:12:41 +00:00
|
|
|
* along with this program; if not, contact: *
|
1997-11-01 01:39:32 +00:00
|
|
|
* *
|
2000-04-24 21:12:41 +00:00
|
|
|
* Free Software Foundation Voice: +1-617-542-5942 *
|
|
|
|
|
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
|
|
|
|
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
|
|
|
|
* *
|
|
|
|
|
* Author: Rob Clark (rclark@cs.hmc.edu) *
|
|
|
|
|
* Author: Linas Vepstas (linas@linas.org) *
|
1997-11-01 01:39:32 +00:00
|
|
|
\********************************************************************/
|
|
|
|
|
|
2000-06-07 20:23:35 +00:00
|
|
|
#include <stdlib.h>
|
1999-11-22 05:11:30 +00:00
|
|
|
#include <math.h>
|
1998-02-02 23:54:44 +00:00
|
|
|
#include <string.h>
|
2000-01-17 21:39:42 +00:00
|
|
|
#include <locale.h>
|
2000-05-03 19:55:36 +00:00
|
|
|
#include <limits.h>
|
2000-03-24 09:47:27 +00:00
|
|
|
#include <ctype.h>
|
1998-02-02 23:54:44 +00:00
|
|
|
|
2000-03-22 10:10:50 +00:00
|
|
|
/* #include <glib.h> */
|
|
|
|
|
|
1997-11-30 02:39:58 +00:00
|
|
|
#include "config.h"
|
1998-01-28 05:55:07 +00:00
|
|
|
#include "messages.h"
|
2000-01-17 21:39:42 +00:00
|
|
|
#include "gnc-common.h"
|
1997-11-01 01:39:32 +00:00
|
|
|
#include "util.h"
|
|
|
|
|
|
1999-01-30 21:41:50 +00:00
|
|
|
/* hack alert -- stpcpy prototype is missing, use -DGNU */
|
|
|
|
|
char * stpcpy (char *dest, const char *src);
|
|
|
|
|
|
1997-11-01 01:39:32 +00:00
|
|
|
/** GLOBALS *********************************************************/
|
2000-06-05 05:51:39 +00:00
|
|
|
gncLogLevel loglevel[MOD_NUM] =
|
|
|
|
|
{
|
|
|
|
|
GNC_LOG_NOTHING, /* DUMMY */
|
|
|
|
|
GNC_LOG_WARNING, /* ENGINE */
|
|
|
|
|
GNC_LOG_WARNING, /* IO */
|
|
|
|
|
GNC_LOG_WARNING, /* REGISTER */
|
|
|
|
|
GNC_LOG_WARNING, /* LEDGER */
|
|
|
|
|
GNC_LOG_WARNING, /* HTML */
|
|
|
|
|
GNC_LOG_WARNING, /* GUI */
|
|
|
|
|
GNC_LOG_WARNING, /* SCRUB */
|
|
|
|
|
GNC_LOG_WARNING, /* GTK_REG */
|
|
|
|
|
GNC_LOG_WARNING, /* GUILE */
|
|
|
|
|
GNC_LOG_DEBUG, /* BACKEND */
|
|
|
|
|
GNC_LOG_WARNING, /* QUERY */
|
1998-12-06 07:43:14 +00:00
|
|
|
};
|
1997-11-22 03:41:59 +00:00
|
|
|
|
2000-06-05 05:51:39 +00:00
|
|
|
/* Set the logging level of the given module. */
|
|
|
|
|
void
|
|
|
|
|
gnc_set_log_level(gncModuleType module, gncLogLevel level)
|
|
|
|
|
{
|
|
|
|
|
if ((module < 0) || (module > MOD_LAST))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
loglevel[module] = level;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Set the logging level for all modules. */
|
|
|
|
|
void
|
|
|
|
|
gnc_set_log_level_global(gncLogLevel level)
|
|
|
|
|
{
|
|
|
|
|
gncModuleType module;
|
|
|
|
|
|
|
|
|
|
for (module = GNC_LOG_NOTHING; module < MOD_NUM; module++)
|
|
|
|
|
loglevel[module] = level;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2000-05-14 20:54:20 +00:00
|
|
|
/********************************************************************\
|
|
|
|
|
\********************************************************************/
|
|
|
|
|
/* prettify() cleans up subroutine names.
|
|
|
|
|
* AIX/xlC has the habit of printing signatures not names; clean this up.
|
|
|
|
|
* On other operating systems, truncate name to 30 chars.
|
|
|
|
|
* Note this routine is not thread safe. Note we wouldn't need this
|
|
|
|
|
* routine if AIX did something more reasonable. Hope thread safety
|
|
|
|
|
* doesn't poke us in eye.
|
|
|
|
|
*/
|
|
|
|
|
char *
|
|
|
|
|
prettify (const char *name)
|
|
|
|
|
{
|
|
|
|
|
static char bf[35];
|
|
|
|
|
char *p;
|
|
|
|
|
strncpy (bf, name, 29); bf[28] = 0;
|
|
|
|
|
p = strchr (bf, '(');
|
|
|
|
|
if (p)
|
|
|
|
|
{
|
|
|
|
|
*(p+1) = ')';
|
|
|
|
|
*(p+2) = 0x0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
strcpy (&bf[26], "...()");
|
|
|
|
|
}
|
|
|
|
|
return bf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1997-11-01 01:39:32 +00:00
|
|
|
/********************************************************************\
|
|
|
|
|
* DEBUGGING MEMORY ALLOCATION STUFF *
|
|
|
|
|
\********************************************************************/
|
1997-11-30 02:39:58 +00:00
|
|
|
#if DEBUG_MEMORY
|
1998-08-05 05:57:41 +00:00
|
|
|
|
1999-01-19 08:29:46 +00:00
|
|
|
// #if defined (__NetBSD__) || defined(__FreeBSD__)
|
|
|
|
|
|
1999-04-13 06:16:26 +00:00
|
|
|
#ifndef HAVE_MALLOC_USABLE_SIZE
|
1999-01-19 08:29:46 +00:00
|
|
|
#define malloc_usable_size(ptr) 0
|
1998-08-05 05:57:41 +00:00
|
|
|
#endif
|
|
|
|
|
|
1997-11-01 01:39:32 +00:00
|
|
|
size_t core=0;
|
1998-08-05 05:57:41 +00:00
|
|
|
|
1997-11-01 01:39:32 +00:00
|
|
|
void
|
|
|
|
|
dfree( void *ptr )
|
2000-03-22 10:10:50 +00:00
|
|
|
{
|
1997-11-01 01:39:32 +00:00
|
|
|
core -= malloc_usable_size(ptr);
|
|
|
|
|
free(ptr);
|
2000-03-22 10:10:50 +00:00
|
|
|
}
|
1997-11-01 01:39:32 +00:00
|
|
|
|
|
|
|
|
void*
|
|
|
|
|
dmalloc( size_t size )
|
2000-03-22 10:10:50 +00:00
|
|
|
{
|
1997-11-01 01:39:32 +00:00
|
|
|
int i;
|
1997-11-22 03:41:59 +00:00
|
|
|
char *ptr;
|
|
|
|
|
ptr = (char *)malloc(size);
|
1997-11-01 01:39:32 +00:00
|
|
|
for( i=0; i<size; i++ )
|
|
|
|
|
ptr[i] = '.';
|
|
|
|
|
|
|
|
|
|
core += malloc_usable_size(ptr);
|
|
|
|
|
return (void *)ptr;
|
2000-03-22 10:10:50 +00:00
|
|
|
}
|
1997-11-01 01:39:32 +00:00
|
|
|
|
|
|
|
|
size_t
|
|
|
|
|
dcoresize(void)
|
2000-03-22 10:10:50 +00:00
|
|
|
{
|
1997-11-01 01:39:32 +00:00
|
|
|
return core;
|
2000-03-22 10:10:50 +00:00
|
|
|
}
|
1997-11-01 01:39:32 +00:00
|
|
|
#endif
|
|
|
|
|
|
2000-05-25 18:30:24 +00:00
|
|
|
/********************************************************************\
|
|
|
|
|
\********************************************************************/
|
|
|
|
|
|
|
|
|
|
#define UPPER(c) (((c) >= 'a' && (c) <= 'z') ? (c) + 'A' - 'a' : (c))
|
|
|
|
|
|
|
|
|
|
/* Search for str2 in first nchar chars of str1, ignore case..
|
|
|
|
|
* Return pointer to first match, or null.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
strncasestr(const char *str1, const char *str2, size_t len)
|
|
|
|
|
{
|
|
|
|
|
while (*str1 && len--)
|
|
|
|
|
{
|
|
|
|
|
if (UPPER(*str1) == UPPER(*str2))
|
|
|
|
|
{
|
|
|
|
|
if (strncasecmp(str1,str2,strlen(str2)) == 0)
|
|
|
|
|
{
|
|
|
|
|
return (char *) str1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
str1++;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Search for str2 in str1, ignore case.
|
|
|
|
|
* Return pointer to first match, or null.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
strcasestr(const char *str1, const char *str2)
|
|
|
|
|
{
|
|
|
|
|
size_t len = strlen (str1);
|
|
|
|
|
char * retval = strncasestr (str1, str2, len);
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Reversed strstr -- search for a needle in the haystack,
|
|
|
|
|
* from the far end
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
rstrstr (const char *haystack, const char * needle)
|
|
|
|
|
{
|
|
|
|
|
int haylen = strlen (haystack);
|
|
|
|
|
int neelen = strlen (needle);
|
|
|
|
|
|
|
|
|
|
const char * hp = haystack + haylen - 1;
|
|
|
|
|
const char * np = needle + neelen - 1;
|
|
|
|
|
|
|
|
|
|
if ((0 == neelen) || (0 == haylen)) return 0x0;
|
|
|
|
|
|
|
|
|
|
while (hp >= haystack+neelen) {
|
|
|
|
|
if (*hp == *np) {
|
|
|
|
|
--np;
|
|
|
|
|
if (np < needle) return (char *) hp;
|
|
|
|
|
} else {
|
|
|
|
|
np = needle + neelen - 1;
|
|
|
|
|
}
|
|
|
|
|
--hp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0x0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* The strpskip() function locates the first occurrence in the
|
|
|
|
|
* string s that does not match any of the characters in "reject".
|
|
|
|
|
* This is the opposite of strpbrk()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
strpskip (const char * s, const char *reject)
|
|
|
|
|
{
|
|
|
|
|
size_t i, rlen;
|
|
|
|
|
char * retval;
|
|
|
|
|
|
|
|
|
|
if (!s) return NULL;
|
|
|
|
|
if (!reject) return (char *) s;
|
|
|
|
|
|
|
|
|
|
rlen = sizeof (reject);
|
|
|
|
|
retval = (char *) s;
|
|
|
|
|
|
|
|
|
|
while (*retval) {
|
|
|
|
|
int match = 0;
|
|
|
|
|
for (i=0; i<rlen; i++) {
|
|
|
|
|
if (reject[i] == *retval) {match=1; break; }
|
|
|
|
|
}
|
|
|
|
|
if (!match) return retval;
|
|
|
|
|
retval ++;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1998-09-21 03:42:58 +00:00
|
|
|
/********************************************************************\
|
|
|
|
|
\********************************************************************/
|
|
|
|
|
|
|
|
|
|
int
|
2000-03-22 10:10:50 +00:00
|
|
|
safe_strcmp (const char * da, const char * db)
|
|
|
|
|
{
|
1998-09-21 03:42:58 +00:00
|
|
|
SAFE_STRCMP (da, db);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-18 21:13:40 +00:00
|
|
|
/********************************************************************\
|
|
|
|
|
\********************************************************************/
|
|
|
|
|
/* inverse of strtoul */
|
|
|
|
|
|
|
|
|
|
#define MAX_DIGITS 50
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
ultostr (unsigned long val, int base)
|
|
|
|
|
{
|
|
|
|
|
char buf[MAX_DIGITS];
|
|
|
|
|
unsigned long broke[MAX_DIGITS];
|
|
|
|
|
int i;
|
|
|
|
|
unsigned long places=0, reval;
|
|
|
|
|
|
|
|
|
|
if ((2>base) || (36<base)) return NULL;
|
|
|
|
|
|
|
|
|
|
/* count digits */
|
|
|
|
|
places = 0;
|
|
|
|
|
for (i=0; i<MAX_DIGITS; i++) {
|
|
|
|
|
broke[i] = val;
|
|
|
|
|
places ++;
|
|
|
|
|
val /= base;
|
|
|
|
|
if (0 == val) break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* normalize */
|
|
|
|
|
reval = 0;
|
|
|
|
|
for (i=places-2; i>=0; i--) {
|
|
|
|
|
reval += broke[i+1];
|
|
|
|
|
reval *= base;
|
|
|
|
|
broke[i] -= reval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* print */
|
|
|
|
|
for (i=0; i<places; i++) {
|
|
|
|
|
if (10>broke[i]) {
|
|
|
|
|
buf[places-1-i] = 0x30+broke[i]; /* ascii digit zero */
|
|
|
|
|
} else {
|
2000-05-26 02:20:11 +00:00
|
|
|
buf[places-1-i] = 0x41-10+broke[i]; /* ascii capital A */
|
1998-10-18 21:13:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
buf[places] = 0x0;
|
|
|
|
|
|
|
|
|
|
return strdup (buf);
|
|
|
|
|
}
|
|
|
|
|
|
1999-12-31 00:05:41 +00:00
|
|
|
/********************************************************************\
|
|
|
|
|
* utility function to convert floating point value to a string
|
|
|
|
|
\********************************************************************/
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
util_fptostr(char *buf, double val, int prec)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
char formatString[10];
|
|
|
|
|
char prefix[] = "%0.";
|
|
|
|
|
char postfix[] = "f";
|
|
|
|
|
|
|
|
|
|
/* This routine can only handle precision between 0 and 9, so
|
|
|
|
|
* clamp precision to that range */
|
|
|
|
|
if (prec > 9) prec = 9;
|
|
|
|
|
if (prec < 0) prec = 0;
|
|
|
|
|
|
|
|
|
|
/* Make sure that the output does not resemble "-0.00" by forcing
|
|
|
|
|
* val to 0.0 when we have a very small negative number */
|
|
|
|
|
if ((val <= 0.0) && (val > -pow(0.1, prec+1) * 5.0))
|
|
|
|
|
val = 0.0;
|
|
|
|
|
|
|
|
|
|
/* Create a format string to pass into sprintf. By doing this,
|
|
|
|
|
* we can get sprintf to convert the number to a string, rather
|
|
|
|
|
* than maintaining conversion code ourselves. */
|
|
|
|
|
i = 0;
|
|
|
|
|
strcpy(&formatString[i], prefix);
|
|
|
|
|
i += strlen(prefix);
|
|
|
|
|
formatString[i] = '0' + prec; /* add prec to ASCII code for '0' */
|
|
|
|
|
i += 1;
|
|
|
|
|
strcpy(&formatString[i], postfix);
|
|
|
|
|
i += strlen(postfix);
|
|
|
|
|
|
|
|
|
|
sprintf(buf, formatString, val);
|
|
|
|
|
|
|
|
|
|
return strlen(buf);
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-24 09:47:27 +00:00
|
|
|
/********************************************************************\
|
|
|
|
|
* returns GNC_T if the string is a number, possibly with whitespace
|
|
|
|
|
\********************************************************************/
|
|
|
|
|
|
|
|
|
|
gncBoolean
|
|
|
|
|
gnc_strisnum(const char *s)
|
|
|
|
|
{
|
|
|
|
|
if (s == NULL) return GNC_F;
|
|
|
|
|
if (*s == 0) return GNC_F;
|
|
|
|
|
|
|
|
|
|
while (*s && isspace(*s))
|
|
|
|
|
s++;
|
|
|
|
|
|
|
|
|
|
if (*s == 0) return GNC_F;
|
|
|
|
|
if (!isdigit(*s)) return GNC_F;
|
|
|
|
|
|
|
|
|
|
while (*s && isdigit(*s))
|
|
|
|
|
s++;
|
|
|
|
|
|
|
|
|
|
if (*s == 0) return GNC_T;
|
|
|
|
|
|
|
|
|
|
while (*s && isspace(*s))
|
|
|
|
|
s++;
|
|
|
|
|
|
|
|
|
|
if (*s == 0) return GNC_T;
|
|
|
|
|
|
|
|
|
|
return GNC_F;
|
|
|
|
|
}
|
|
|
|
|
|
1999-07-05 22:47:57 +00:00
|
|
|
/********************************************************************\
|
|
|
|
|
* stpcpy for those platforms that don't have it.
|
|
|
|
|
\********************************************************************/
|
|
|
|
|
|
1999-07-05 22:58:24 +00:00
|
|
|
#if !HAVE_STPCPY
|
1999-07-05 22:47:57 +00:00
|
|
|
char *
|
1999-11-22 05:11:30 +00:00
|
|
|
stpcpy (char *dest, const char *src)
|
1999-07-05 22:47:57 +00:00
|
|
|
{
|
|
|
|
|
strcpy(dest, src);
|
|
|
|
|
return(dest + strlen(src));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
|
1997-12-06 02:59:44 +00:00
|
|
|
/********************************************************************\
|
|
|
|
|
* currency & locale related stuff.
|
|
|
|
|
\********************************************************************/
|
|
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
static void
|
|
|
|
|
gnc_lconv_set(char **p_value, char *default_value)
|
|
|
|
|
{
|
|
|
|
|
char *value = *p_value;
|
|
|
|
|
|
|
|
|
|
if ((value == NULL) || (value[0] == 0))
|
|
|
|
|
*p_value = default_value;
|
|
|
|
|
}
|
|
|
|
|
|
2000-02-27 21:33:56 +00:00
|
|
|
static void
|
|
|
|
|
gnc_lconv_set_char(char *p_value, char default_value)
|
|
|
|
|
{
|
2000-05-03 19:55:36 +00:00
|
|
|
if ((p_value != NULL) && (*p_value == CHAR_MAX))
|
2000-02-27 21:33:56 +00:00
|
|
|
*p_value = default_value;
|
|
|
|
|
}
|
|
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
struct lconv *
|
|
|
|
|
gnc_localeconv()
|
|
|
|
|
{
|
|
|
|
|
static struct lconv lc;
|
|
|
|
|
static gncBoolean lc_set = GNC_F;
|
|
|
|
|
|
|
|
|
|
if (lc_set)
|
|
|
|
|
return &lc;
|
|
|
|
|
|
|
|
|
|
lc = *localeconv();
|
|
|
|
|
|
|
|
|
|
gnc_lconv_set(&lc.decimal_point, ".");
|
|
|
|
|
gnc_lconv_set(&lc.thousands_sep, ",");
|
2000-03-23 11:31:40 +00:00
|
|
|
gnc_lconv_set(&lc.int_curr_symbol, "USD ");
|
2000-01-17 21:39:42 +00:00
|
|
|
gnc_lconv_set(&lc.currency_symbol, CURRENCY_SYMBOL);
|
|
|
|
|
gnc_lconv_set(&lc.mon_decimal_point, ".");
|
|
|
|
|
gnc_lconv_set(&lc.mon_thousands_sep, ",");
|
|
|
|
|
gnc_lconv_set(&lc.negative_sign, "-");
|
1998-11-16 07:01:09 +00:00
|
|
|
|
2000-03-22 10:10:50 +00:00
|
|
|
gnc_lconv_set_char(&lc.frac_digits, 2);
|
|
|
|
|
gnc_lconv_set_char(&lc.int_frac_digits, 2);
|
2000-02-27 21:33:56 +00:00
|
|
|
gnc_lconv_set_char(&lc.p_cs_precedes, 1);
|
|
|
|
|
gnc_lconv_set_char(&lc.p_sep_by_space, 0);
|
|
|
|
|
gnc_lconv_set_char(&lc.n_cs_precedes, 1);
|
|
|
|
|
gnc_lconv_set_char(&lc.n_sep_by_space, 0);
|
|
|
|
|
gnc_lconv_set_char(&lc.p_sign_posn, 1);
|
|
|
|
|
gnc_lconv_set_char(&lc.n_sign_posn, 1);
|
|
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
lc_set = GNC_T;
|
1998-11-16 06:28:13 +00:00
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
return &lc;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-23 11:31:40 +00:00
|
|
|
char *
|
|
|
|
|
gnc_locale_default_currency()
|
|
|
|
|
{
|
|
|
|
|
static char currency[4];
|
|
|
|
|
gncBoolean got_it = GNC_F;
|
|
|
|
|
struct lconv *lc;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (got_it)
|
|
|
|
|
return currency;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
|
currency[i] = 0;
|
|
|
|
|
|
|
|
|
|
lc = gnc_localeconv();
|
|
|
|
|
|
|
|
|
|
strncpy(currency, lc->int_curr_symbol, 3);
|
|
|
|
|
|
|
|
|
|
got_it = GNC_T;
|
|
|
|
|
|
|
|
|
|
return currency;
|
|
|
|
|
}
|
|
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
/* Utility function for printing non-negative amounts */
|
1998-11-16 06:28:13 +00:00
|
|
|
static int
|
2000-01-17 21:39:42 +00:00
|
|
|
PrintAmt(char *buf, double val, int prec,
|
2000-02-27 21:33:56 +00:00
|
|
|
gncBoolean use_separators,
|
|
|
|
|
gncBoolean monetary,
|
|
|
|
|
int min_trailing_zeros)
|
1998-11-16 06:28:13 +00:00
|
|
|
{
|
2000-01-17 21:39:42 +00:00
|
|
|
int i, stringLength, numWholeDigits, sepCount;
|
|
|
|
|
struct lconv *lc = gnc_localeconv();
|
1999-12-31 00:05:41 +00:00
|
|
|
char tempBuf[50];
|
|
|
|
|
char *bufPtr = buf;
|
|
|
|
|
|
|
|
|
|
/* check if we're printing infinity */
|
|
|
|
|
if (!finite(val)) {
|
2000-01-17 21:39:42 +00:00
|
|
|
strcpy (buf, "inf");
|
|
|
|
|
return 3;
|
1999-12-31 00:05:41 +00:00
|
|
|
}
|
1998-11-16 06:28:13 +00:00
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
if (val < 0.0)
|
|
|
|
|
val = DABS(val);
|
|
|
|
|
|
1999-12-31 00:05:41 +00:00
|
|
|
util_fptostr(tempBuf, val, prec);
|
2000-01-17 21:39:42 +00:00
|
|
|
|
2000-02-27 21:33:56 +00:00
|
|
|
/* Here we strip off trailing decimal zeros per the argument. */
|
|
|
|
|
if (prec > 0)
|
|
|
|
|
{
|
|
|
|
|
int max_delete;
|
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
|
|
max_delete = prec - min_trailing_zeros;
|
|
|
|
|
|
|
|
|
|
p = tempBuf + strlen(tempBuf) - 1;
|
|
|
|
|
|
|
|
|
|
while ((*p == '0') && (max_delete > 0))
|
|
|
|
|
{
|
|
|
|
|
*p-- = 0;
|
|
|
|
|
max_delete--;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-23 11:31:40 +00:00
|
|
|
if (*p == '.')
|
2000-02-27 21:33:56 +00:00
|
|
|
*p = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
if (!use_separators)
|
|
|
|
|
{
|
2000-03-28 22:38:21 +00:00
|
|
|
/* fix up the decimal place, if there is one */
|
|
|
|
|
stringLength = strlen(tempBuf);
|
|
|
|
|
numWholeDigits = -1;
|
|
|
|
|
for (i = stringLength - 1; i >= 0; i--) {
|
|
|
|
|
if (tempBuf[i] == '.') {
|
|
|
|
|
if (monetary)
|
|
|
|
|
tempBuf[i] = lc->mon_decimal_point[0];
|
|
|
|
|
else
|
|
|
|
|
tempBuf[i] = lc->decimal_point[0];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
strcpy(buf, tempBuf);
|
|
|
|
|
}
|
1999-12-31 00:05:41 +00:00
|
|
|
else
|
2000-01-17 21:39:42 +00:00
|
|
|
{
|
|
|
|
|
/* Determine where the decimal place is, if there is one */
|
|
|
|
|
stringLength = strlen(tempBuf);
|
|
|
|
|
numWholeDigits = -1;
|
|
|
|
|
for (i = stringLength - 1; i >= 0; i--) {
|
2000-03-28 22:38:21 +00:00
|
|
|
if ((tempBuf[i] == '.') || (tempBuf[i] == lc->decimal_point[0])) {
|
2000-01-17 21:39:42 +00:00
|
|
|
numWholeDigits = i;
|
|
|
|
|
if (monetary)
|
|
|
|
|
tempBuf[i] = lc->mon_decimal_point[0];
|
2000-03-23 11:31:40 +00:00
|
|
|
else
|
|
|
|
|
tempBuf[i] = lc->decimal_point[0];
|
2000-01-17 21:39:42 +00:00
|
|
|
break;
|
1998-11-16 06:28:13 +00:00
|
|
|
}
|
2000-01-17 21:39:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (numWholeDigits < 0)
|
|
|
|
|
numWholeDigits = stringLength; /* Can't find decimal place, it's
|
|
|
|
|
* a whole number */
|
|
|
|
|
|
|
|
|
|
/* We now know the number of whole digits, now insert separators while
|
|
|
|
|
* copying them from the temp buffer to the destination */
|
|
|
|
|
bufPtr = buf;
|
|
|
|
|
for (i = 0; i < numWholeDigits; i++, bufPtr++) {
|
|
|
|
|
*bufPtr = tempBuf[i];
|
|
|
|
|
sepCount = (numWholeDigits - i) - 1;
|
|
|
|
|
if ((sepCount % 3 == 0) &&
|
|
|
|
|
(sepCount != 0))
|
|
|
|
|
{
|
|
|
|
|
bufPtr++;
|
|
|
|
|
if (monetary)
|
|
|
|
|
*bufPtr = lc->mon_thousands_sep[0];
|
|
|
|
|
else
|
|
|
|
|
*bufPtr = lc->thousands_sep[0];
|
1999-12-31 00:05:41 +00:00
|
|
|
}
|
2000-01-17 21:39:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
strcpy(bufPtr, &tempBuf[numWholeDigits]);
|
|
|
|
|
} /* endif */
|
1998-11-16 06:28:13 +00:00
|
|
|
|
1999-12-31 00:05:41 +00:00
|
|
|
return strlen(buf);
|
1998-11-16 06:28:13 +00:00
|
|
|
}
|
|
|
|
|
|
1999-01-30 21:22:13 +00:00
|
|
|
int
|
2000-05-16 23:48:19 +00:00
|
|
|
xaccSPrintAmountGeneral (char * bufp, double val,
|
|
|
|
|
GNCPrintAmountFlags flags,
|
|
|
|
|
int precision,
|
|
|
|
|
int min_trailing_zeros,
|
|
|
|
|
const char *curr_sym)
|
1997-12-06 02:59:44 +00:00
|
|
|
{
|
2000-01-17 21:39:42 +00:00
|
|
|
struct lconv *lc;
|
|
|
|
|
|
|
|
|
|
char *orig_bufp = bufp;
|
2000-04-24 23:20:36 +00:00
|
|
|
const char *currency_symbol;
|
|
|
|
|
const char *sign;
|
2000-01-17 21:39:42 +00:00
|
|
|
|
|
|
|
|
char cs_precedes;
|
|
|
|
|
char sep_by_space;
|
|
|
|
|
char sign_posn;
|
|
|
|
|
|
|
|
|
|
gncBoolean print_sign = GNC_T;
|
1999-01-30 21:22:13 +00:00
|
|
|
|
|
|
|
|
if (!bufp) return 0;
|
1998-11-16 06:28:13 +00:00
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
lc = gnc_localeconv();
|
|
|
|
|
|
1999-11-22 05:09:40 +00:00
|
|
|
if (DEQ(val, 0.0))
|
|
|
|
|
val = 0.0;
|
|
|
|
|
|
2000-05-16 23:48:19 +00:00
|
|
|
if (flags & PRTSHR)
|
2000-01-17 21:39:42 +00:00
|
|
|
{
|
|
|
|
|
currency_symbol = "shrs";
|
|
|
|
|
cs_precedes = 0; /* currency symbol follows amount */
|
|
|
|
|
sep_by_space = 1; /* they are separated by a space */
|
|
|
|
|
}
|
2000-05-16 23:48:19 +00:00
|
|
|
else if (flags & PRTEUR)
|
2000-04-24 21:28:25 +00:00
|
|
|
{
|
|
|
|
|
currency_symbol = "EUR";
|
|
|
|
|
cs_precedes = 1; /* currency symbol precedes amount */
|
|
|
|
|
sep_by_space = 0; /* they are not separated by a space */
|
|
|
|
|
}
|
2000-01-17 21:39:42 +00:00
|
|
|
else
|
|
|
|
|
{
|
2000-04-24 21:28:25 +00:00
|
|
|
if (curr_sym == NULL)
|
2000-04-21 10:49:15 +00:00
|
|
|
{
|
|
|
|
|
currency_symbol = lc->currency_symbol;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
currency_symbol = curr_sym;
|
|
|
|
|
}
|
2000-04-24 21:28:25 +00:00
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
if (val < 0.0)
|
|
|
|
|
{
|
|
|
|
|
cs_precedes = lc->n_cs_precedes;
|
|
|
|
|
sep_by_space = lc->n_sep_by_space;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cs_precedes = lc->p_cs_precedes;
|
|
|
|
|
sep_by_space = lc->p_sep_by_space;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (val < 0.0)
|
|
|
|
|
{
|
|
|
|
|
sign = lc->negative_sign;
|
|
|
|
|
sign_posn = lc->n_sign_posn;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sign = lc->positive_sign;
|
|
|
|
|
sign_posn = lc->p_sign_posn;
|
|
|
|
|
}
|
1999-12-31 00:05:41 +00:00
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
if ((val == 0.0) || (sign == NULL) || (sign[0] == 0))
|
|
|
|
|
print_sign = GNC_F;
|
|
|
|
|
|
|
|
|
|
/* See if we print sign now */
|
|
|
|
|
if (print_sign && (sign_posn == 1))
|
|
|
|
|
bufp = stpcpy(bufp, sign);
|
|
|
|
|
|
|
|
|
|
/* Now see if we print currency */
|
|
|
|
|
if (cs_precedes)
|
|
|
|
|
{
|
|
|
|
|
/* See if we print sign now */
|
|
|
|
|
if (print_sign && (sign_posn == 3))
|
|
|
|
|
bufp = stpcpy(bufp, sign);
|
|
|
|
|
|
2000-05-16 23:48:19 +00:00
|
|
|
if (flags & PRTSYM)
|
2000-01-17 21:39:42 +00:00
|
|
|
{
|
|
|
|
|
bufp = stpcpy(bufp, currency_symbol);
|
|
|
|
|
if (sep_by_space)
|
|
|
|
|
bufp = stpcpy(bufp, " ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See if we print sign now */
|
|
|
|
|
if (print_sign && (sign_posn == 4))
|
|
|
|
|
bufp = stpcpy(bufp, sign);
|
1997-12-06 02:59:44 +00:00
|
|
|
}
|
|
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
/* Now see if we print parentheses */
|
2000-02-27 21:33:56 +00:00
|
|
|
if (print_sign && (sign_posn == 0))
|
2000-01-17 21:39:42 +00:00
|
|
|
bufp = stpcpy(bufp, "(");
|
|
|
|
|
|
|
|
|
|
/* Now print the value */
|
2000-05-16 23:48:19 +00:00
|
|
|
bufp += PrintAmt(bufp, DABS(val), precision, flags & PRTSEP,
|
|
|
|
|
!(flags & PRTNMN), min_trailing_zeros);
|
2000-01-17 21:39:42 +00:00
|
|
|
|
|
|
|
|
/* Now see if we print parentheses */
|
2000-02-27 21:33:56 +00:00
|
|
|
if (print_sign && (sign_posn == 0))
|
2000-01-17 21:39:42 +00:00
|
|
|
bufp = stpcpy(bufp, ")");
|
|
|
|
|
|
|
|
|
|
/* Now see if we print currency */
|
|
|
|
|
if (!cs_precedes)
|
|
|
|
|
{
|
|
|
|
|
/* See if we print sign now */
|
|
|
|
|
if (print_sign && (sign_posn == 3))
|
|
|
|
|
bufp = stpcpy(bufp, sign);
|
|
|
|
|
|
2000-05-16 23:48:19 +00:00
|
|
|
if (flags & PRTSYM)
|
2000-01-17 21:39:42 +00:00
|
|
|
{
|
|
|
|
|
if (sep_by_space)
|
|
|
|
|
bufp = stpcpy(bufp, " ");
|
|
|
|
|
bufp = stpcpy(bufp, currency_symbol);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See if we print sign now */
|
|
|
|
|
if (print_sign && (sign_posn == 4))
|
|
|
|
|
bufp = stpcpy(bufp, sign);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See if we print sign now */
|
|
|
|
|
if (print_sign && (sign_posn == 2))
|
|
|
|
|
bufp = stpcpy(bufp, sign);
|
|
|
|
|
|
1999-01-30 21:22:13 +00:00
|
|
|
/* return length of printed string */
|
2000-01-17 21:39:42 +00:00
|
|
|
return (bufp - orig_bufp);
|
1999-01-30 21:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
2000-02-27 21:33:56 +00:00
|
|
|
int
|
2000-05-16 23:48:19 +00:00
|
|
|
xaccSPrintAmount (char * bufp, double val, GNCPrintAmountFlags flags,
|
|
|
|
|
const char *curr_code)
|
2000-02-27 21:33:56 +00:00
|
|
|
{
|
2000-04-24 21:28:25 +00:00
|
|
|
struct lconv *lc;
|
2000-03-22 10:10:50 +00:00
|
|
|
int precision;
|
|
|
|
|
int min_trailing_zeros;
|
2000-05-03 09:56:04 +00:00
|
|
|
char curr_sym[5];
|
2000-02-27 21:33:56 +00:00
|
|
|
|
2000-04-24 21:28:25 +00:00
|
|
|
lc = gnc_localeconv();
|
|
|
|
|
|
|
|
|
|
if (curr_code && (strncmp(curr_code, lc->int_curr_symbol, 3) == 0))
|
|
|
|
|
curr_code = NULL;
|
2000-05-03 09:56:04 +00:00
|
|
|
else if (curr_code)
|
|
|
|
|
{
|
|
|
|
|
strncpy(curr_sym, curr_code, 3);
|
|
|
|
|
curr_sym[3] = '\0';
|
|
|
|
|
strcat(curr_sym, " ");
|
|
|
|
|
curr_code = curr_sym;
|
|
|
|
|
}
|
2000-04-24 21:28:25 +00:00
|
|
|
|
2000-05-03 09:56:04 +00:00
|
|
|
if (curr_code && (strncmp(curr_code, "EUR", 3) == 0))
|
2000-05-16 23:48:19 +00:00
|
|
|
flags |= PRTEUR;
|
2000-04-24 21:28:25 +00:00
|
|
|
|
2000-05-16 23:48:19 +00:00
|
|
|
if (flags & PRTCUR)
|
|
|
|
|
{
|
|
|
|
|
precision = 5;
|
|
|
|
|
min_trailing_zeros = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (flags & PRTSHR)
|
2000-02-27 21:33:56 +00:00
|
|
|
{
|
|
|
|
|
precision = 4;
|
|
|
|
|
min_trailing_zeros = 0;
|
|
|
|
|
}
|
2000-05-16 23:48:19 +00:00
|
|
|
else if (flags & PRTEUR)
|
2000-04-24 21:28:25 +00:00
|
|
|
{
|
|
|
|
|
precision = 2;
|
|
|
|
|
min_trailing_zeros = 2;
|
|
|
|
|
}
|
2000-03-22 10:10:50 +00:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
precision = lc->frac_digits;
|
|
|
|
|
min_trailing_zeros = lc->frac_digits;
|
|
|
|
|
}
|
2000-02-27 21:33:56 +00:00
|
|
|
|
2000-05-16 23:48:19 +00:00
|
|
|
return xaccSPrintAmountGeneral(bufp, val, flags, precision,
|
2000-04-24 21:28:25 +00:00
|
|
|
min_trailing_zeros, curr_code);
|
2000-02-27 21:33:56 +00:00
|
|
|
}
|
|
|
|
|
|
2000-03-09 08:04:03 +00:00
|
|
|
char *
|
2000-05-16 23:48:19 +00:00
|
|
|
xaccPrintAmount (double val, GNCPrintAmountFlags flags, const char *curr_code)
|
1999-01-30 21:22:13 +00:00
|
|
|
{
|
|
|
|
|
/* hack alert -- this is not thread safe ... */
|
|
|
|
|
static char buf[BUFSIZE];
|
|
|
|
|
|
2000-05-16 23:48:19 +00:00
|
|
|
xaccSPrintAmount (buf, val, flags, curr_code);
|
1999-01-30 21:22:13 +00:00
|
|
|
|
|
|
|
|
/* its OK to return buf, since we declared it static */
|
1997-12-06 02:59:44 +00:00
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-09 08:04:03 +00:00
|
|
|
char *
|
|
|
|
|
xaccPrintAmountArgs (double val, gncBoolean print_currency_symbol,
|
2000-04-24 21:28:25 +00:00
|
|
|
gncBoolean print_separators, gncBoolean is_shares_value,
|
|
|
|
|
const char *curr_code)
|
2000-03-09 08:04:03 +00:00
|
|
|
{
|
2000-05-16 23:48:19 +00:00
|
|
|
GNCPrintAmountFlags flags = 0;
|
2000-03-09 08:04:03 +00:00
|
|
|
|
2000-05-16 23:48:19 +00:00
|
|
|
if (print_currency_symbol) flags |= PRTSYM;
|
|
|
|
|
if (print_separators) flags |= PRTSEP;
|
|
|
|
|
if (is_shares_value) flags |= PRTSHR;
|
2000-03-09 08:04:03 +00:00
|
|
|
|
2000-05-16 23:48:19 +00:00
|
|
|
return xaccPrintAmount(val, flags, curr_code);
|
2000-03-09 08:04:03 +00:00
|
|
|
}
|
|
|
|
|
|
1998-02-02 23:25:44 +00:00
|
|
|
|
|
|
|
|
/********************************************************************\
|
2000-01-17 21:39:42 +00:00
|
|
|
* xaccParseAmount *
|
|
|
|
|
* parses amount strings using locale data *
|
|
|
|
|
* *
|
|
|
|
|
* Args: str -- pointer to string rep of num *
|
|
|
|
|
monetary -- boolean indicating whether value is monetary *
|
|
|
|
|
* Return: double -- the parsed amount *
|
|
|
|
|
\********************************************************************/
|
|
|
|
|
|
|
|
|
|
double xaccParseAmount (const char * instr, gncBoolean monetary)
|
|
|
|
|
{
|
|
|
|
|
struct lconv *lc = gnc_localeconv();
|
2000-05-19 10:27:33 +00:00
|
|
|
gncBoolean isneg = GNC_F;
|
2000-01-17 21:39:42 +00:00
|
|
|
char *mstr, *str, *tok;
|
|
|
|
|
double amount = 0.0;
|
|
|
|
|
char negative_sign;
|
|
|
|
|
char thousands_sep;
|
|
|
|
|
char decimal_point;
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
if (!instr) return 0.0;
|
2000-05-19 10:27:33 +00:00
|
|
|
if (*instr == '\0') return 0.0;
|
|
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
mstr = strdup (instr);
|
|
|
|
|
str = mstr;
|
|
|
|
|
|
|
|
|
|
negative_sign = lc->negative_sign[0];
|
|
|
|
|
if (monetary)
|
|
|
|
|
{
|
|
|
|
|
thousands_sep = lc->mon_thousands_sep[0];
|
|
|
|
|
decimal_point = lc->mon_decimal_point[0];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
thousands_sep = lc->thousands_sep[0];
|
|
|
|
|
decimal_point = lc->decimal_point[0];
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-19 10:27:33 +00:00
|
|
|
/* strip off garbage at the beginning of the line */
|
|
|
|
|
while (*str != '\0')
|
|
|
|
|
{
|
|
|
|
|
switch (*str)
|
|
|
|
|
{
|
|
|
|
|
case '\r':
|
|
|
|
|
case '\n':
|
|
|
|
|
case ' ':
|
|
|
|
|
case '\t':
|
|
|
|
|
str++;
|
|
|
|
|
continue;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* look for a negative sign */
|
|
|
|
|
if (*str == negative_sign) {
|
|
|
|
|
isneg = GNC_T;
|
|
|
|
|
str++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (*str == '\0') return 0.0;
|
|
|
|
|
|
|
|
|
|
/* go to end of string */
|
|
|
|
|
for (tok = str; *tok != '\0'; tok++)
|
|
|
|
|
;
|
|
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
/* strip off garbage at end of the line */
|
2000-05-19 10:27:33 +00:00
|
|
|
while (--tok != str)
|
|
|
|
|
{
|
|
|
|
|
switch (*tok)
|
|
|
|
|
{
|
|
|
|
|
case '\r':
|
|
|
|
|
case '\n':
|
|
|
|
|
case ' ':
|
|
|
|
|
case '\t':
|
|
|
|
|
continue;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2000-01-17 21:39:42 +00:00
|
|
|
|
2000-05-19 10:27:33 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* look for a negative sign at the end, some locales allow it,
|
|
|
|
|
* we'll just allow it everywhere. */
|
|
|
|
|
if (*tok == negative_sign) {
|
|
|
|
|
isneg = GNC_T;
|
|
|
|
|
*tok = '\0';
|
2000-01-17 21:39:42 +00:00
|
|
|
}
|
|
|
|
|
|
2000-05-19 10:27:33 +00:00
|
|
|
if (*str == '\0') return 0.0;
|
|
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
/* remove thousands separator */
|
|
|
|
|
tok = strchr (str, thousands_sep);
|
|
|
|
|
while (tok) {
|
2000-05-19 10:27:33 +00:00
|
|
|
*tok = '\0';
|
2000-01-17 21:39:42 +00:00
|
|
|
amount *= 1000.0;
|
|
|
|
|
amount += ((double) (1000 * atoi (str)));
|
|
|
|
|
str = tok + sizeof(char);
|
|
|
|
|
tok = strchr (str, thousands_sep);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* search for a decimal point */
|
|
|
|
|
tok = strchr (str, decimal_point);
|
|
|
|
|
if (tok) {
|
2000-05-19 10:27:33 +00:00
|
|
|
*tok = '\0';
|
2000-01-17 21:39:42 +00:00
|
|
|
amount += ((double) (atoi (str)));
|
|
|
|
|
str = tok + sizeof(char);
|
|
|
|
|
|
|
|
|
|
/* if there is anything trailing the decimal
|
|
|
|
|
* point, convert it */
|
|
|
|
|
if (str[0]) {
|
|
|
|
|
|
|
|
|
|
/* strip off garbage at end of the line */
|
|
|
|
|
tok = strchr (str, ' ');
|
2000-05-19 10:27:33 +00:00
|
|
|
if (tok) *tok = '\0';
|
2000-06-21 09:48:39 +00:00
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
/* adjust for number of decimal places */
|
|
|
|
|
len = strlen(str);
|
2000-06-21 09:48:39 +00:00
|
|
|
|
|
|
|
|
if (len > 8)
|
|
|
|
|
{
|
|
|
|
|
str[8] = '\0';
|
|
|
|
|
len = 8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (8 == len) {
|
|
|
|
|
amount += 0.00000001 * ((double) atoi (str));
|
|
|
|
|
} else
|
|
|
|
|
if (7 == len) {
|
|
|
|
|
amount += 0.0000001 * ((double) atoi (str));
|
|
|
|
|
} else
|
2000-01-17 21:39:42 +00:00
|
|
|
if (6 == len) {
|
|
|
|
|
amount += 0.000001 * ((double) atoi (str));
|
|
|
|
|
} else
|
|
|
|
|
if (5 == len) {
|
|
|
|
|
amount += 0.00001 * ((double) atoi (str));
|
|
|
|
|
} else
|
|
|
|
|
if (4 == len) {
|
|
|
|
|
amount += 0.0001 * ((double) atoi (str));
|
|
|
|
|
} else
|
|
|
|
|
if (3 == len) {
|
|
|
|
|
amount += 0.001 * ((double) atoi (str));
|
|
|
|
|
} else
|
|
|
|
|
if (2 == len) {
|
|
|
|
|
amount += 0.01 * ((double) atoi (str));
|
|
|
|
|
} else
|
|
|
|
|
if (1 == len) {
|
|
|
|
|
amount += 0.1 * ((double) atoi (str));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
amount += ((double) (atoi (str)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isneg) amount = -amount;
|
|
|
|
|
|
|
|
|
|
free (mstr);
|
|
|
|
|
return amount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1997-11-22 10:42:02 +00:00
|
|
|
/************************* END OF FILE ******************************\
|
|
|
|
|
\********************************************************************/
|