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 *
|
1998-10-18 21:13:40 +00:00
|
|
|
* Copyright (C) 1997, 1998 Linas Vepstas *
|
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*
|
|
|
|
|
* along with this program; if not, write to the Free Software *
|
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
|
|
|
|
|
* *
|
|
|
|
|
* Author: Rob Clark *
|
|
|
|
|
* Internet: rclark@cs.hmc.edu *
|
|
|
|
|
* Address: 609 8th Street *
|
|
|
|
|
* Huntington Beach, CA 92648-4632 *
|
|
|
|
|
\********************************************************************/
|
|
|
|
|
|
1998-02-02 23:54:44 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
|
1997-11-30 02:39:58 +00:00
|
|
|
#include "config.h"
|
1998-01-28 05:55:07 +00:00
|
|
|
#include "messages.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 *********************************************************/
|
1998-12-06 21:48:50 +00:00
|
|
|
/*
|
|
|
|
|
0 == disable all messages
|
|
|
|
|
1 == enble only error messages
|
|
|
|
|
2 == print warnings
|
|
|
|
|
3 == print info messages
|
|
|
|
|
4 == print debugging messages
|
|
|
|
|
*/
|
1998-12-06 07:43:14 +00:00
|
|
|
int loglevel[MODULE_MAX] =
|
|
|
|
|
{0, /* DUMMY */
|
1998-12-06 21:48:50 +00:00
|
|
|
2, /* ENGINE */
|
|
|
|
|
2, /* IO */
|
1998-12-06 08:26:10 +00:00
|
|
|
2, /* REGISTER */
|
1998-12-06 21:48:50 +00:00
|
|
|
2, /* LEDGER */
|
|
|
|
|
2, /* GUI */
|
1998-12-14 07:45:39 +00:00
|
|
|
4, /* SCRUB */
|
1999-01-20 06:18:17 +00:00
|
|
|
4, /* GTK_REG */
|
1998-12-06 07:43:14 +00:00
|
|
|
};
|
1997-11-22 03:41:59 +00:00
|
|
|
|
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__)
|
|
|
|
|
|
|
|
|
|
#if !HAVE_MALLOC_USABLE_SIZE
|
|
|
|
|
#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 )
|
|
|
|
|
{
|
|
|
|
|
core -= malloc_usable_size(ptr);
|
|
|
|
|
free(ptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void*
|
|
|
|
|
dmalloc( size_t size )
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t
|
|
|
|
|
dcoresize(void)
|
|
|
|
|
{
|
|
|
|
|
return core;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
1998-09-21 03:42:58 +00:00
|
|
|
/********************************************************************\
|
|
|
|
|
\********************************************************************/
|
|
|
|
|
|
|
|
|
|
int
|
1998-10-10 05:38:48 +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 {
|
|
|
|
|
buf[places-1-i] = 0x41-10+broke[i]; /* ascii capaital A */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
buf[places] = 0x0;
|
|
|
|
|
|
|
|
|
|
return strdup (buf);
|
|
|
|
|
}
|
|
|
|
|
|
1997-12-06 02:59:44 +00:00
|
|
|
/********************************************************************\
|
|
|
|
|
* currency & locale related stuff.
|
|
|
|
|
* first attempt at internationalization i18n of currency amounts
|
1997-12-06 03:26:12 +00:00
|
|
|
* In the long run, amounts should be printed with punctuation
|
|
|
|
|
* returned from the localconv() subroutine
|
1997-12-06 02:59:44 +00:00
|
|
|
\********************************************************************/
|
|
|
|
|
|
1998-11-16 07:01:09 +00:00
|
|
|
/* The PrtAmtComma() routine prints a comma-separated currency value */
|
|
|
|
|
|
1998-11-16 06:28:13 +00:00
|
|
|
/* THOU_SEP is a comma in U.S. but a period in some parts of Europe */
|
|
|
|
|
/* CENT_SEP is a period in U.S. but a comma in some parts of Europe */
|
|
|
|
|
#define THOU_SEP ','
|
|
|
|
|
#define CENT_SEP '.'
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
PrtAmtComma (char * buf, double val, int prec)
|
|
|
|
|
{
|
|
|
|
|
int i, ival, ncommas = 0;
|
|
|
|
|
double tmp, amt=0.0;
|
|
|
|
|
char *start = buf;
|
|
|
|
|
|
|
|
|
|
/* count number of commas */
|
|
|
|
|
tmp = val;
|
|
|
|
|
while (tmp > 1000.0) {
|
|
|
|
|
tmp *= 0.001;
|
|
|
|
|
ncommas ++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* print digits in groups of three, seperated by commas */
|
|
|
|
|
for (i=ncommas; i>=0; i--) {
|
|
|
|
|
int j;
|
|
|
|
|
|
|
|
|
|
amt *= 1000.0;
|
|
|
|
|
tmp = val;
|
1998-11-16 07:01:09 +00:00
|
|
|
for (j=i; j>0; j--) tmp *= 0.001;
|
1998-11-16 06:28:13 +00:00
|
|
|
tmp -= amt;
|
|
|
|
|
ival = tmp;
|
|
|
|
|
if (i !=ncommas) {
|
|
|
|
|
buf += sprintf (buf, "%03d", ival);
|
|
|
|
|
} else {
|
|
|
|
|
buf += sprintf (buf, "%d", ival);
|
|
|
|
|
}
|
|
|
|
|
*buf = THOU_SEP; buf++;
|
|
|
|
|
amt += ival;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* place decimal point */
|
|
|
|
|
buf --; *buf = CENT_SEP; buf++;
|
|
|
|
|
|
1998-11-16 07:01:09 +00:00
|
|
|
/* print two or three decimal places */
|
1998-11-16 06:28:13 +00:00
|
|
|
if (3 == prec) {
|
1998-11-16 07:01:09 +00:00
|
|
|
ival = 0.5 + 1000.0 * (val-amt);
|
1998-11-16 06:28:13 +00:00
|
|
|
buf += sprintf (buf, "%03d", ival);
|
|
|
|
|
} else {
|
1998-11-16 07:01:09 +00:00
|
|
|
ival = 0.5 + 100.0 * (val-amt);
|
1998-11-16 06:28:13 +00:00
|
|
|
buf += sprintf (buf, "%02d", ival);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (buf-start);
|
|
|
|
|
}
|
|
|
|
|
|
1999-01-30 21:22:13 +00:00
|
|
|
int
|
|
|
|
|
xaccSPrintAmount (char * bufp, double val, short shrs)
|
1997-12-06 02:59:44 +00:00
|
|
|
{
|
1999-01-30 21:22:13 +00:00
|
|
|
char * orig_bufp = bufp;
|
|
|
|
|
|
|
|
|
|
if (!bufp) return 0;
|
1998-11-16 06:28:13 +00:00
|
|
|
|
|
|
|
|
if (0.0 > val) {
|
1999-01-30 21:22:13 +00:00
|
|
|
bufp[0] = '-';
|
1998-11-16 06:28:13 +00:00
|
|
|
bufp ++;
|
1998-11-16 07:01:09 +00:00
|
|
|
val = -val;
|
1998-11-16 06:28:13 +00:00
|
|
|
}
|
1997-12-06 02:59:44 +00:00
|
|
|
|
|
|
|
|
if (shrs & PRTSHR) {
|
1998-11-16 06:28:13 +00:00
|
|
|
if (shrs & PRTSEP) {
|
|
|
|
|
bufp += PrtAmtComma (bufp, val, 3);
|
1997-12-06 02:59:44 +00:00
|
|
|
} else {
|
1998-11-16 06:28:13 +00:00
|
|
|
bufp += sprintf( bufp, "%.3f", val );
|
|
|
|
|
}
|
|
|
|
|
if (shrs & PRTSYM) {
|
1999-01-30 21:22:13 +00:00
|
|
|
/* stpcpy returns pointer to end of string, not like strcpy */
|
|
|
|
|
bufp = stpcpy (bufp, " shrs");
|
1997-12-06 02:59:44 +00:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
if (shrs & PRTSYM) {
|
1998-11-16 07:01:09 +00:00
|
|
|
bufp += sprintf( bufp, "%s ", CURRENCY_SYMBOL);
|
1998-11-16 06:28:13 +00:00
|
|
|
}
|
|
|
|
|
if (shrs & PRTSEP) {
|
1999-01-30 21:22:13 +00:00
|
|
|
bufp += PrtAmtComma (bufp, val, 2);
|
1997-12-06 02:59:44 +00:00
|
|
|
} else {
|
1999-01-30 21:22:13 +00:00
|
|
|
bufp += sprintf( bufp, "%.2f", val );
|
1997-12-06 02:59:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-01-30 21:22:13 +00:00
|
|
|
/* return length of printed string */
|
|
|
|
|
return (bufp-orig_bufp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
xaccPrintAmount (double val, short shrs)
|
|
|
|
|
{
|
|
|
|
|
/* hack alert -- this is not thread safe ... */
|
|
|
|
|
static char buf[BUFSIZE];
|
|
|
|
|
|
|
|
|
|
xaccSPrintAmount (buf, val, shrs);
|
|
|
|
|
|
|
|
|
|
/* its OK to return buf, since we declared it static */
|
1997-12-06 02:59:44 +00:00
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
1998-02-02 23:25:44 +00:00
|
|
|
|
|
|
|
|
/********************************************************************\
|
|
|
|
|
* xaccParseUSAmount *
|
|
|
|
|
* parses U.S. style monetary strings *
|
|
|
|
|
* (strings of the form DDD,DDD,DDD.CC *
|
|
|
|
|
* *
|
|
|
|
|
* Args: str -- pointer to string rep of sum *
|
|
|
|
|
* Return: double -- the parsed amount *
|
1998-02-02 23:28:11 +00:00
|
|
|
*
|
|
|
|
|
* Note: be careful changing this algorithm. The Quicken-file-format
|
|
|
|
|
* parser depends a lot on the ability of this routine to do what it's
|
|
|
|
|
* doing. Don't break it!
|
1998-02-02 23:25:44 +00:00
|
|
|
\********************************************************************/
|
|
|
|
|
|
1998-03-03 07:54:15 +00:00
|
|
|
/* The following tokens are used to define the US-style monetary
|
|
|
|
|
* strings. With a bit of cleverness, it should be possible to modify
|
|
|
|
|
* these to handle various international styles ... maybe ... */
|
|
|
|
|
|
1998-02-02 23:54:44 +00:00
|
|
|
#define MINUS_SIGN '-'
|
|
|
|
|
#define K_SEP ',' /* thousands separator */
|
|
|
|
|
#define DEC_SEP '.' /* decimal point */
|
|
|
|
|
|
|
|
|
|
double xaccParseUSAmount (const char * instr)
|
1998-02-02 23:25:44 +00:00
|
|
|
{
|
1998-02-02 23:54:44 +00:00
|
|
|
char *mstr, *str, *tok;
|
1998-02-02 23:25:44 +00:00
|
|
|
double dollars = 0.0;
|
|
|
|
|
int len;
|
|
|
|
|
int isneg = 0;
|
|
|
|
|
|
1998-02-02 23:54:44 +00:00
|
|
|
if (!instr) return 0.0;
|
|
|
|
|
mstr = strdup (instr);
|
|
|
|
|
str = mstr;
|
1998-02-02 23:25:44 +00:00
|
|
|
|
1998-02-02 23:54:44 +00:00
|
|
|
/* strip off garbage at end of the line */
|
|
|
|
|
tok = strchr (str, '\r');
|
|
|
|
|
if (tok) *tok = 0x0;
|
|
|
|
|
tok = strchr (str, '\n');
|
|
|
|
|
if (tok) *tok = 0x0;
|
1998-02-02 23:25:44 +00:00
|
|
|
|
1998-02-02 23:54:44 +00:00
|
|
|
/* search for a minus sign */
|
|
|
|
|
tok = strchr (str, MINUS_SIGN);
|
1998-02-02 23:25:44 +00:00
|
|
|
if (tok) {
|
1998-02-02 23:54:44 +00:00
|
|
|
isneg = 1;
|
1998-02-02 23:25:44 +00:00
|
|
|
str = tok+sizeof(char);
|
|
|
|
|
}
|
|
|
|
|
|
1998-02-02 23:54:44 +00:00
|
|
|
/* remove comma's */
|
|
|
|
|
tok = strchr (str, K_SEP);
|
|
|
|
|
while (tok) {
|
1998-02-02 23:25:44 +00:00
|
|
|
*tok = 0x0;
|
|
|
|
|
dollars *= 1000.0;
|
|
|
|
|
dollars += ((double) (1000 * atoi (str)));
|
|
|
|
|
str = tok+sizeof(char);
|
1998-03-03 07:54:15 +00:00
|
|
|
tok = strchr (str, K_SEP);
|
1998-02-02 23:25:44 +00:00
|
|
|
}
|
|
|
|
|
|
1998-02-02 23:54:44 +00:00
|
|
|
/* search for a decimal point */
|
|
|
|
|
tok = strchr (str, DEC_SEP);
|
1998-02-02 23:25:44 +00:00
|
|
|
if (tok) {
|
|
|
|
|
*tok = 0x0;
|
|
|
|
|
dollars += ((double) (atoi (str)));
|
|
|
|
|
str = tok+sizeof(char);
|
|
|
|
|
|
1998-02-02 23:54:44 +00:00
|
|
|
/* if there is anything trailing the decimal
|
|
|
|
|
* point, convert it */
|
|
|
|
|
if (str[0]) {
|
|
|
|
|
|
|
|
|
|
/* strip off garbage at end of the line */
|
|
|
|
|
tok = strchr (str, ' ');
|
|
|
|
|
if (tok) *tok = 0x0;
|
|
|
|
|
|
|
|
|
|
/* adjust for number of decimal places */
|
|
|
|
|
len = strlen(str);
|
|
|
|
|
if (6 == len) {
|
|
|
|
|
dollars += 0.000001 * ((double) atoi (str));
|
|
|
|
|
} else
|
|
|
|
|
if (5 == len) {
|
|
|
|
|
dollars += 0.00001 * ((double) atoi (str));
|
|
|
|
|
} else
|
|
|
|
|
if (4 == len) {
|
|
|
|
|
dollars += 0.0001 * ((double) atoi (str));
|
|
|
|
|
} else
|
|
|
|
|
if (3 == len) {
|
|
|
|
|
dollars += 0.001 * ((double) atoi (str));
|
|
|
|
|
} else
|
|
|
|
|
if (2 == len) {
|
|
|
|
|
dollars += 0.01 * ((double) atoi (str));
|
|
|
|
|
} else
|
|
|
|
|
if (1 == len) {
|
|
|
|
|
dollars += 0.1 * ((double) atoi (str));
|
|
|
|
|
}
|
1998-02-02 23:25:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
dollars += ((double) (atoi (str)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isneg) dollars = -dollars;
|
|
|
|
|
|
1998-02-02 23:54:44 +00:00
|
|
|
free (mstr);
|
1998-02-02 23:25:44 +00:00
|
|
|
return dollars;
|
|
|
|
|
}
|
|
|
|
|
|
1997-11-22 10:42:02 +00:00
|
|
|
/************************* END OF FILE ******************************\
|
|
|
|
|
\********************************************************************/
|