Re-indentation of source code, first try, only in the libqof directory so far.

This also strips trailing whitespaces from lines where they existed.
This re-indentation was done using astyle-1.23 using the following options:

astyle --indent=spaces=4 --brackets=break --pad-oper

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@18319 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Christian Stimming 2009-09-18 19:40:57 +00:00
parent 49d62ad506
commit c5077e259f
63 changed files with 14035 additions and 12865 deletions

View File

@ -1,4 +1,4 @@
/*
/*
* gnc-date-p.h
*
* Copyright (C) 2007 Andreas Koehler <andi5.py@gmx.net>
@ -45,10 +45,11 @@ gchar *qof_formatted_time_to_utf8(const gchar *locale_string);
#ifdef G_OS_WIN32
typedef enum {
QOF_WIN32_PICTURE_DATE,
QOF_WIN32_PICTURE_TIME,
QOF_WIN32_PICTURE_DATETIME
typedef enum
{
QOF_WIN32_PICTURE_DATE,
QOF_WIN32_PICTURE_TIME,
QOF_WIN32_PICTURE_DATETIME
} QofWin32Picture;
/** Get a strftime/strptime format specification for date, time or date and time,

File diff suppressed because it is too large Load Diff

View File

@ -24,46 +24,46 @@
* Boston, MA 02110-1301, USA gnu@gnu.org *
\********************************************************************/
/** @addtogroup Date
Utility functions to handle date and time (adjusting, getting
the current date, printing the date and time, etc.)
Utility functions to handle date and time (adjusting, getting
the current date, printing the date and time, etc.)
Overall, this file is quite a mess. Note, however, that other
Overall, this file is quite a mess. Note, however, that other
applications, besides just GnuCash, use this file. In particular,
GnoTime (gttr.sourcefore.net) uses this file, and this file is
GnoTime (gttr.sourcefore.net) uses this file, and this file is
formally a part of QOF (qof.sourceforge.net).
An important note about time-keeping: The general goal of any
An important note about time-keeping: The general goal of any
program that works with numeric time values SHOULD BE to always
stores and use UNIVERSAL TIME internally. Universal time is the
'one true time' that is independent of one's location on planet
Earth. It is measured in seconds from midnight January 1, 1970
in localtime-Grenwich (GMT). If one wants to display the local
time, then the display-print routine should make all final
time, then the display-print routine should make all final
tweaks to print the local time. The local time *must not* be
kept as a numeric value anywhere in the program. If one wants
to parse a user's input string as if it were local time, then
the output of the parse routine MUST BE universal time.
A sane program must never ever store (to file or db) a time
that is not Universal Time. Break these rules, and you will
the output of the parse routine MUST BE universal time.
A sane program must never ever store (to file or db) a time
that is not Universal Time. Break these rules, and you will
rue the day...
\warning HACK ALERT -- the scan and print routines should probably be moved
to somewhere else. The engine really isn't involved with things
like printing formats. This is needed mostly by the GUI and so on.
If a file-io backend needs date handling, it should do it itself,
instead of depending on the routines here.
instead of depending on the routines here.
(to be renamed qofdate.h in libqof2.)
@author Copyright (C) 1997 Robin D. Clark <rclark@cs.hmc.edu>
@author Copyright (C) 1997 Robin D. Clark <rclark@cs.hmc.edu>
@author Copyright (C) 1998-2001,2003 Linas Vepstas <linas@linas.org>
*/
/** @{
@file gnc-date.h
@brief Date and Time handling routines
/** @{
@file gnc-date.h
@brief Date and Time handling routines
*/
#ifndef GNC_DATE_H
#define GNC_DATE_H
@ -81,8 +81,8 @@ extern const char *gnc_default_strftime_date_format;
Timezone independent, date and time inclusive, as used in the QSF backend.
The T and Z characters are from xsd:dateTime format in coordinated universal time, UTC.
You can reproduce the string from the GNU/Linux command line using the date utility:
date -u +%Y-%m-%dT%H:M:SZ = 2004-12-12T23:39:11Z The datestring must be timezone independent
and include all specified fields. Remember to use gmtime() NOT localtime()!
date -u +%Y-%m-%dT%H:M:SZ = 2004-12-12T23:39:11Z The datestring must be timezone independent
and include all specified fields. Remember to use gmtime() NOT localtime()!
*/
#define QOF_UTC_DATE_FORMAT "%Y-%m-%dT%H:%M:%SZ"
@ -90,13 +90,13 @@ and include all specified fields. Remember to use gmtime() NOT localtime()!
/** Enum for determining a date format */
typedef enum
{
QOF_DATE_FORMAT_US, /**< United states: mm/dd/yyyy */
QOF_DATE_FORMAT_UK, /**< Britain: dd/mm/yyyy */
QOF_DATE_FORMAT_CE, /**< Continental Europe: dd.mm.yyyy */
QOF_DATE_FORMAT_ISO, /**< ISO: yyyy-mm-dd */
QOF_DATE_FORMAT_UTC, /**< UTC: 2004-12-12T23:39:11Z */
QOF_DATE_FORMAT_LOCALE, /**< Take from locale information */
QOF_DATE_FORMAT_CUSTOM /**< Used by the check printing code */
QOF_DATE_FORMAT_US, /**< United states: mm/dd/yyyy */
QOF_DATE_FORMAT_UK, /**< Britain: dd/mm/yyyy */
QOF_DATE_FORMAT_CE, /**< Continental Europe: dd.mm.yyyy */
QOF_DATE_FORMAT_ISO, /**< ISO: yyyy-mm-dd */
QOF_DATE_FORMAT_UTC, /**< UTC: 2004-12-12T23:39:11Z */
QOF_DATE_FORMAT_LOCALE, /**< Take from locale information */
QOF_DATE_FORMAT_CUSTOM /**< Used by the check printing code */
} QofDateFormat;
#define DATE_FORMAT_FIRST QOF_DATE_FORMAT_US
@ -110,15 +110,16 @@ by qof_date_text_format_get_string */
* This is how to format the month, as a number, an abbreviated string,
* or the full name.
*/
typedef enum {
GNCDATE_MONTH_NUMBER,
GNCDATE_MONTH_ABBREV,
GNCDATE_MONTH_NAME
typedef enum
{
GNCDATE_MONTH_NUMBER,
GNCDATE_MONTH_ABBREV,
GNCDATE_MONTH_NAME
} GNCDateMonthFormat;
/** \name String / DateFormat conversion. */
//@{
//@{
/** \brief The string->value versions return FALSE on success and TRUE on failure */
const gchar* gnc_date_dateformat_to_string(QofDateFormat format);
@ -129,7 +130,7 @@ Note the reversed return values!
@return FALSE on success, TRUE on failure.
*/
gboolean gnc_date_string_to_dateformat(const gchar* format_string,
QofDateFormat *format);
QofDateFormat *format);
const gchar* gnc_date_monthformat_to_string(GNCDateMonthFormat format);
@ -139,14 +140,14 @@ Note the reversed return values!
@return FALSE on success, TRUE on failure.
*/
gboolean gnc_date_string_to_monthformat(const gchar *format_string,
GNCDateMonthFormat *format);
GNCDateMonthFormat *format);
// @}
/* Datatypes *******************************************************/
/** \brief Use a 64-bit unsigned int timespec
*
* struct timespec64 is just like the unix 'struct timespec' except
* struct timespec64 is just like the unix 'struct timespec' except
* that we use a 64-bit
* unsigned int to store the seconds. This should adequately cover
* dates in the distant future as well as the distant past, as long as
@ -158,12 +159,12 @@ gboolean gnc_date_string_to_monthformat(const gchar *format_string,
#ifndef SWIG /* swig 1.1p5 can't hack the long long type */
struct timespec64
{
gint64 tv_sec;
glong tv_nsec;
gint64 tv_sec;
glong tv_nsec;
};
#endif /* SWIG */
/** The Timespec is just like the unix 'struct timespec'
/** The Timespec is just like the unix 'struct timespec'
* except that we use a 64-bit unsigned int to
* store the seconds. This should adequately cover dates in the
* distant future as well as the distant past, as long as they're not
@ -177,7 +178,7 @@ typedef struct timespec64 Timespec;
/* Prototypes ******************************************************/
/** \name Timespec functions */
// @{
// @{
/** strict equality */
gboolean timespec_equal(const Timespec *ta, const Timespec *tb);
@ -208,16 +209,16 @@ Timespec gnc_dmy2timespec (gint day, gint month, gint year);
/** Same as gnc_dmy2timespec, but last second of the day */
Timespec gnc_dmy2timespec_end (gint day, gint month, gint year);
/** The gnc_iso8601_to_timespec_gmt() routine converts an ISO-8601 style
/** The gnc_iso8601_to_timespec_gmt() routine converts an ISO-8601 style
* date/time string to Timespec. Please note that ISO-8601 strings
* are a representation of Universal Time (UTC), and as such, they
* 'store' UTC. To make them human readable, they show timezone
* 'store' UTC. To make them human readable, they show timezone
* information along with a local-time string. But fundamentally,
* they *are* UTC. Thus, thir routine takes a UTC input, and
* they *are* UTC. Thus, thir routine takes a UTC input, and
* returns a UTC output.
*
* For example: 1998-07-17 11:00:00.68-0500
* is 680 milliseconds after 11 o'clock, central daylight time
* For example: 1998-07-17 11:00:00.68-0500
* is 680 milliseconds after 11 o'clock, central daylight time
* It is also 680 millisecs after 16:00:00 hours UTC.
* \return The universl time.
*
@ -226,16 +227,16 @@ Timespec gnc_dmy2timespec_end (gint day, gint month, gint year);
*/
Timespec gnc_iso8601_to_timespec_gmt(const gchar *);
/** The gnc_timespec_to_iso8601_buff() routine takes the input
* UTC Timespec value and prints it as an ISO-8601 style string.
* The buffer must be long enough to contain the NULL-terminated
* string (32 characters + NUL). This routine returns a pointer
* to the null terminator (and can thus be used in the 'stpcpy'
/** The gnc_timespec_to_iso8601_buff() routine takes the input
* UTC Timespec value and prints it as an ISO-8601 style string.
* The buffer must be long enough to contain the NULL-terminated
* string (32 characters + NUL). This routine returns a pointer
* to the null terminator (and can thus be used in the 'stpcpy'
* metaphor of string concatenation).
*
* Please note that ISO-8601 strings are a representation of
* Universal Time (UTC), and as such, they 'store' UTC. To make them
* human readable, they show timezone information along with a
* Please note that ISO-8601 strings are a representation of
* Universal Time (UTC), and as such, they 'store' UTC. To make them
* human readable, they show timezone information along with a
* local-time string. But fundamentally, they *are* UTC. Thus,
* this routine takes a UTC input, and returns a UTC output.
*
@ -249,11 +250,11 @@ gchar * gnc_timespec_to_iso8601_buff (Timespec ts, gchar * buff);
void gnc_timespec2dmy (Timespec ts, gint *day, gint *month, gint *year);
/** \warning hack alert XXX FIXME -- these date routines return incorrect
* values for dates before 1970. Most of them are good only up
* till 2038. This needs fixing ...
* values for dates before 1970. Most of them are good only up
* till 2038. This needs fixing ...
*
* XXX This routine should be modified to assume that the
* the user wanted the time at noon, localtime. The returned
* XXX This routine should be modified to assume that the
* the user wanted the time at noon, localtime. The returned
* time_t should be seconds (at GMT) of the local noon-time.
*/
time_t xaccDMYToSec (gint day, gint month, gint year);
@ -277,13 +278,13 @@ glong gnc_timezone (const struct tm *tm);
/** \name QofDateFormat functions */
// @{
/** The qof_date_format_get routine returns the date format that
* the date printing will use when printing a date, and the scaning
* the date printing will use when printing a date, and the scaning
* routines will assume when parsing a date.
* @returns: the one of the enumerated date formats.
*/
QofDateFormat qof_date_format_get(void);
/**
/**
* The qof_date_format_set() routine sets date format to one of
* US, UK, CE, OR ISO. Checks to make sure it's a legal value.
* Args: QofDateFormat: enumeration indicating preferred format
@ -322,7 +323,7 @@ const gchar *qof_date_text_format_get_string(QofDateFormat df);
*/
gchar dateSeparator(void);
/** \name Date Printing/Scanning functions
/** \name Date Printing/Scanning functions
*/
// @{
/**
@ -385,12 +386,12 @@ size_t qof_print_date_buff (char * buff, size_t buflen, time_t secs);
/** Convenience; calls through to qof_print_date_dmy_buff(). **/
size_t qof_print_gdate(char *buf, size_t bufflen, const GDate *gd);
/** Convenience; calls through to qof_print_date_dmy_buff().
/** Convenience; calls through to qof_print_date_dmy_buff().
* Return: string, which should be freed when no longer needed.
* **/
char * qof_print_date (time_t secs);
/** Convenience; calls through to qof_print_date_dmy_buff().
/** Convenience; calls through to qof_print_date_dmy_buff().
* Return: static global string.
* \warning This routine is not thread-safe, because it uses a single
* global buffer to store the return value. Use qof_print_date_buff()
@ -416,7 +417,7 @@ size_t qof_print_date_time_buff (char * buff, size_t len, time_t secs);
* @return A pointer to the generated string.
* @note The caller owns this buffer and must free it when done. */
char * xaccDateUtilGetStamp (time_t thyme);
/** qof_scan_date
* Convert a string into day / month / year integers according to
* the current dateFormat value.
@ -448,11 +449,11 @@ gboolean qof_scan_date_secs (const char *buff, time_t *secs);
static inline
void gnc_tm_set_day_start (struct tm *tm)
{
/* First second of the day */
tm->tm_hour = 0;
tm->tm_min = 0;
tm->tm_sec = 0;
tm->tm_isdst = -1;
/* First second of the day */
tm->tm_hour = 0;
tm->tm_min = 0;
tm->tm_sec = 0;
tm->tm_isdst = -1;
}
/** The gnc_tm_set_day_start() inline routine will set the appropriate
@ -462,11 +463,11 @@ void gnc_tm_set_day_start (struct tm *tm)
static inline
void gnc_tm_set_day_middle (struct tm *tm)
{
/* First second of the day */
tm->tm_hour = 12;
tm->tm_min = 0;
tm->tm_sec = 0;
tm->tm_isdst = -1;
/* First second of the day */
tm->tm_hour = 12;
tm->tm_min = 0;
tm->tm_sec = 0;
tm->tm_isdst = -1;
}
/** The gnc_tm_set_day_start() inline routine will set the appropriate
@ -476,11 +477,11 @@ void gnc_tm_set_day_middle (struct tm *tm)
static inline
void gnc_tm_set_day_end (struct tm *tm)
{
/* Last second of the day */
tm->tm_hour = 23;
tm->tm_min = 59;
tm->tm_sec = 59;
tm->tm_isdst = -1;
/* Last second of the day */
tm->tm_hour = 23;
tm->tm_min = 59;
tm->tm_sec = 59;
tm->tm_isdst = -1;
}
/** The gnc_tm_get_day_start() routine will convert the given time in

File diff suppressed because it is too large Load Diff

View File

@ -24,17 +24,17 @@
The 'Numeric' functions provide a way of working with rational
numbers while maintaining strict control over rounding errors
when adding rationals with different denominators. The Numeric
class is primarily used for working with monetary amounts,
class is primarily used for working with monetary amounts,
where the denominator typically represents the smallest fraction
of the currency (e.g. pennies, centimes). The numeric class
can handle any fraction (e.g. twelfth's) and is not limited
to fractions that are powers of ten.
to fractions that are powers of ten.
A 'Numeric' value represents a number in rational form, with a
64-bit integer as numerator and denominator. Rationals are
ideal for many uses, such as performing exact, roundoff-error-free
addition and multiplication, but 64-bit rationals do not have
the dynamic range of floating point numbers.
addition and multiplication, but 64-bit rationals do not have
the dynamic range of floating point numbers.
See \ref gncnumericexample
@ -52,10 +52,10 @@ See \ref gncnumericexample
#include <glib-object.h>
struct _gnc_numeric
struct _gnc_numeric
{
gint64 num;
gint64 denom;
gint64 num;
gint64 denom;
};
/** @brief An rational-number type
@ -82,31 +82,31 @@ typedef struct _gnc_numeric gnc_numeric;
"rounding instructions" with zero or one "denominator types".
Valid rounding instructions are:
GNC_HOW_RND_FLOOR
GNC_HOW_RND_CEIL
GNC_HOW_RND_CEIL
GNC_HOW_RND_TRUNC
GNC_HOW_RND_PROMOTE
GNC_HOW_RND_PROMOTE
GNC_HOW_RND_ROUND_HALF_DOWN
GNC_HOW_RND_ROUND_HALF_UP
GNC_HOW_RND_ROUND_HALF_UP
GNC_HOW_RND_ROUND
GNC_HOW_RND_NEVER
The denominator type specifies how to compute a denominator if
GNC_DENOM_AUTO is specified as the 'denom'. Valid
GNC_DENOM_AUTO is specified as the 'denom'. Valid
denominator types are:
GNC_HOW_DENOM_EXACT
GNC_HOW_DENOM_REDUCE
GNC_HOW_DENOM_LCD
GNC_HOW_DENOM_FIXED
GNC_HOW_DENOM_EXACT
GNC_HOW_DENOM_REDUCE
GNC_HOW_DENOM_LCD
GNC_HOW_DENOM_FIXED
GNC_HOW_DENOM_SIGFIGS(N)
To use traditional rational-number operational semantics (all results
are exact and are reduced to relatively-prime fractions) pass the
argument GNC_DENOM_AUTO as 'denom' and
argument GNC_DENOM_AUTO as 'denom' and
GNC_HOW_DENOM_REDUCE| GNC_HOW_RND_NEVER as 'how'.
To enforce strict financial semantics (such that all operands must have
the same denominator as each other and as the result), use
GNC_DENOM_AUTO as 'denom' and
GNC_DENOM_AUTO as 'denom' and
GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER as 'how'.
@{
*/
@ -114,8 +114,8 @@ typedef struct _gnc_numeric gnc_numeric;
/** \brief bitmasks for HOW flags.
* bits 8-15 of 'how' are reserved for the number of significant
* digits to use in the output with GNC_HOW_DENOM_SIGFIG
*/
* digits to use in the output with GNC_HOW_DENOM_SIGFIG
*/
#define GNC_NUMERIC_RND_MASK 0x0000000f
#define GNC_NUMERIC_DENOM_MASK 0x000000f0
#define GNC_NUMERIC_SIGFIGS_MASK 0x0000ff00
@ -125,107 +125,110 @@ typedef struct _gnc_numeric gnc_numeric;
* Rounding instructions control how fractional parts in the specified
* denominator affect the result. For example, if a computed result is
* "3/4" but the specified denominator for the return value is 2, should
* the return value be "1/2" or "2/2"?
* the return value be "1/2" or "2/2"?
*
* Possible rounding instructions are:
*/
enum {
/** Round toward -infinity */
GNC_HOW_RND_FLOOR = 0x01,
enum
{
/** Round toward -infinity */
GNC_HOW_RND_FLOOR = 0x01,
/** Round toward +infinity */
GNC_HOW_RND_CEIL = 0x02,
/** Round toward +infinity */
GNC_HOW_RND_CEIL = 0x02,
/** Truncate fractions (round toward zero) */
GNC_HOW_RND_TRUNC = 0x03,
/** Truncate fractions (round toward zero) */
GNC_HOW_RND_TRUNC = 0x03,
/** Promote fractions (round away from zero) */
GNC_HOW_RND_PROMOTE = 0x04,
/** Promote fractions (round away from zero) */
GNC_HOW_RND_PROMOTE = 0x04,
/** Round to the nearest integer, rounding toward zero
* when there are two equidistant nearest integers.
*/
GNC_HOW_RND_ROUND_HALF_DOWN = 0x05,
/** Round to the nearest integer, rounding toward zero
* when there are two equidistant nearest integers.
*/
GNC_HOW_RND_ROUND_HALF_DOWN = 0x05,
/** Round to the nearest integer, rounding away from zero
* when there are two equidistant nearest integers.
*/
GNC_HOW_RND_ROUND_HALF_UP = 0x06,
/** Round to the nearest integer, rounding away from zero
* when there are two equidistant nearest integers.
*/
GNC_HOW_RND_ROUND_HALF_UP = 0x06,
/** Use unbiased ("banker's") rounding. This rounds to the
* nearest integer, and to the nearest even integer when there
* are two equidistant nearest integers. This is generally the
* one you should use for financial quantities.
*/
GNC_HOW_RND_ROUND = 0x07,
/** Use unbiased ("banker's") rounding. This rounds to the
* nearest integer, and to the nearest even integer when there
* are two equidistant nearest integers. This is generally the
* one you should use for financial quantities.
*/
GNC_HOW_RND_ROUND = 0x07,
/** Never round at all, and signal an error if there is a
* fractional result in a computation.
*/
GNC_HOW_RND_NEVER = 0x08
/** Never round at all, and signal an error if there is a
* fractional result in a computation.
*/
GNC_HOW_RND_NEVER = 0x08
};
/** How to compute a denominator, or'ed into the "how" field. */
enum {
/** Use any denominator which gives an exactly correct ratio of
* numerator to denominator. Use EXACT when you do not wish to
* lose any information in the result but also do not want to
* spend any time finding the "best" denominator.
*/
GNC_HOW_DENOM_EXACT = 0x10,
enum
{
/** Use any denominator which gives an exactly correct ratio of
* numerator to denominator. Use EXACT when you do not wish to
* lose any information in the result but also do not want to
* spend any time finding the "best" denominator.
*/
GNC_HOW_DENOM_EXACT = 0x10,
/** Reduce the result value by common factor elimination,
* using the smallest possible value for the denominator that
* keeps the correct ratio. The numerator and denominator of
* the result are relatively prime.
*/
GNC_HOW_DENOM_REDUCE = 0x20,
/** Reduce the result value by common factor elimination,
* using the smallest possible value for the denominator that
* keeps the correct ratio. The numerator and denominator of
* the result are relatively prime.
*/
GNC_HOW_DENOM_REDUCE = 0x20,
/** Find the least common multiple of the arguments' denominators
* and use that as the denominator of the result.
*/
GNC_HOW_DENOM_LCD = 0x30,
/** Find the least common multiple of the arguments' denominators
* and use that as the denominator of the result.
*/
GNC_HOW_DENOM_LCD = 0x30,
/** All arguments are required to have the same denominator,
* that denominator is to be used in the output, and an error
* is to be signaled if any argument has a different denominator.
*/
GNC_HOW_DENOM_FIXED = 0x40,
/** All arguments are required to have the same denominator,
* that denominator is to be used in the output, and an error
* is to be signaled if any argument has a different denominator.
*/
GNC_HOW_DENOM_FIXED = 0x40,
/** Round to the number of significant figures given in the rounding
* instructions by the GNC_HOW_DENOM_SIGFIGS () macro.
*/
GNC_HOW_DENOM_SIGFIG = 0x50
/** Round to the number of significant figures given in the rounding
* instructions by the GNC_HOW_DENOM_SIGFIGS () macro.
*/
GNC_HOW_DENOM_SIGFIG = 0x50
};
/** Build a 'how' value that will generate a denominator that will
/** Build a 'how' value that will generate a denominator that will
* keep at least n significant figures in the result.
*/
#define GNC_HOW_DENOM_SIGFIGS( n ) ( ((( n ) & 0xff) << 8) | GNC_HOW_DENOM_SIGFIG)
#define GNC_HOW_GET_SIGFIGS( a ) ( (( a ) & 0xff00 ) >> 8)
/** Error codes */
typedef enum {
GNC_ERROR_OK = 0, /**< No error */
GNC_ERROR_ARG = -1, /**< Argument is not a valid number */
GNC_ERROR_OVERFLOW = -2, /**< Intermediate result overflow */
typedef enum
{
GNC_ERROR_OK = 0, /**< No error */
GNC_ERROR_ARG = -1, /**< Argument is not a valid number */
GNC_ERROR_OVERFLOW = -2, /**< Intermediate result overflow */
/** GNC_HOW_DENOM_FIXED was specified, but argument denominators differed. */
GNC_ERROR_DENOM_DIFF = -3,
/** GNC_HOW_DENOM_FIXED was specified, but argument denominators differed. */
GNC_ERROR_DENOM_DIFF = -3,
/** GNC_HOW_RND_NEVER was specified, but the result could not be
* converted to the desired denominator without a remainder. */
GNC_ERROR_REMAINDER = -4
/** GNC_HOW_RND_NEVER was specified, but the result could not be
* converted to the desired denominator without a remainder. */
GNC_ERROR_REMAINDER = -4
} GNCNumericErrorCode;
/** Values that can be passed as the 'denom' argument.
* The include a positive number n to be used as the
* denominator of the output value. Other possibilities
/** Values that can be passed as the 'denom' argument.
* The include a positive number n to be used as the
* denominator of the output value. Other possibilities
* include the list below:
*/
/** Compute an appropriate denominator automatically. Flags in
/** Compute an appropriate denominator automatically. Flags in
* the 'how' argument will specify how to compute the denominator.
*/
#define GNC_DENOM_AUTO 0
@ -239,24 +242,28 @@ typedef enum {
@{
*/
/** Make a gnc_numeric from numerator and denominator */
static inline
gnc_numeric gnc_numeric_create(gint64 num, gint64 denom) {
gnc_numeric out;
out.num = num;
out.denom = denom;
return out;
static inline
gnc_numeric gnc_numeric_create(gint64 num, gint64 denom)
{
gnc_numeric out;
out.num = num;
out.denom = denom;
return out;
}
/** create a zero-value gnc_numeric */
static inline
gnc_numeric gnc_numeric_zero(void) { return gnc_numeric_create(0, 1); }
gnc_numeric gnc_numeric_zero(void)
{
return gnc_numeric_create(0, 1);
}
/** Convert a floating-point number to a gnc_numeric.
* Both 'denom' and 'how' are used as in arithmetic,
/** Convert a floating-point number to a gnc_numeric.
* Both 'denom' and 'how' are used as in arithmetic,
* but GNC_DENOM_AUTO is not recognized; a denominator
* must be specified either explicitctly or through sigfigs.
*/
gnc_numeric double_to_gnc_numeric(double in, gint64 denom,
gnc_numeric double_to_gnc_numeric(double in, gint64 denom,
gint how);
/** Read a gnc_numeric from str, skipping any leading whitespace.
@ -265,7 +272,7 @@ gnc_numeric double_to_gnc_numeric(double in, gint64 denom,
gboolean string_to_gnc_numeric(const gchar* str, gnc_numeric *n);
/** Create a gnc_numeric object that signals the error condition
* noted by error_code, rather than a number.
* noted by error_code, rather than a number.
*/
gnc_numeric gnc_numeric_error(GNCNumericErrorCode error_code);
/** @} */
@ -274,11 +281,17 @@ gnc_numeric gnc_numeric_error(GNCNumericErrorCode error_code);
@{
*/
/** Return numerator */
static inline
gint64 gnc_numeric_num(gnc_numeric a) { return a.num; }
static inline
gint64 gnc_numeric_num(gnc_numeric a)
{
return a.num;
}
/** Return denominator */
static inline
gint64 gnc_numeric_denom(gnc_numeric a) { return a.denom; }
static inline
gint64 gnc_numeric_denom(gnc_numeric a)
{
return a.denom;
}
/** Convert numeric to floating-point value. */
gdouble gnc_numeric_to_double(gnc_numeric in);
@ -292,13 +305,13 @@ gchar *gnc_numeric_to_string(gnc_numeric n);
gchar * gnc_num_dbg_to_string(gnc_numeric n);
/** @}*/
/** @name Comparisons and Predicates
/** @name Comparisons and Predicates
@{
*/
/** Check for error signal in value. Returns GNC_ERROR_OK (==0) if
* the number appears to be valid, otherwise it returns the
* type of error. Error values always have a denominator of zero.
*/
*/
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a);
/** Returns 1 if a>b, -1 if b>a, 0 if a == b */
@ -313,20 +326,20 @@ gboolean gnc_numeric_negative_p(gnc_numeric a);
/** Returns 1 if a > 0, otherwise returns 0. */
gboolean gnc_numeric_positive_p(gnc_numeric a);
/** Equivalence predicate: Returns TRUE (1) if a and b are
/** Equivalence predicate: Returns TRUE (1) if a and b are
* exactly the same (have the same numerator and denominator)
*/
gboolean gnc_numeric_eq(gnc_numeric a, gnc_numeric b);
*/
gboolean gnc_numeric_eq(gnc_numeric a, gnc_numeric b);
/** Equivalence predicate: Returns TRUE (1) if a and b represent
* the same number. That is, return TRUE if the ratios, when
* the same number. That is, return TRUE if the ratios, when
* reduced by eliminating common factors, are identical.
*/
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b);
*/
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b);
/** Equivalence predicate:
* Convert both a and b to denom using the
* specified DENOM and method HOW, and compare numerators
/** Equivalence predicate:
* Convert both a and b to denom using the
* specified DENOM and method HOW, and compare numerators
* the results using gnc_numeric_equal.
*
For example, if a == 7/16 and b == 3/4,
@ -335,20 +348,20 @@ gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b);
gnc_numeric_same(a, b, 2, GNC_HOW_RND_ROUND) == 0
because 7/16 rounds to 1/2 under unbiased rounding but 3/4 rounds
to 2/2.
*/
gint gnc_numeric_same(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how);
*/
gint gnc_numeric_same(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how);
/** @} */
/** @name Arithmetic Operations
@{
/** @name Arithmetic Operations
@{
*/
/** Return a+b. */
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b,
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how);
/** Return a-b. */
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b,
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how);
/** Multiply a times b, returning the product. An overflow
@ -356,17 +369,17 @@ gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b,
* be represented as a ratio of 64-bit int's after removing
* common factors.
*/
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b,
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how);
/** Division. Note that division can overflow, in the following
* sense: if we write x=a/b and y=c/d then x/y = (a*d)/(b*c)
* If, after eliminating all common factors between the numerator
* (a*d) and the denominator (b*c), then if either the numerator
* and/or the denominator are *still* greater than 2^63, then
/** Division. Note that division can overflow, in the following
* sense: if we write x=a/b and y=c/d then x/y = (a*d)/(b*c)
* If, after eliminating all common factors between the numerator
* (a*d) and the denominator (b*c), then if either the numerator
* and/or the denominator are *still* greater than 2^63, then
* the division has overflowed.
*/
gnc_numeric gnc_numeric_div(gnc_numeric x, gnc_numeric y,
gnc_numeric gnc_numeric_div(gnc_numeric x, gnc_numeric y,
gint64 denom, gint how);
/** Negate the argument */
gnc_numeric gnc_numeric_neg(gnc_numeric a);
@ -374,28 +387,30 @@ gnc_numeric gnc_numeric_neg(gnc_numeric a);
/** Return the absolute value of the argument */
gnc_numeric gnc_numeric_abs(gnc_numeric a);
/**
/**
* Shortcut for common case: gnc_numeric_add(a, b, GNC_DENOM_AUTO,
* GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
*/
static inline
gnc_numeric gnc_numeric_add_fixed(gnc_numeric a, gnc_numeric b) {
return gnc_numeric_add(a, b, GNC_DENOM_AUTO,
GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
gnc_numeric gnc_numeric_add_fixed(gnc_numeric a, gnc_numeric b)
{
return gnc_numeric_add(a, b, GNC_DENOM_AUTO,
GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
}
/**
/**
* Shortcut for most common case: gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
* GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
*/
static inline
gnc_numeric gnc_numeric_sub_fixed(gnc_numeric a, gnc_numeric b) {
return gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
static inline
gnc_numeric gnc_numeric_sub_fixed(gnc_numeric a, gnc_numeric b)
{
return gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
}
/** @} */
/** @name Arithmetic Functions with Exact Error Returns
/** @name Arithmetic Functions with Exact Error Returns
@{
*/
/** The same as gnc_numeric_add, but uses 'error' for accumulating
@ -410,14 +425,14 @@ gnc_numeric gnc_numeric_sub_with_error(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how,
gnc_numeric * error);
/** The same as gnc_numeric_mul, but uses error for
/** The same as gnc_numeric_mul, but uses error for
* accumulating conversion roundoff error.
*/
gnc_numeric gnc_numeric_mul_with_error(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how,
gnc_numeric * error);
/** The same as gnc_numeric_div, but uses error for
/** The same as gnc_numeric_div, but uses error for
* accumulating conversion roundoff error.
*/
gnc_numeric gnc_numeric_div_with_error(gnc_numeric a, gnc_numeric b,
@ -425,24 +440,24 @@ gnc_numeric gnc_numeric_div_with_error(gnc_numeric a, gnc_numeric b,
gnc_numeric * error);
/** @} */
/** @name Change Denominator
/** @name Change Denominator
@{
*/
/** Change the denominator of a gnc_numeric value to the
* specified denominator under standard arguments
* 'denom' and 'how'.
/** Change the denominator of a gnc_numeric value to the
* specified denominator under standard arguments
* 'denom' and 'how'.
*/
gnc_numeric gnc_numeric_convert(gnc_numeric in, gint64 denom,
gnc_numeric gnc_numeric_convert(gnc_numeric in, gint64 denom,
gint how);
/** Same as gnc_numeric_convert, but return a remainder
* value for accumulating conversion error.
/** Same as gnc_numeric_convert, but return a remainder
* value for accumulating conversion error.
*/
gnc_numeric gnc_numeric_convert_with_error(gnc_numeric in, gint64 denom,
gint how,
gnc_numeric * error);
gnc_numeric gnc_numeric_convert_with_error(gnc_numeric in, gint64 denom,
gint how,
gnc_numeric * error);
/** Return input after reducing it by Greated Common Factor (GCF)
/** Return input after reducing it by Greated Common Factor (GCF)
* elimination */
gnc_numeric gnc_numeric_reduce(gnc_numeric in);
@ -462,7 +477,7 @@ gboolean gnc_numeric_to_decimal(gnc_numeric * a,
guint8 * max_decimal_places);
/** @} */
/** @name GValue
/** @name GValue
@{
*/
GType gnc_numeric_get_type( void );
@ -470,23 +485,23 @@ GType gnc_numeric_get_type( void );
/** @} */
/** @name Deprecated, backwards-compatible definitions
/** @name Deprecated, backwards-compatible definitions
@{
*/
#define GNC_RND_FLOOR GNC_HOW_RND_FLOOR
#define GNC_RND_CEIL GNC_HOW_RND_CEIL
#define GNC_RND_CEIL GNC_HOW_RND_CEIL
#define GNC_RND_TRUNC GNC_HOW_RND_TRUNC
#define GNC_RND_PROMOTE GNC_HOW_RND_PROMOTE
#define GNC_RND_PROMOTE GNC_HOW_RND_PROMOTE
#define GNC_RND_ROUND_HALF_DOWN GNC_HOW_RND_ROUND_HALF_DOWN
#define GNC_RND_ROUND_HALF_UP GNC_HOW_RND_ROUND_HALF_UP
#define GNC_RND_ROUND_HALF_UP GNC_HOW_RND_ROUND_HALF_UP
#define GNC_RND_ROUND GNC_HOW_RND_ROUND
#define GNC_RND_NEVER GNC_HOW_RND_NEVER
#define GNC_DENOM_EXACT GNC_HOW_DENOM_EXACT
#define GNC_DENOM_REDUCE GNC_HOW_DENOM_REDUCE
#define GNC_DENOM_LCD GNC_HOW_DENOM_LCD
#define GNC_DENOM_FIXED GNC_HOW_DENOM_FIXED
#define GNC_DENOM_SIGFIG GNC_HOW_DENOM_SIGFIG
#define GNC_DENOM_EXACT GNC_HOW_DENOM_EXACT
#define GNC_DENOM_REDUCE GNC_HOW_DENOM_REDUCE
#define GNC_DENOM_LCD GNC_HOW_DENOM_LCD
#define GNC_DENOM_FIXED GNC_HOW_DENOM_FIXED
#define GNC_DENOM_SIGFIG GNC_HOW_DENOM_SIGFIG
#define GNC_DENOM_SIGFIGS(X) GNC_HOW_DENOM_SIGFIGS(X)
#define GNC_NUMERIC_GET_SIGFIGS(X) GNC_HOW_GET_SIGFIGS(X)

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,7 @@
\********************************************************************/
#ifndef GUID_H
#define GUID_H
#define GUID_H
#include <stddef.h>
#include <glib-object.h>
@ -30,7 +30,7 @@
/** @addtogroup Entity
@{ */
/** @addtogroup GUID
Globally Unique ID's provide a way to uniquely identify
Globally Unique ID's provide a way to uniquely identify
some thing. A GUID is a unique, cryptographically
random 128-bit value. The identifier is so random that
it is safe to assume that there is no other such item
@ -45,7 +45,7 @@
@{ */
/** @file guid.h
@brief globally unique ID User API
@brief globally unique ID User API
@author Copyright (C) 2000 Dave Peticolas <peticola@cs.ucdavis.edu>
*/
@ -53,9 +53,9 @@
#define GUID_DATA_SIZE 16
typedef union _GUID
{
guchar data[GUID_DATA_SIZE];
guchar data[GUID_DATA_SIZE];
gint __align_me; /* this just ensures that GUIDs are 32-bit
gint __align_me; /* this just ensures that GUIDs are 32-bit
* aligned on systems that need them to be. */
} GUID;
@ -63,8 +63,8 @@ typedef union _GUID
#define GNC_TYPE_GUID (gnc_guid_get_type())
#define GNC_VALUE_HOLDS_GUID(value) G_VALUE_HOLDS(value, GNC_TYPE_GUID)
GType gnc_guid_get_type (void);
G_CONST_RETURN GUID* gnc_value_get_guid (const GValue *value);
GType gnc_guid_get_type (void);
G_CONST_RETURN GUID* gnc_value_get_guid (const GValue *value);
/** number of characters needed to encode a guid as a string
* not including the null terminator. */
@ -124,11 +124,11 @@ void guid_shutdown (void);
* existing value will be replaced with a new value.
*
* This routine uses the md5 algorithm to build strong random guids.
* Note that while guid's are generated randomly, the odds of this
* Note that while guid's are generated randomly, the odds of this
* routine returning a non-unique id are astronomically small.
* (Literally astronomically: If you had Cray's on every solar
* system in the universe running for the entire age of the universe,
* you'd still have less than a one-in-a-million chance of coming up
* you'd still have less than a one-in-a-million chance of coming up
* with a duplicate id. 2^128 == 10^38 is a really really big number.)
*/
void guid_new(GUID *guid);
@ -153,11 +153,11 @@ void guid_free (GUID *guid);
GUID *guid_copy (const GUID *guid);
/** The guid_to_string() routine returns a null-terminated string
* encoding of the id. String encodings of identifiers are hex
* numbers printed only with the characters '0' through '9' and
* 'a' through 'f'. The encoding will always be GUID_ENCODING_LENGTH
* characters long.
/** The guid_to_string() routine returns a null-terminated string
* encoding of the id. String encodings of identifiers are hex
* numbers printed only with the characters '0' through '9' and
* 'a' through 'f'. The encoding will always be GUID_ENCODING_LENGTH
* characters long.
*
* XXX This routine is not thread safe and is deprecated. Please
* use the routine guid_to_string_buff() instead.

View File

@ -27,22 +27,22 @@
#include "kvp_frame.h"
/** @addtogroup KVP
@{
@{
*/
/** @file kvp-util-p.h
* @brief misc odd-job kvp utils engine-private routines
* @author Copyright (C) 2001, 2003 Linas Vepstas <linas@linas.org> *
*/
/** @name KvpBag Bags of GUID Pointers
@{
/** @name KvpBag Bags of GUID Pointers
@{
*/
/** The gnc_kvp_bag_add() routine is used to maintain a collection
/** The gnc_kvp_bag_add() routine is used to maintain a collection
* of pointers in a kvp tree.
*
* The thing being pointed at is uniquely identified by its GUID.
* The thing being pointed at is uniquely identified by its GUID.
* This routine is typically used to create a linked list, and/or
* a collection of pointers to objects that are 'related' to each
* a collection of pointers to objects that are 'related' to each
* other in some way.
*
* The var-args should be pairs of strings (const char *) followed by
@ -56,39 +56,39 @@
* frame, and put it in the bag. The frame will contain named data
* from the subroutine arguments. Thus, for example:
*
* gnc_kvp_array (kvp, "foo", secs, "acct_guid", aguid,
* gnc_kvp_array (kvp, "foo", secs, "acct_guid", aguid,
* "book_guid", bguid, NULL);
*
* will create a frame containing "/acct_guid" and "/book_guid", whose
* values are aguid and bguid respecitvely. The frame will also
* contain "/date", whose value will be secs. This frame will be
* placed into the bag located at "foo".
* placed into the bag located at "foo".
*
* This routine returns a pointer to the frame that was created, or
* This routine returns a pointer to the frame that was created, or
* NULL if an error occured.
*/
KvpFrame * gnc_kvp_bag_add (KvpFrame *kvp_root, const char *path, time_t secs,
const char *first_name, ...);
KvpFrame * gnc_kvp_bag_add (KvpFrame *kvp_root, const char *path, time_t secs,
const char *first_name, ...);
/** The gnc_kvp_bag_merge() routine will move the bag contents from
* the 'kvp_from', to the 'into' bag. It will then delete the
* the 'kvp_from', to the 'into' bag. It will then delete the
* 'from' bag from the kvp tree.
*/
void gnc_kvp_bag_merge (KvpFrame *kvp_into, const char *intopath,
void gnc_kvp_bag_merge (KvpFrame *kvp_into, const char *intopath,
KvpFrame *kvp_from, const char *frompath);
/** The gnc_kvp_bag_find_by_guid() routine examines the bag pointed
* located at root. It looks for a frame in that bag that has the
* guid value of "desired_guid" filed under the key name "guid_name".
* If it finds that matching guid, then it returns a pointer to
* If it finds that matching guid, then it returns a pointer to
* the KVP frame that contains it. If it is not found, or if there
* is any other error, NULL is returned.
*/
KvpFrame * gnc_kvp_bag_find_by_guid (KvpFrame *root, const char * path,
const char *guid_name, const GUID *desired_guid);
const char *guid_name, const GUID *desired_guid);
/** Remove the given frame from the bag. The frame is removed,

View File

@ -31,55 +31,55 @@
#include "kvp-util-p.h"
/* ================================================================ */
static KvpFrame *
gnc_kvp_array_va (KvpFrame *kvp_root, const char * path,
gnc_kvp_array_va (KvpFrame *kvp_root, const char * path,
time_t secs, const char * first_name, va_list ap)
{
KvpFrame *cwd;
Timespec ts;
const char *name;
KvpFrame *cwd;
Timespec ts;
const char *name;
if (!kvp_root) return NULL;
if (!first_name) return NULL;
/* Create subdirectory and put the actual data */
cwd = kvp_frame_new();
if (!kvp_root) return NULL;
if (!first_name) return NULL;
/* Record the time */
ts.tv_sec = secs;
ts.tv_nsec = 0;
kvp_frame_set_timespec (cwd, "date", ts);
/* Create subdirectory and put the actual data */
cwd = kvp_frame_new();
/* Loop over the args */
name = first_name;
while (name)
{
const GUID *guid;
guid = va_arg (ap, const GUID *);
/* Record the time */
ts.tv_sec = secs;
ts.tv_nsec = 0;
kvp_frame_set_timespec (cwd, "date", ts);
kvp_frame_set_guid (cwd, name, guid);
/* Loop over the args */
name = first_name;
while (name)
{
const GUID *guid;
guid = va_arg (ap, const GUID *);
name = va_arg (ap, const char *);
}
kvp_frame_set_guid (cwd, name, guid);
/* Attach cwd into the array */
kvp_frame_add_frame_nc (kvp_root, path, cwd);
return cwd;
name = va_arg (ap, const char *);
}
/* Attach cwd into the array */
kvp_frame_add_frame_nc (kvp_root, path, cwd);
return cwd;
}
/* ================================================================ */
KvpFrame *
gnc_kvp_bag_add (KvpFrame *pwd, const char * path,
gnc_kvp_bag_add (KvpFrame *pwd, const char * path,
time_t secs, const char *first_name, ...)
{
KvpFrame *cwd;
va_list ap;
va_start (ap, first_name);
cwd = gnc_kvp_array_va (pwd, path, secs, first_name, ap);
va_end (ap);
return cwd;
KvpFrame *cwd;
va_list ap;
va_start (ap, first_name);
cwd = gnc_kvp_array_va (pwd, path, secs, first_name, ap);
va_end (ap);
return cwd;
}
/* ================================================================ */
@ -90,33 +90,33 @@ gnc_kvp_bag_add (KvpFrame *pwd, const char * path,
GUID *guid = kvp_frame_get_guid (fr, guid_name); \
if (guid && guid_equal (desired_guid, guid)) return fr; \
} \
}
}
KvpFrame *
gnc_kvp_bag_find_by_guid (KvpFrame *root, const char * path,
const char *guid_name, const GUID *desired_guid)
const char *guid_name, const GUID *desired_guid)
{
KvpValue *arr;
KvpValueType valtype;
GList *node;
KvpValue *arr;
KvpValueType valtype;
GList *node;
arr = kvp_frame_get_value (root, path);
valtype = kvp_value_get_type (arr);
if (KVP_TYPE_FRAME == valtype)
{
MATCH_GUID (arr);
arr = kvp_frame_get_value (root, path);
valtype = kvp_value_get_type (arr);
if (KVP_TYPE_FRAME == valtype)
{
MATCH_GUID (arr);
return NULL;
}
/* Its gotta be a single isolated frame, or a list of them. */
if (KVP_TYPE_GLIST != valtype) return NULL;
for (node = kvp_value_get_glist(arr); node; node = node->next)
{
KvpValue *va = node->data;
MATCH_GUID (va);
}
return NULL;
}
/* Its gotta be a single isolated frame, or a list of them. */
if (KVP_TYPE_GLIST != valtype) return NULL;
for (node = kvp_value_get_glist(arr); node; node=node->next)
{
KvpValue *va = node->data;
MATCH_GUID (va);
}
return NULL;
}
/* ================================================================ */
@ -124,40 +124,40 @@ gnc_kvp_bag_find_by_guid (KvpFrame *root, const char * path,
void
gnc_kvp_bag_remove_frame (KvpFrame *root, const char *path, KvpFrame *fr)
{
KvpValue *arr;
KvpValueType valtype;
GList *node, *listhead;
KvpValue *arr;
KvpValueType valtype;
GList *node, *listhead;
arr = kvp_frame_get_value (root, path);
valtype = kvp_value_get_type (arr);
if (KVP_TYPE_FRAME == valtype)
{
if (fr == kvp_value_get_frame (arr))
arr = kvp_frame_get_value (root, path);
valtype = kvp_value_get_type (arr);
if (KVP_TYPE_FRAME == valtype)
{
KvpValue *old_val = kvp_frame_replace_value_nc (root, path, NULL);
kvp_value_replace_frame_nc (old_val, NULL);
kvp_value_delete (old_val);
if (fr == kvp_value_get_frame (arr))
{
KvpValue *old_val = kvp_frame_replace_value_nc (root, path, NULL);
kvp_value_replace_frame_nc (old_val, NULL);
kvp_value_delete (old_val);
}
return;
}
return;
}
/* Its gotta be a single isolated frame, or a list of them. */
if (KVP_TYPE_GLIST != valtype) return;
/* Its gotta be a single isolated frame, or a list of them. */
if (KVP_TYPE_GLIST != valtype) return;
listhead = kvp_value_get_glist(arr);
for (node = listhead; node; node=node->next)
{
KvpValue *va = node->data;
if (fr == kvp_value_get_frame (va))
listhead = kvp_value_get_glist(arr);
for (node = listhead; node; node = node->next)
{
listhead = g_list_remove_link (listhead, node);
g_list_free_1 (node);
kvp_value_replace_glist_nc (arr, listhead);
kvp_value_replace_frame_nc (va, NULL);
kvp_value_delete (va);
return;
KvpValue *va = node->data;
if (fr == kvp_value_get_frame (va))
{
listhead = g_list_remove_link (listhead, node);
g_list_free_1 (node);
kvp_value_replace_glist_nc (arr, listhead);
kvp_value_replace_frame_nc (va, NULL);
kvp_value_delete (va);
return;
}
}
}
}
/* ================================================================ */
@ -165,40 +165,40 @@ gnc_kvp_bag_remove_frame (KvpFrame *root, const char *path, KvpFrame *fr)
static KvpFrame *
gnc_kvp_bag_get_first (KvpFrame *root, const char * path)
{
KvpValue *arr, *va;
KvpValueType valtype;
GList *node;
KvpValue *arr, *va;
KvpValueType valtype;
GList *node;
arr = kvp_frame_get_value (root, path);
valtype = kvp_value_get_type (arr);
if (KVP_TYPE_FRAME == valtype)
{
return kvp_value_get_frame(arr);
}
arr = kvp_frame_get_value (root, path);
valtype = kvp_value_get_type (arr);
if (KVP_TYPE_FRAME == valtype)
{
return kvp_value_get_frame(arr);
}
/* Its gotta be a single isolated frame, or a list of them. */
if (KVP_TYPE_GLIST != valtype) return NULL;
/* Its gotta be a single isolated frame, or a list of them. */
if (KVP_TYPE_GLIST != valtype) return NULL;
node = kvp_value_get_glist(arr);
if (NULL == node) return NULL;
node = kvp_value_get_glist(arr);
if (NULL == node) return NULL;
va = node->data;
return kvp_value_get_frame(va);
va = node->data;
return kvp_value_get_frame(va);
}
void
gnc_kvp_bag_merge (KvpFrame *kvp_into, const char *intopath,
KvpFrame *kvp_from, const char *frompath)
{
KvpFrame *fr;
KvpFrame *fr;
fr = gnc_kvp_bag_get_first (kvp_from, frompath);
while (fr)
{
gnc_kvp_bag_remove_frame (kvp_from, frompath, fr);
kvp_frame_add_frame_nc (kvp_into, intopath, fr);
fr = gnc_kvp_bag_get_first (kvp_from, frompath);
}
while (fr)
{
gnc_kvp_bag_remove_frame (kvp_from, frompath, fr);
kvp_frame_add_frame_nc (kvp_into, intopath, fr);
fr = gnc_kvp_bag_get_first (kvp_from, frompath);
}
}
/* ================================================================ */
@ -209,27 +209,27 @@ gnc_kvp_bag_merge (KvpFrame *kvp_into, const char *intopath,
static void
kv_pair_helper(gpointer key, gpointer val, gpointer user_data)
{
GSList **result = (GSList **) user_data;
GHashTableKVPair *kvp = g_new(GHashTableKVPair, 1);
GSList **result = (GSList **) user_data;
GHashTableKVPair *kvp = g_new(GHashTableKVPair, 1);
kvp->key = key;
kvp->value = val;
*result = g_slist_prepend(*result, kvp);
kvp->key = key;
kvp->value = val;
*result = g_slist_prepend(*result, kvp);
}
GSList *
g_hash_table_key_value_pairs(GHashTable *table)
{
GSList *result_list = NULL;
g_hash_table_foreach(table, kv_pair_helper, &result_list);
return result_list;
GSList *result_list = NULL;
g_hash_table_foreach(table, kv_pair_helper, &result_list);
return result_list;
}
void
g_hash_table_kv_pair_free_gfunc(gpointer data, gpointer user_data)
{
GHashTableKVPair *kvp = (GHashTableKVPair *) data;
g_free(kvp);
GHashTableKVPair *kvp = (GHashTableKVPair *) data;
g_free(kvp);
}
/*======================== END OF FILE =============================*/

View File

@ -21,31 +21,32 @@
\********************************************************************/
/** @addtogroup KVP
@{
@{
*/
/** @file kvp-util.h
@brief QOF KVP utility functions
/** @file kvp-util.h
@brief QOF KVP utility functions
*/
/** @name Hash Utilities
@{
@{
*/
#ifndef GNC_KVP_UTIL_H
#define GNC_KVP_UTIL_H
typedef struct {
gpointer key;
gpointer value;
typedef struct
{
gpointer key;
gpointer value;
} GHashTableKVPair;
/**
/**
Returns a GSList* of all the
keys and values in a given hash table. Data elements of lists are
actual hash elements, so be careful, and deallocation of the
GHashTableKVPairs in the result list are the caller's
responsibility. A typical sequence might look like this:
GSList *kvps = g_hash_table_key_value_pairs(hash);
GSList *kvps = g_hash_table_key_value_pairs(hash);
... use kvps->data->key and kvps->data->val, etc. here ...
g_slist_foreach(kvps, g_hash_table_kv_pair_free_gfunc, NULL);
g_slist_free(kvps);

File diff suppressed because it is too large Load Diff

View File

@ -22,16 +22,16 @@
* A KvpFrame is a set of associations between character strings
* (keys) and KvpValue structures. A KvpValue is a union with
* possible types enumerated in the KvpValueType enum, and includes,
* possible types enumerated in the KvpValueType enum, and includes,
* among other things, ints, doubles, strings, guid's, lists, time
* and numeric values. KvpValues may also be other frames, so
* KVP is inherently hierarchical.
*
*
* Values are stored in a 'slot' associated with a key.
* Pointers passed as arguments into set_slot and get_slot are the
* responsibility of the caller. Pointers returned by get_slot are
* owned by the kvp_frame. Make copies as needed.
*
*
* A 'path' is a sequence of keys that can be followed to a value.
* Paths may be specified as varargs (variable number of arguments
* to a subrutine, NULL-terminated), as a GSList, or as a standard
@ -42,14 +42,14 @@
*
* Note that although, in principle, keys may contain the / and . and
* .. characters, doing so may lead to confusion, and will make
* path-string parsing routines fail. In other words, don't use
* path-string parsing routines fail. In other words, don't use
* a key such as 'some/key' or 'some/./other/../key' because you
* may get unexpected results.
*
* To set a value into a frame, you will want to use one of the
*
* To set a value into a frame, you will want to use one of the
* kvp_frame_set_xxx() routines. Most of the other routines provide
* only low-level access that you probably shouldn't use.
@{
*/
/** @file kvp_frame.h
@ -73,40 +73,41 @@ typedef struct _KvpFrame KvpFrame;
/** A KvpValue is a union with possible types enumerated in the
* KvpValueType enum. */
typedef struct _KvpValue KvpValue;
/** \brief possible types in the union KvpValue
* \todo : People have asked for boolean values,
/** \brief possible types in the union KvpValue
* \todo : People have asked for boolean values,
* e.g. in xaccAccountSetAutoInterestXfer
*
* \todo In the long run, this should be synchronized with the
* \todo In the long run, this should be synchronized with the
* core QOF types, which in turn should be synced to the g_types
* in GLib. Unfortunately, this requires writing a pile of code
* to handle all of the different cases.
* An alternative might be to make kvp values inherit from the
* An alternative might be to make kvp values inherit from the
* core g_types (i.e. add new core g_types) ??
*/
typedef enum {
KVP_TYPE_GINT64=1, /**< QOF_TYPE_INT64 gint64 */
KVP_TYPE_DOUBLE, /**< QOF_TYPE_DOUBLE gdouble */
KVP_TYPE_NUMERIC, /**< QOF_TYPE_NUMERIC */
KVP_TYPE_STRING, /**< QOF_TYPE_STRING gchar* */
KVP_TYPE_GUID, /**< QOF_TYPE_GUID */
KVP_TYPE_TIMESPEC, /**< QOF_TYPE_DATE */
KVP_TYPE_BINARY, /**< no QOF equivalent. */
KVP_TYPE_GLIST, /**< no QOF equivalent. */
KVP_TYPE_FRAME /**< no QOF equivalent. */
typedef enum
{
KVP_TYPE_GINT64 = 1, /**< QOF_TYPE_INT64 gint64 */
KVP_TYPE_DOUBLE, /**< QOF_TYPE_DOUBLE gdouble */
KVP_TYPE_NUMERIC, /**< QOF_TYPE_NUMERIC */
KVP_TYPE_STRING, /**< QOF_TYPE_STRING gchar* */
KVP_TYPE_GUID, /**< QOF_TYPE_GUID */
KVP_TYPE_TIMESPEC, /**< QOF_TYPE_DATE */
KVP_TYPE_BINARY, /**< no QOF equivalent. */
KVP_TYPE_GLIST, /**< no QOF equivalent. */
KVP_TYPE_FRAME /**< no QOF equivalent. */
} KvpValueType;
/** \deprecated Deprecated backwards compat token
do \b not use these in new code.
do \b not use these in new code.
*/
#define kvp_frame KvpFrame
/** \deprecated Deprecated backwards compat token */
#define kvp_value KvpValue
/** \deprecated Deprecated backwards compat token */
#define kvp_value_t KvpValueType
/** @name KvpFrame Constructors
@{
*/
@ -114,14 +115,14 @@ do \b not use these in new code.
/** Return a new empty instance of KvpFrame */
KvpFrame * kvp_frame_new(void);
/** Perform a deep (recursive) delete of the frame and any subframes.
/** Perform a deep (recursive) delete of the frame and any subframes.
* kvp_frame_delete and kvp_value_delete are deep (recursive) deletes.
* kvp_frame_copy and kvp_value_copy are deep value copies.
* kvp_frame_copy and kvp_value_copy are deep value copies.
*/
void kvp_frame_delete(KvpFrame * frame);
/** Perform a deep (recursive) value copy, copying the fraame,
/** Perform a deep (recursive) value copy, copying the fraame,
* subframes, and the values as well. */
KvpFrame * kvp_frame_copy(const KvpFrame * frame);
@ -134,15 +135,15 @@ gboolean kvp_frame_is_empty(const KvpFrame * frame);
@{
*/
/** store the value of the
* gint64 at the indicated path. If not all frame components of
/** store the value of the
* gint64 at the indicated path. If not all frame components of
* the path exist, they are created.
*
*/
void kvp_frame_set_gint64(KvpFrame * frame, const gchar * path, gint64 ival);
/**
* store the value of the
* double at the indicated path. If not all frame components of
* store the value of the
* double at the indicated path. If not all frame components of
* the path exist, they are created.
*/
void kvp_frame_set_double(KvpFrame * frame, const gchar * path, double dval);
@ -152,15 +153,15 @@ void kvp_frame_set_double(KvpFrame * frame, const gchar * path, double dval);
Use kvp_frame_set_numeric instead of kvp_frame_set_gnc_numeric
*/
#define kvp_frame_set_gnc_numeric kvp_frame_set_numeric
/** store the value of the
/** store the value of the
* gnc_numeric at the indicated path.
* If not all frame components of
* If not all frame components of
* the path exist, they are created.
*/
void kvp_frame_set_numeric(KvpFrame * frame, const gchar * path, gnc_numeric nval);
/** store the value of the
/** store the value of the
* Timespec at the indicated path.
* If not all frame components of
* If not all frame components of
* the path exist, they are created.
*/
void kvp_frame_set_timespec(KvpFrame * frame, const gchar * path, Timespec ts);
@ -173,15 +174,15 @@ Use kvp_frame_set_string instead of kvp_frame_set_str
/** \brief Store a copy of the string at the indicated path.
* If not all frame components of the path
* If not all frame components of the path
* exist, they are created. If there was another string previously
* stored at that path, the old copy is deleted.
*
* Similarly, the set_guid and set_frame will make copies and
* store those. Old copies, if any, are deleted.
* store those. Old copies, if any, are deleted.
*
* The kvp_frame_set_frame_nc() routine works as above, but does
* *NOT* copy the frame.
* The kvp_frame_set_frame_nc() routine works as above, but does
* *NOT* copy the frame.
*/
void kvp_frame_set_string(KvpFrame * frame, const gchar * path, const gchar* str);
void kvp_frame_set_guid(KvpFrame * frame, const gchar * path, const GUID *guid);
@ -190,40 +191,40 @@ void kvp_frame_set_frame(KvpFrame *frame, const gchar *path, KvpFrame *chld);
void kvp_frame_set_frame_nc(KvpFrame *frame, const gchar *path, KvpFrame *chld);
/** The kvp_frame_set_value() routine copies the value into the frame,
* at the location 'path'. If the path contains slashes '/', these
* are assumed to represent a sequence of keys. The returned value
* at the location 'path'. If the path contains slashes '/', these
* are assumed to represent a sequence of keys. The returned value
* is a pointer to the actual frame into which the value was inserted;
* it is NULL if the frame couldn't be found (and thus the value wasn't
* it is NULL if the frame couldn't be found (and thus the value wasn't
* inserted). The old value at this location, if any, is destroyed.
*
* Pointers passed as arguments into this routine are the responsibility
* Pointers passed as arguments into this routine are the responsibility
* of the caller; the pointers are *not* taken over or managed.
*/
KvpFrame * kvp_frame_set_value(KvpFrame * frame,
KvpFrame * kvp_frame_set_value(KvpFrame * frame,
const gchar * path, const KvpValue * value);
/**
* The kvp_frame_set_value_nc() routine puts the value (without copying
* it) into the frame, putting it at the location 'path'. If the path
* it) into the frame, putting it at the location 'path'. If the path
* contains slashes '/', these are assumed to represent a sequence of keys.
* The returned value is a pointer to the actual frame into which the value
* was inserted; it is NULL if the frame couldn't be found (and thus the
* The returned value is a pointer to the actual frame into which the value
* was inserted; it is NULL if the frame couldn't be found (and thus the
* value wasn't inserted). The old value at this location, if any,
* is destroyed.
*
* This routine is handy for avoiding excess memory allocations & frees.
* Note that because the KvpValue was grabbed, you can't just delete
* Note that because the KvpValue was grabbed, you can't just delete
* unless you remove the key as well (or unless you replace the value).
*/
KvpFrame * kvp_frame_set_value_nc(KvpFrame * frame,
const gchar * path, KvpValue * value);
KvpFrame * kvp_frame_set_value_nc(KvpFrame * frame,
const gchar * path, KvpValue * value);
/** The kvp_frame_replace_value_nc() routine places the new value
* at the indicated path. It returns the old value, if any.
* It returns NULL if there was an error, or if there was no
/** The kvp_frame_replace_value_nc() routine places the new value
* at the indicated path. It returns the old value, if any.
* It returns NULL if there was an error, or if there was no
* old value. If the path doesn't exist, it is created, unless
* new_value is NULL. Passing in a NULL new_value has the
* new_value is NULL. Passing in a NULL new_value has the
* effect of deleting the trailing slot (i.e. the trailing path
* element).
* element).
*/
KvpValue * kvp_frame_replace_value_nc (KvpFrame * frame, const gchar * slot,
KvpValue * new_value);
@ -236,8 +237,8 @@ KvpValue * kvp_frame_replace_value_nc (KvpFrame * frame, const gchar * slot,
* turning it into a set of key-value pairs, and adding those to the
* indicated frame. URL-encoded strings are the things that are
* returned by web browsers when a form is filled out. For example,
* 'start-date=June&end-date=November' consists of two keys,
* 'start-date' and 'end-date', which have the values 'June' and
* 'start-date=June&end-date=November' consists of two keys,
* 'start-date' and 'end-date', which have the values 'June' and
* 'November', respectively. This routine also handles % encoding.
*
* This routine treats all values as strings; it does *not* attempt
@ -246,19 +247,19 @@ KvpValue * kvp_frame_replace_value_nc (KvpFrame * frame, const gchar * slot,
void kvp_frame_add_url_encoding (KvpFrame *frame, const gchar *enc);
/** @} */
/** @name KvpFrame Glist Bag Storing
/** @name KvpFrame Glist Bag Storing
@{
*/
/** The kvp_frame_add_gint64() routine will add the value of the
* gint64 to the glist bag of values at the indicated path.
* If not all frame components of the path exist, they are
* created. If the value previously stored at this path was
* not a glist bag, then a bag will be formed there, the old
/** The kvp_frame_add_gint64() routine will add the value of the
* gint64 to the glist bag of values at the indicated path.
* If not all frame components of the path exist, they are
* created. If the value previously stored at this path was
* not a glist bag, then a bag will be formed there, the old
* value placed in the bag, and the new value added to the bag.
*
* Similarly, the add_double, add_numeric, and add_timespec
* routines perform the same function, for each of the respective
* Similarly, the add_double, add_numeric, and add_timespec
* routines perform the same function, for each of the respective
* types.
*/
void kvp_frame_add_gint64(KvpFrame * frame, const gchar * path, gint64 ival);
@ -280,17 +281,17 @@ Use kvp_frame_add_string instead of kvp_frame_add_str
/** \brief Copy of the string to the glist bag at the indicated path.
* If not all frame components
* of the path exist, they are created. If there was another
* If not all frame components
* of the path exist, they are created. If there was another
* item previously stored at that path, then the path is converted
* to a bag, and the old value, along with the new value, is added
* to the bag.
*
* Similarly, the add_guid and add_frame will make copies and
* add those.
* add those.
*
* The kvp_frame_add_frame_nc() routine works as above, but does
* *NOT* copy the frame.
* The kvp_frame_add_frame_nc() routine works as above, but does
* *NOT* copy the frame.
*/
void kvp_frame_add_string(KvpFrame * frame, const gchar * path, const gchar* str);
void kvp_frame_add_guid(KvpFrame * frame, const gchar * path, const GUID *guid);
@ -306,7 +307,7 @@ void kvp_frame_add_frame_nc(KvpFrame *frame, const gchar *path, KvpFrame *chld);
* to the bag. This routine returns the pointer to the last frame
* (the actual frame to which the value was added), or NULL if there
* was an error of any sort (typically, a parse error in the path).
*
*
* The *_nc() routine is analogous, except that it doesn't copy the
* value.
*/
@ -318,22 +319,22 @@ KvpFrame * kvp_frame_add_value_nc(KvpFrame * frame, const gchar * path, KvpValue
/** @name KvpFrame Value Fetching
Value accessors. These all take a unix-style slash-separated
Value accessors. These all take a unix-style slash-separated
path as an argument, and return the value stored at that location.
If the object at the end of that path is not of the type that was
asked for, then a NULL or a zero is returned. So, for example,
asking for a string when the path stored an int will return a NULL.
In some future date, this may be changed to a looser type system,
In some future date, this may be changed to a looser type system,
such as perl's automatic re-typing (e.g. an integer value might be
converted to a printed string representing that value).
If any part of the path does not exist, then NULL or zero will be
returned.
The values returned for GUID, binary, GList, KvpFrame and string
The values returned for GUID, binary, GList, KvpFrame and string
are "non-copying" -- the returned item is the actual item stored.
Do not delete this item unless you take the required care to avoid
possible bad pointer derefrences (i.e. core dumps). Also, be
possible bad pointer derefrences (i.e. core dumps). Also, be
careful hanging on to those references if you are also storing
at the same path names: the referenced item will be freed during
the store.
@ -351,7 +352,7 @@ gnc_numeric kvp_frame_get_numeric(const KvpFrame *frame, const gchar *path);
const gchar * kvp_frame_get_string(const KvpFrame *frame, const gchar *path);
GUID * kvp_frame_get_guid(const KvpFrame *frame, const gchar *path);
void * kvp_frame_get_binary(const KvpFrame *frame, const gchar *path,
guint64 * size_return);
guint64 * size_return);
Timespec kvp_frame_get_timespec(const KvpFrame *frame, const gchar *path);
KvpValue * kvp_frame_get_value(const KvpFrame *frame, const gchar *path);
@ -373,10 +374,11 @@ KvpValue * kvp_frame_get_value(const KvpFrame *frame, const gchar *path);
* @return The KvpFrame at the specified path, or NULL if it doesn't
* exist.
*/
/*@ dependent @*/ KvpFrame * kvp_frame_get_frame(const KvpFrame *frame, const gchar *path);
/*@ dependent @*/
KvpFrame * kvp_frame_get_frame(const KvpFrame *frame, const gchar *path);
/** This routine returns the last frame of the path.
* If the frame path doesn't exist, it is created.
* If the frame path doesn't exist, it is created.
* Note that this is *VERY DIFFERENT FROM* like kvp_frame_get_frame()
*
* @note The semantics of this function implemented the gnucash-1.8
@ -388,28 +390,28 @@ KvpValue * kvp_frame_get_value(const KvpFrame *frame, const gchar *path);
* kvp_frame_get_frame_path(). This happened on 2003-09-14, revision
* 1.31.
*/
KvpFrame * kvp_frame_get_frame_path (KvpFrame *frame, const gchar *,...);
KvpFrame * kvp_frame_get_frame_path (KvpFrame *frame, const gchar *, ...);
/** This routine returns the last frame of the path.
* If the frame path doesn't exist, it is created.
* If the frame path doesn't exist, it is created.
* Note that this is *VERY DIFFERENT FROM* kvp_frame_get_frame()
*/
KvpFrame * kvp_frame_get_frame_gslist (KvpFrame *frame,
const GSList *key_path);
const GSList *key_path);
/** This routine returns the last frame of the path.
* If the frame path doesn't exist, it is created.
* If the frame path doesn't exist, it is created.
* Note that this is *VERY DIFFERENT FROM* kvp_frame_get_frame()
*
* The kvp_frame_get_frame_slash() routine takes a single string
* where the keys are separated by slashes; thus, for example:
* /this/is/a/valid/path and///so//is////this/
* Multiple slashes are compresed. Leading slash is optional.
* The pointers . and .. are *not* currently followed/obeyed.
* The pointers . and .. are *not* currently followed/obeyed.
* (This is a bug that needs fixing).
*/
KvpFrame * kvp_frame_get_frame_slash (KvpFrame *frame,
const gchar *path);
const gchar *path);
/** @} */
/** @name KvpFrame KvpValue low-level storing routines.
@ -418,8 +420,8 @@ You probably shouldn't be using these low-level routines
All of the kvp_frame_set_slot_*() routines set the slot values
"destructively", in that if there was an old value there, that
old value is destroyed (and the memory freed). Thus, one
should not hang on to value pointers, as these will get
old value is destroyed (and the memory freed). Thus, one
should not hang on to value pointers, as these will get
trashed if set_slot is called on the corresponding key.
If you want the old value, use kvp_frame_replace_slot().
@ -434,31 +436,31 @@ You probably shouldn't be using these low-level routines
* slot.
*/
KvpValue * kvp_frame_replace_slot_nc (KvpFrame * frame, const gchar * slot,
KvpValue * new_value);
KvpValue * new_value);
/** The kvp_frame_set_slot() routine copies the value into the frame,
* associating it with a copy of 'key'. Pointers passed as arguments
* associating it with a copy of 'key'. Pointers passed as arguments
* into kvp_frame_set_slot are the responsibility of the caller;
* the pointers are *not* taken over or managed. The old value at
* this location, if any, is destroyed.
*/
void kvp_frame_set_slot(KvpFrame * frame,
void kvp_frame_set_slot(KvpFrame * frame,
const gchar * key, const KvpValue * value);
/**
* The kvp_frame_set_slot_nc() routine puts the value (without copying
* it) into the frame, associating it with a copy of 'key'. This
* it) into the frame, associating it with a copy of 'key'. This
* routine is handy for avoiding excess memory allocations & frees.
* Note that because the KvpValue was grabbed, you can't just delete
* Note that because the KvpValue was grabbed, you can't just delete
* unless you remove the key as well (or unless you replace the value).
* The old value at this location, if any, is destroyed.
*/
void kvp_frame_set_slot_nc(KvpFrame * frame,
void kvp_frame_set_slot_nc(KvpFrame * frame,
const gchar * key, KvpValue * value);
/** The kvp_frame_set_slot_path() routine walks the hierarchy,
* using the key values to pick each branch. When the terminal
* node is reached, the value is copied into it. The old value
* using the key values to pick each branch. When the terminal
* node is reached, the value is copied into it. The old value
* at this location, if any, is destroyed.
*/
void kvp_frame_set_slot_path (KvpFrame *frame,
@ -471,8 +473,8 @@ void kvp_frame_set_slot_path (KvpFrame *frame,
* location, if any, is destroyed.
*/
void kvp_frame_set_slot_path_gslist (KvpFrame *frame,
const KvpValue *value,
GSList *key_path);
const KvpValue *value,
GSList *key_path);
/** @} */
@ -480,9 +482,9 @@ void kvp_frame_set_slot_path_gslist (KvpFrame *frame,
You probably shouldn't be using these low-level routines
Returns the KvpValue in the given KvpFrame 'frame' that is
Returns the KvpValue in the given KvpFrame 'frame' that is
associated with 'key'. If there is no key in the frame, NULL
is returned. If the value associated with the key is NULL,
is returned. If the value associated with the key is NULL,
NULL is returned.
Pointers passed as arguments into get_slot are the responsibility
@ -496,13 +498,13 @@ KvpValue * kvp_frame_get_slot(const KvpFrame * frame, const gchar * key);
* path, or NULL if any portion of the path doesn't exist.
*/
KvpValue * kvp_frame_get_slot_path (KvpFrame *frame,
const gchar *first_key, ...);
const gchar *first_key, ...);
/** This routine return the value at the end of the
* path, or NULL if any portion of the path doesn't exist.
*/
KvpValue * kvp_frame_get_slot_path_gslist (KvpFrame *frame,
const GSList *key_path);
const GSList *key_path);
/**
* Similar returns as strcmp.
@ -513,7 +515,7 @@ gint double_compare(double v1, double v2);
/** @} */
/** @name KvpValue List Convenience Functions
You probably shouldn't be using these low-level routines
You probably shouldn't be using these low-level routines
kvp_glist_compare() compares <b>GLists of kvp_values</b> (not to
be confused with GLists of something else): it iterates over
@ -522,7 +524,7 @@ gint double_compare(double v1, double v2);
*/
gint kvp_glist_compare(const GList * list1, const GList * list2);
/** kvp_glist_copy() performs a deep copy of a <b>GList of
/** kvp_glist_copy() performs a deep copy of a <b>GList of
* kvp_values</b> (not to be confused with GLists of something
* else): same as mapping kvp_value_copy() over the elements and
* then copying the spine.
@ -544,7 +546,7 @@ void kvp_glist_delete(GList * list);
The following routines are constructors for kvp_value.
Those with pointer arguments copy in the value.
The *_nc() versions do *not* copy in thier values,
The *_nc() versions do *not* copy in thier values,
but use them directly.
@{
*/
@ -572,7 +574,7 @@ KvpValue * kvp_value_new_glist(const GList * value);
KvpValue * kvp_value_new_binary_nc(void * data, guint64 datasize);
/** Creates a KvpValue from a <b>GList of kvp_value's</b>! (Not to be
* confused with GList's of something else!)
* confused with GList's of something else!)
*
* This value constructor is non-copying (KvpValue takes pointer
* ownership). The values *must* have been allocated via glib
@ -600,7 +602,7 @@ GList * kvp_value_replace_glist_nc(KvpValue *value, GList *newlist);
/** @name KvpValue Value access
You probably shouldn't be using these low-level routines
You probably shouldn't be using these low-level routines
@{
*/
@ -608,11 +610,11 @@ KvpValueType kvp_value_get_type(const KvpValue * value);
/** Value accessors. Those for GUID, binary, GList, KvpFrame and
* string are non-copying -- the caller can modify the value
* string are non-copying -- the caller can modify the value
* directly. Just don't free it, or you screw up everything.
* Note that if another value is stored at the key location
* that this value came from, then this value will be
* uncermoniously deleted, and you will be left pointing to
* that this value came from, then this value will be
* uncermoniously deleted, and you will be left pointing to
* garbage. So don't store values at the same time you are
* examining their contents.
*/
@ -632,7 +634,7 @@ GUID * kvp_value_get_guid(const KvpValue * value);
/** Value accessor. This one is non-copying -- the caller can modify
* the value directly. */
void * kvp_value_get_binary(const KvpValue * value,
guint64 * size_return);
guint64 * size_return);
/** Returns the GList of kvp_frame's (not to be confused with GList's
* of something else!) from the given kvp_frame. This one is
@ -641,7 +643,8 @@ GList * kvp_value_get_glist(const KvpValue * value);
/** Value accessor. This one is non-copying -- the caller can modify
* the value directly. */
/*@ dependent @*/ KvpFrame * kvp_value_get_frame(const KvpValue * value);
/*@ dependent @*/
KvpFrame * kvp_value_get_frame(const KvpValue * value);
Timespec kvp_value_get_timespec(const KvpValue * value);
/**
@ -664,7 +667,7 @@ itself a debugging and development utility function.
*/
gchar* kvp_value_to_string(const KvpValue *val);
/** Manipulator:
/** Manipulator:
*
* copying - but more efficient than creating a new KvpValue manually. */
gboolean kvp_value_binary_append(KvpValue *v, void *data, guint64 size);

View File

@ -62,15 +62,15 @@ static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
(RFC 1321, 3.3: Step 3) */
void
md5_init_ctx (ctx)
struct md5_ctx *ctx;
struct md5_ctx *ctx;
{
ctx->A = 0x67452301;
ctx->B = 0xefcdab89;
ctx->C = 0x98badcfe;
ctx->D = 0x10325476;
ctx->A = 0x67452301;
ctx->B = 0xefcdab89;
ctx->C = 0x98badcfe;
ctx->D = 0x10325476;
ctx->total[0] = ctx->total[1] = 0;
ctx->buflen = 0;
ctx->total[0] = ctx->total[1] = 0;
ctx->buflen = 0;
}
/* Put result from CTX in first 16 bytes following RESBUF. The result
@ -80,15 +80,15 @@ md5_init_ctx (ctx)
aligned for a 32 bits value. */
void *
md5_read_ctx (ctx, resbuf)
const struct md5_ctx *ctx;
void *resbuf;
const struct md5_ctx *ctx;
void *resbuf;
{
((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
return resbuf;
return resbuf;
}
/* Process the remaining bytes in the internal buffer and the usual
@ -98,30 +98,30 @@ md5_read_ctx (ctx, resbuf)
aligned for a 32 bits value. */
void *
md5_finish_ctx (ctx, resbuf)
struct md5_ctx *ctx;
void *resbuf;
struct md5_ctx *ctx;
void *resbuf;
{
/* Take yet unprocessed bytes into account. */
md5_uint32 bytes = ctx->buflen;
size_t pad;
/* Take yet unprocessed bytes into account. */
md5_uint32 bytes = ctx->buflen;
size_t pad;
/* Now count remaining bytes. */
ctx->total[0] += bytes;
if (ctx->total[0] < bytes)
++ctx->total[1];
/* Now count remaining bytes. */
ctx->total[0] += bytes;
if (ctx->total[0] < bytes)
++ctx->total[1];
pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
memcpy (&ctx->buffer[bytes], fillbuf, pad);
pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
memcpy (&ctx->buffer[bytes], fillbuf, pad);
/* Put the 64-bit file length in *bits* at the end of the buffer. */
*(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3);
*(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) |
(ctx->total[0] >> 29));
/* Put the 64-bit file length in *bits* at the end of the buffer. */
*(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3);
*(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) |
(ctx->total[0] >> 29));
/* Process last bytes. */
md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
/* Process last bytes. */
md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
return md5_read_ctx (ctx, resbuf);
return md5_read_ctx (ctx, resbuf);
}
/* Compute MD5 message digest for bytes read from STREAM. The
@ -129,55 +129,55 @@ md5_finish_ctx (ctx, resbuf)
beginning at RESBLOCK. */
int
md5_stream (stream, resblock)
FILE *stream;
void *resblock;
FILE *stream;
void *resblock;
{
/* Important: BLOCKSIZE must be a multiple of 64. */
/* Important: BLOCKSIZE must be a multiple of 64. */
#define BLOCKSIZE 4096
struct md5_ctx ctx;
char buffer[BLOCKSIZE + 72];
size_t sum;
struct md5_ctx ctx;
char buffer[BLOCKSIZE + 72];
size_t sum;
/* Initialize the computation context. */
md5_init_ctx (&ctx);
/* Initialize the computation context. */
md5_init_ctx (&ctx);
/* Iterate over full file contents. */
while (1)
/* Iterate over full file contents. */
while (1)
{
/* We read the file in blocks of BLOCKSIZE bytes. One call of the
computation function processes the whole buffer so that with the
next round of the loop another block can be read. */
size_t n;
sum = 0;
/* We read the file in blocks of BLOCKSIZE bytes. One call of the
computation function processes the whole buffer so that with the
next round of the loop another block can be read. */
size_t n;
sum = 0;
/* Read block. Take care for partial reads. */
do
{
n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
/* Read block. Take care for partial reads. */
do
{
n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
sum += n;
}
while (sum < BLOCKSIZE && n != 0);
if (n == 0 && ferror (stream))
return 1;
sum += n;
}
while (sum < BLOCKSIZE && n != 0);
if (n == 0 && ferror (stream))
return 1;
/* If end of file is reached, end the loop. */
if (n == 0)
break;
/* If end of file is reached, end the loop. */
if (n == 0)
break;
/* Process buffer with BLOCKSIZE bytes. Note that
BLOCKSIZE % 64 == 0
*/
md5_process_block (buffer, BLOCKSIZE, &ctx);
/* Process buffer with BLOCKSIZE bytes. Note that
BLOCKSIZE % 64 == 0
*/
md5_process_block (buffer, BLOCKSIZE, &ctx);
}
/* Add the last bytes if necessary. */
if (sum > 0)
md5_process_bytes (buffer, sum, &ctx);
/* Add the last bytes if necessary. */
if (sum > 0)
md5_process_bytes (buffer, sum, &ctx);
/* Construct result in desired memory. */
md5_finish_ctx (&ctx, resblock);
return 0;
/* Construct result in desired memory. */
md5_finish_ctx (&ctx, resblock);
return 0;
}
/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
@ -186,90 +186,90 @@ md5_stream (stream, resblock)
digest. */
void *
md5_buffer (buffer, len, resblock)
const char *buffer;
size_t len;
void *resblock;
const char *buffer;
size_t len;
void *resblock;
{
struct md5_ctx ctx;
struct md5_ctx ctx;
/* Initialize the computation context. */
md5_init_ctx (&ctx);
/* Initialize the computation context. */
md5_init_ctx (&ctx);
/* Process whole buffer but last len % 64 bytes. */
md5_process_bytes (buffer, len, &ctx);
/* Process whole buffer but last len % 64 bytes. */
md5_process_bytes (buffer, len, &ctx);
/* Put result in desired memory area. */
return md5_finish_ctx (&ctx, resblock);
/* Put result in desired memory area. */
return md5_finish_ctx (&ctx, resblock);
}
void
md5_process_bytes (buffer, len, ctx)
const void *buffer;
size_t len;
struct md5_ctx *ctx;
const void *buffer;
size_t len;
struct md5_ctx *ctx;
{
#define NUM_MD5_WORDS 1024
size_t add = 0;
size_t add = 0;
/* When we already have some bits in our internal buffer concatenate
both inputs first. */
if (ctx->buflen != 0)
/* When we already have some bits in our internal buffer concatenate
both inputs first. */
if (ctx->buflen != 0)
{
size_t left_over = ctx->buflen;
size_t left_over = ctx->buflen;
add = 128 - left_over > len ? len : 128 - left_over;
add = 128 - left_over > len ? len : 128 - left_over;
memcpy (&ctx->buffer[left_over], buffer, add);
ctx->buflen += add;
memcpy (&ctx->buffer[left_over], buffer, add);
ctx->buflen += add;
if (left_over + add > 64)
{
md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx);
/* The regions in the following copy operation cannot overlap. */
memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
(left_over + add) & 63);
ctx->buflen = (left_over + add) & 63;
}
if (left_over + add > 64)
{
md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx);
/* The regions in the following copy operation cannot overlap. */
memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
(left_over + add) & 63);
ctx->buflen = (left_over + add) & 63;
}
buffer = (const char *) buffer + add;
len -= add;
buffer = (const char *) buffer + add;
len -= add;
}
/* Process available complete blocks. */
if (len > 64)
/* Process available complete blocks. */
if (len > 64)
{
if ((add & 3) == 0) /* buffer is still 32-bit aligned */
if ((add & 3) == 0) /* buffer is still 32-bit aligned */
{
md5_process_block (buffer, len & ~63, ctx);
buffer = (const char *) buffer + (len & ~63);
md5_process_block (buffer, len & ~63, ctx);
buffer = (const char *) buffer + (len & ~63);
}
else /* buffer is not 32-bit aligned */
else /* buffer is not 32-bit aligned */
{
md5_uint32 md5_buffer[NUM_MD5_WORDS];
size_t num_bytes;
size_t buf_bytes;
md5_uint32 md5_buffer[NUM_MD5_WORDS];
size_t num_bytes;
size_t buf_bytes;
num_bytes = len & ~63;
while (num_bytes > 0)
num_bytes = len & ~63;
while (num_bytes > 0)
{
buf_bytes = (num_bytes < sizeof(md5_buffer)) ?
num_bytes : sizeof(md5_buffer);
memcpy (md5_buffer, buffer, buf_bytes);
md5_process_block (md5_buffer, buf_bytes, ctx);
num_bytes -= buf_bytes;
buffer = (const char *) buffer + buf_bytes;
buf_bytes = (num_bytes < sizeof(md5_buffer)) ?
num_bytes : sizeof(md5_buffer);
memcpy (md5_buffer, buffer, buf_bytes);
md5_process_block (md5_buffer, buf_bytes, ctx);
num_bytes -= buf_bytes;
buffer = (const char *) buffer + buf_bytes;
}
}
len &= 63;
len &= 63;
}
/* Move remaining bytes in internal buffer. */
if (len > 0)
/* Move remaining bytes in internal buffer. */
if (len > 0)
{
memcpy (ctx->buffer, buffer, len);
ctx->buflen = len;
memcpy (ctx->buffer, buffer, len);
ctx->buflen = len;
}
}
@ -288,42 +288,42 @@ md5_process_bytes (buffer, len, ctx)
void
md5_process_block (buffer, len, ctx)
const void *buffer;
size_t len;
struct md5_ctx *ctx;
const void *buffer;
size_t len;
struct md5_ctx *ctx;
{
md5_uint32 correct_words[16];
const md5_uint32 *words = buffer;
size_t nwords = len / sizeof (md5_uint32);
const md5_uint32 *endp = words + nwords;
md5_uint32 A = ctx->A;
md5_uint32 B = ctx->B;
md5_uint32 C = ctx->C;
md5_uint32 D = ctx->D;
md5_uint32 correct_words[16];
const md5_uint32 *words = buffer;
size_t nwords = len / sizeof (md5_uint32);
const md5_uint32 *endp = words + nwords;
md5_uint32 A = ctx->A;
md5_uint32 B = ctx->B;
md5_uint32 C = ctx->C;
md5_uint32 D = ctx->D;
/* First increment the byte count. RFC 1321 specifies the possible
length of the file up to 2^64 bits. Here we only compute the
number of bytes. Do a double word increment. */
ctx->total[0] += len;
if (ctx->total[0] < len)
++ctx->total[1];
/* First increment the byte count. RFC 1321 specifies the possible
length of the file up to 2^64 bits. Here we only compute the
number of bytes. Do a double word increment. */
ctx->total[0] += len;
if (ctx->total[0] < len)
++ctx->total[1];
/* Process all bytes in the buffer with 64 bytes in each round of
the loop. */
while (words < endp)
/* Process all bytes in the buffer with 64 bytes in each round of
the loop. */
while (words < endp)
{
md5_uint32 *cwp = correct_words;
md5_uint32 A_save = A;
md5_uint32 B_save = B;
md5_uint32 C_save = C;
md5_uint32 D_save = D;
md5_uint32 *cwp = correct_words;
md5_uint32 A_save = A;
md5_uint32 B_save = B;
md5_uint32 C_save = C;
md5_uint32 D_save = D;
/* First round: using the given function, the context and a constant
the next context is computed. Because the algorithms processing
unit is a 32-bit word and it is determined to work on words in
little endian byte order we perhaps have to change the byte order
before the computation. To reduce the work for the next steps
we store the swapped words in the array CORRECT_WORDS. */
/* First round: using the given function, the context and a constant
the next context is computed. Because the algorithms processing
unit is a 32-bit word and it is determined to work on words in
little endian byte order we perhaps have to change the byte order
before the computation. To reduce the work for the next steps
we store the swapped words in the array CORRECT_WORDS. */
#define OP(a, b, c, d, s, T) \
do \
@ -335,37 +335,37 @@ md5_process_block (buffer, len, ctx)
} \
while (0)
/* It is unfortunate that C does not provide an operator for
cyclic rotation. Hope the C compiler is smart enough. */
/* It is unfortunate that C does not provide an operator for
cyclic rotation. Hope the C compiler is smart enough. */
#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
/* Before we start, one word to the strange constants.
They are defined in RFC 1321 as
/* Before we start, one word to the strange constants.
They are defined in RFC 1321 as
T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
*/
T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
*/
/* Round 1. */
OP (A, B, C, D, 7, 0xd76aa478);
OP (D, A, B, C, 12, 0xe8c7b756);
OP (C, D, A, B, 17, 0x242070db);
OP (B, C, D, A, 22, 0xc1bdceee);
OP (A, B, C, D, 7, 0xf57c0faf);
OP (D, A, B, C, 12, 0x4787c62a);
OP (C, D, A, B, 17, 0xa8304613);
OP (B, C, D, A, 22, 0xfd469501);
OP (A, B, C, D, 7, 0x698098d8);
OP (D, A, B, C, 12, 0x8b44f7af);
OP (C, D, A, B, 17, 0xffff5bb1);
OP (B, C, D, A, 22, 0x895cd7be);
OP (A, B, C, D, 7, 0x6b901122);
OP (D, A, B, C, 12, 0xfd987193);
OP (C, D, A, B, 17, 0xa679438e);
OP (B, C, D, A, 22, 0x49b40821);
/* Round 1. */
OP (A, B, C, D, 7, 0xd76aa478);
OP (D, A, B, C, 12, 0xe8c7b756);
OP (C, D, A, B, 17, 0x242070db);
OP (B, C, D, A, 22, 0xc1bdceee);
OP (A, B, C, D, 7, 0xf57c0faf);
OP (D, A, B, C, 12, 0x4787c62a);
OP (C, D, A, B, 17, 0xa8304613);
OP (B, C, D, A, 22, 0xfd469501);
OP (A, B, C, D, 7, 0x698098d8);
OP (D, A, B, C, 12, 0x8b44f7af);
OP (C, D, A, B, 17, 0xffff5bb1);
OP (B, C, D, A, 22, 0x895cd7be);
OP (A, B, C, D, 7, 0x6b901122);
OP (D, A, B, C, 12, 0xfd987193);
OP (C, D, A, B, 17, 0xa679438e);
OP (B, C, D, A, 22, 0x49b40821);
/* For the second to fourth round we have the possibly swapped words
in CORRECT_WORDS. Redefine the macro to take an additional first
argument specifying the function to use. */
/* For the second to fourth round we have the possibly swapped words
in CORRECT_WORDS. Redefine the macro to take an additional first
argument specifying the function to use. */
#undef OP
#define OP(f, a, b, c, d, k, s, T) \
do \
@ -376,70 +376,70 @@ md5_process_block (buffer, len, ctx)
} \
while (0)
/* Round 2. */
OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
OP (FG, D, A, B, C, 6, 9, 0xc040b340);
OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
OP (FG, D, A, B, C, 10, 9, 0x02441453);
OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
/* Round 2. */
OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
OP (FG, D, A, B, C, 6, 9, 0xc040b340);
OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
OP (FG, D, A, B, C, 10, 9, 0x02441453);
OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
/* Round 3. */
OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
OP (FH, D, A, B, C, 8, 11, 0x8771f681);
OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
OP (FH, B, C, D, A, 6, 23, 0x04881d05);
OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
/* Round 3. */
OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
OP (FH, D, A, B, C, 8, 11, 0x8771f681);
OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
OP (FH, B, C, D, A, 6, 23, 0x04881d05);
OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
/* Round 4. */
OP (FI, A, B, C, D, 0, 6, 0xf4292244);
OP (FI, D, A, B, C, 7, 10, 0x432aff97);
OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
OP (FI, C, D, A, B, 6, 15, 0xa3014314);
OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
/* Round 4. */
OP (FI, A, B, C, D, 0, 6, 0xf4292244);
OP (FI, D, A, B, C, 7, 10, 0x432aff97);
OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
OP (FI, C, D, A, B, 6, 15, 0xa3014314);
OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
/* Add the starting values of the context. */
A += A_save;
B += B_save;
C += C_save;
D += D_save;
/* Add the starting values of the context. */
A += A_save;
B += B_save;
C += C_save;
D += D_save;
}
/* Put checksum in context given as argument. */
ctx->A = A;
ctx->B = B;
ctx->C = C;
ctx->D = D;
/* Put checksum in context given as argument. */
ctx->A = A;
ctx->B = B;
ctx->C = C;
ctx->D = D;
}

View File

@ -55,17 +55,17 @@ typedef u_int32_t md5_uint32;
# endif
# if UINT_MAX == UINT_MAX_32_BITS
typedef unsigned int md5_uint32;
typedef unsigned int md5_uint32;
# else
# if USHRT_MAX == UINT_MAX_32_BITS
typedef unsigned short md5_uint32;
typedef unsigned short md5_uint32;
# else
# if ULONG_MAX == UINT_MAX_32_BITS
typedef unsigned long md5_uint32;
typedef unsigned long md5_uint32;
# else
/* The following line is intended to evoke an error.
Using #error is not portable enough. */
"Cannot determine unsigned 32-bit data type."
/* The following line is intended to evoke an error.
Using #error is not portable enough. */
"Cannot determine unsigned 32-bit data type."
# endif
# endif
# endif
@ -81,14 +81,14 @@ typedef u_int32_t md5_uint32;
/* Structure to save state of computation between the single steps. */
struct md5_ctx
{
md5_uint32 A;
md5_uint32 B;
md5_uint32 C;
md5_uint32 D;
md5_uint32 A;
md5_uint32 B;
md5_uint32 C;
md5_uint32 D;
md5_uint32 total[2];
md5_uint32 buflen;
char buffer[128];
md5_uint32 total[2];
md5_uint32 buflen;
char buffer[128];
};
/*
@ -110,7 +110,7 @@ extern void md5_init_ctx __P ((struct md5_ctx *ctx));
IMPORTANT: On some systems it is required that buffer be 32-bit
aligned. */
extern void md5_process_block __P ((const void *buffer, size_t len,
struct md5_ctx *ctx));
struct md5_ctx *ctx));
/* Starting with the result of former calls of this function (or the
initialization function) update the context for the next LEN bytes
@ -121,7 +121,7 @@ extern void md5_process_block __P ((const void *buffer, size_t len,
IMPORTANT: On some systems it is required that buffer be 32-bit
aligned. */
extern void md5_process_bytes __P ((const void *buffer, size_t len,
struct md5_ctx *ctx));
struct md5_ctx *ctx));
/* Process the remaining bytes in the buffer and put result from CTX
in first 16 bytes following RESBUF. The result is always in little

View File

@ -1,4 +1,4 @@
/*
/*
* qof-win32.c
*
* Copyright (C) 2007 Andreas Koehler <andi5.py@gmx.net>
@ -47,10 +47,11 @@ qof_time_format_from_utf8(const gchar *utf8_format)
return NULL;
/* malloc and convert */
retval = g_malloc((count+1) * sizeof(gchar));
count = wcstombs(retval, utf16_format, count+1);
retval = g_malloc((count + 1) * sizeof(gchar));
count = wcstombs(retval, utf16_format, count + 1);
g_free(utf16_format);
if (count <= 0) {
if (count <= 0)
{
g_free(retval);
return NULL;
}
@ -71,9 +72,10 @@ qof_formatted_time_to_utf8(const gchar *locale_string)
return NULL;
/* malloc and convert */
utf16_string = g_malloc((count+1) * sizeof(gunichar2));
count = mbstowcs(utf16_string, locale_string, count+1);
if (count <= 0) {
utf16_string = g_malloc((count + 1) * sizeof(gunichar2));
count = mbstowcs(utf16_string, locale_string, count + 1);
if (count <= 0)
{
g_free(utf16_string);
return NULL;
}
@ -90,7 +92,8 @@ qof_win32_get_time_format(QofWin32Picture picture)
gchar *locale_string, *format;
gchar *tmp1, *tmp2;
switch (picture) {
switch (picture)
{
case QOF_WIN32_PICTURE_DATE:
locale_string = get_win32_locale_string(LOCALE_SSHORTDATE);
break;
@ -111,9 +114,10 @@ qof_win32_get_time_format(QofWin32Picture picture)
G_LOCK(picture_to_format);
if (!picture_to_format)
picture_to_format = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, g_free);
NULL, g_free);
format = g_hash_table_lookup(picture_to_format, locale_string);
if (!format) {
if (!format)
{
format = translate_win32_picture(locale_string);
g_hash_table_insert(picture_to_format, g_strdup(locale_string), format);
}

View File

@ -21,7 +21,7 @@
#ifndef QOF_H_
#define QOF_H_
/** @defgroup QOF Query Object Framework
/** @defgroup QOF Query Object Framework
@{
*/

View File

@ -26,15 +26,15 @@
@{ */
/** @name Backend_Private
Pseudo-object defining how the engine can interact with different
back-ends (which may be SQL databases, or network interfaces to
back-ends (which may be SQL databases, or network interfaces to
remote QOF servers. File-io is just one type of backend).
The callbacks will be called at the appropriate times during
The callbacks will be called at the appropriate times during
a book session to allow the backend to store the data as needed.
@file qofbackend-p.h
@brief private api for data storage backend
@author Copyright (c) 2000,2001,2004 Linas Vepstas <linas@linas.org>
@author Copyright (c) 2000,2001,2004 Linas Vepstas <linas@linas.org>
@author Copyright (c) 2005 Neil Williams <linux@codehelp.co.uk>
@{ */
@ -48,7 +48,7 @@
#include "qofsession.h"
/**
* The backend_new routine sets the functions that will be used
* The backend_new routine sets the functions that will be used
* by the backend to perform the actions required by QOF. A
* basic minimum is session_begin, session_end, load and
* sync. Any unused functions should be set to NULL. If the
@ -56,9 +56,9 @@
* that these are set to usable defaults before returning. To use
* configuration options, load_config and get_config must also
* be defined.
*
*
* The session_begin() routine gives the backend a second initialization
* opportunity. It is suggested that the backend check that
* opportunity. It is suggested that the backend check that
* the URL is syntactically correct, and that it is actually
* reachable. This is probably(?) a good time to initialize
* the actual network connection.
@ -66,8 +66,8 @@
* The 'ignore_lock' argument indicates whether the single-user
* lock on the backend should be cleared. The typical GUI sequence
* leading to this is: (1) GUI attempts to open the backend
* by calling this routine with FALSE==ignore_lock. (2) If backend
* error'ed BACKEND_LOCK, then GUI asks user what to do. (3) if user
* by calling this routine with FALSE==ignore_lock. (2) If backend
* error'ed BACKEND_LOCK, then GUI asks user what to do. (3) if user
* answers 'break & enter' then this routine is called again with
* TRUE==ignore_lock.
*
@ -75,7 +75,7 @@
* routine should create a new 'database', if it doesn't already
* exist. For example, for a file-backend, this would create the
* file, if it didn't already exist. For an SQL backend, this
* would create the database (the schema) if it didn't already
* would create the database (the schema) if it didn't already
* exist. This flag is used to implement the 'SaveAs' GUI, where
* the user requests to save data to a new backend.
*
@ -94,9 +94,9 @@
* when a user opened a register, resulting in a query being sent to
* the backend.
*
* (Its OK to send over entities at this point, but one should
* be careful of the network load; also, its possible that whatever
* is sent is not what the user wanted anyway, which is why its
* (Its OK to send over entities at this point, but one should
* be careful of the network load; also, its possible that whatever
* is sent is not what the user wanted anyway, which is why its
* better to wait for the query).
*
* The begin() routine is called when the engine is about to
@ -107,11 +107,11 @@
* backend data storage.
*
* The rollback() routine is used to revert changes in the engine
* and unlock the backend.
* and unlock the backend.
*
* If the second user tries to modify an entity that
* the first user deleted, then the backend should set the error
* to ERR_BACKEND_MOD_DESTROY from this routine, so that the
* to ERR_BACKEND_MOD_DESTROY from this routine, so that the
* engine can properly clean up.
*
* The compile_query() method compiles a QOF query object into
@ -120,7 +120,7 @@
* need to be turned into a corresponding SQL query statement, and
* sent to the database for evaluation.
*
* The free_query() method frees the data structure returned from
* The free_query() method frees the data structure returned from
* compile_query()
*
* The run_query() callback takes a compiled query (generated by
@ -130,30 +130,30 @@
* to poke these into the account-group hierarchy held by the query
* object.
*
* For a network-communications backend, essentially the same is
* done, except that this routine would convert the query to wire
* For a network-communications backend, essentially the same is
* done, except that this routine would convert the query to wire
* protocol, get an answer from the remote server, and push that
* into the account-group object.
*
* The returned list of entities can be used to build a local
* cache of the matching data. This will allow the QOF client to
* cache of the matching data. This will allow the QOF client to
* continue functioning even when disconnected from the server:
* this is because it will have its local cache of data from which to work.
*
* The sync() routine synchronizes the engine contents to the backend.
* This should done by using version numbers (hack alert -- the engine
* does not currently contain version numbers).
* If the engine contents are newer than what is in the backend, the
* If the engine contents are newer than what is in the backend, the
* data is stored to the backend. If the engine contents are older,
* then the engine contents are updated.
* then the engine contents are updated.
*
* Note that this sync operation is only meant to apply to the
* Note that this sync operation is only meant to apply to the
* current contents of the engine. This routine is not intended
* to be used to fetch entity data from the backend.
*
* File based backends tend to use sync as if it was called dump.
* Data is written out into the backend, overwriting the previous
* data. Database backends should implement a more intelligent
* data. Database backends should implement a more intelligent
* solution.
*
* The counter() routine increments the named counter and returns the
@ -185,11 +185,11 @@
* Call the book commit() to complete the book partitioning.
*
* After the begin(), there will be a call to run_query(), followed
* probably by a string of object calls, and completed by commit().
* It should be explicitly understood that the results of that
* run_query() precisely constitute the set of objects that are to
* be moved between the initial and the new book. This specification
* can be used by a clever backend to avoid excess data movement
* probably by a string of object calls, and completed by commit().
* It should be explicitly understood that the results of that
* run_query() precisely constitute the set of objects that are to
* be moved between the initial and the new book. This specification
* can be used by a clever backend to avoid excess data movement
* between the server and the QOF client, as explained below.
*
* There are several possible ways in which a backend may choose to
@ -198,27 +198,27 @@
* write out the new book to a file when the commit() call is made.
* By that point, the engine will have performed all of the
* nitty-gritty of moving transactions from one book to the other.
*
*
* A 'database-type' backend has several interesting choices. One
* simple choice is to simply perform the run_query() as it
* normally would, and likewise treat the object edits as usual.
* In this scenario, the commit() is more or less a no-op.
* This implementation has a drawback, however: the run_query() may
* cause the transfer of a <b>huge</b> amount of data between the backend
* and the engine. For a large dataset, this is quite undesirable.
* In addition, there are risks associated with the loss of network
* connectivity during the transfer; thus a partition might terminate
* normally would, and likewise treat the object edits as usual.
* In this scenario, the commit() is more or less a no-op.
* This implementation has a drawback, however: the run_query() may
* cause the transfer of a <b>huge</b> amount of data between the backend
* and the engine. For a large dataset, this is quite undesirable.
* In addition, there are risks associated with the loss of network
* connectivity during the transfer; thus a partition might terminate
* half-finished, in some indeterminate state, due to network errors.
* It might be difficult to recover from such errors: the engine does
* It might be difficult to recover from such errors: the engine does
* not take any special safety measures during the transfer.
*
* Thus, for a large database, an alternate implementation
* might be to use the run_query() call as an opportunity to
* Thus, for a large database, an alternate implementation
* might be to use the run_query() call as an opportunity to
* transfer entities between the two books in the database,
* and not actually return any new data to the engine. In
* this scenario, the engine will attempt to transfer those
* this scenario, the engine will attempt to transfer those
* entities that it does know about. It does not, however,
* need to know about all the other entities that also would
* need to know about all the other entities that also would
* be transfered over. In this way, a backend could perform
* a mass transfer of entities between books without having
* to actually move much (or any) data to the engine.
@ -240,126 +240,131 @@
struct QofBackendProvider_s
{
/** Some arbitrary name given for this particular backend provider */
/*@ observer @*/ const char * provider_name;
/** Some arbitrary name given for this particular backend provider */
/*@ observer @*/
const char * provider_name;
/** The access method that this provider provides, for example,
* file:// http:// postgres:// or sqlite://, but without the :// at the end
*/
/*@ observer @*/ const char * access_method;
/** The access method that this provider provides, for example,
* file:// http:// postgres:// or sqlite://, but without the :// at the end
*/
/*@ observer @*/
const char * access_method;
/** \brief Partial QofBook handler
TRUE if the backend handles external references
to entities outside this book and can save a QofBook that
does not contain any specific QOF objects.
*/
gboolean partial_book_supported;
/** Return a new, fully initialized backend.
*
* If the backend supports configuration, all configuration options
* should be initialised to usable values here.
* */
QofBackend * (*backend_new) (void);
/** \brief Partial QofBook handler
/** \brief Distinguish two providers with same access method.
More than 1 backend can be registered under the same access_method,
so each one is passed the path to the data (e.g. a file) and
should return TRUE only:
-# if the backend recognises the type as one that it can load and write or
-# if the path contains no data but can be used (e.g. a new session).
\note If the backend can cope with more than one type, the backend
should not try to store or cache the sub-type for this data.
It is sufficient only to return TRUE if any ONE of the supported
types match the incoming data. The backend should not assume that
returning TRUE will mean that the data will naturally follow.
*/
/*@ null @*/ gboolean (*check_data_type) (const char*);
/** Free this structure, unregister this backend handler. */
void (*provider_free) (/*@ only @*/ QofBackendProvider *);
TRUE if the backend handles external references
to entities outside this book and can save a QofBook that
does not contain any specific QOF objects.
*/
gboolean partial_book_supported;
/** Return a new, fully initialized backend.
*
* If the backend supports configuration, all configuration options
* should be initialised to usable values here.
* */
QofBackend * (*backend_new) (void);
/** \brief Distinguish two providers with same access method.
More than 1 backend can be registered under the same access_method,
so each one is passed the path to the data (e.g. a file) and
should return TRUE only:
-# if the backend recognises the type as one that it can load and write or
-# if the path contains no data but can be used (e.g. a new session).
\note If the backend can cope with more than one type, the backend
should not try to store or cache the sub-type for this data.
It is sufficient only to return TRUE if any ONE of the supported
types match the incoming data. The backend should not assume that
returning TRUE will mean that the data will naturally follow.
*/
/*@ null @*/
gboolean (*check_data_type) (const char*);
/** Free this structure, unregister this backend handler. */
void (*provider_free) (/*@ only @*/ QofBackendProvider *);
};
typedef enum {
LOAD_TYPE_INITIAL_LOAD,
LOAD_TYPE_LOAD_ALL
typedef enum
{
LOAD_TYPE_INITIAL_LOAD,
LOAD_TYPE_LOAD_ALL
} QofBackendLoadType;
struct QofBackend_s
{
void (*session_begin) (QofBackend *be,
QofSession *session,
const char *book_id,
gboolean ignore_lock,
gboolean create_if_nonexistent);
void (*session_end) (QofBackend *);
void (*destroy_backend) (/*@ only @*/ QofBackend *);
void (*session_begin) (QofBackend *be,
QofSession *session,
const char *book_id,
gboolean ignore_lock,
gboolean create_if_nonexistent);
void (*session_end) (QofBackend *);
void (*destroy_backend) (/*@ only @*/ QofBackend *);
void (*load) (QofBackend *, /*@ dependent @*/ QofBook *, QofBackendLoadType);
void (*load) (QofBackend *, /*@ dependent @*/ QofBook *, QofBackendLoadType);
void (*begin) (QofBackend *, QofInstance *);
void (*commit) (QofBackend *, QofInstance *);
void (*rollback) (QofBackend *, QofInstance *);
void (*begin) (QofBackend *, QofInstance *);
void (*commit) (QofBackend *, QofInstance *);
void (*rollback) (QofBackend *, QofInstance *);
gpointer (*compile_query) (QofBackend *, QofQuery *);
void (*free_query) (QofBackend *, gpointer);
void (*run_query) (QofBackend *, gpointer);
gpointer (*compile_query) (QofBackend *, QofQuery *);
void (*free_query) (QofBackend *, gpointer);
void (*run_query) (QofBackend *, gpointer);
void (*sync) (QofBackend *, /*@ dependent @*/ QofBook *);
void (*load_config) (QofBackend *, KvpFrame *);
/*@ observer @*/ KvpFrame* (*get_config) (QofBackend *);
gint64 (*counter) (QofBackend *, const char *counter_name);
void (*sync) (QofBackend *, /*@ dependent @*/ QofBook *);
void (*load_config) (QofBackend *, KvpFrame *);
/*@ observer @*/
KvpFrame* (*get_config) (QofBackend *);
gint64 (*counter) (QofBackend *, const char *counter_name);
gboolean (*events_pending) (QofBackend *);
gboolean (*process_events) (QofBackend *);
gboolean (*events_pending) (QofBackend *);
gboolean (*process_events) (QofBackend *);
QofBePercentageFunc percentage;
QofBackendProvider *provider;
QofBePercentageFunc percentage;
/** Detect if the sync operation will overwrite data
*
* File based backends tend to consider the original file
* as 'stale' immediately the data finishes loading. New data
* only exists in memory and the data in the file is completely
* replaced when qof_session_save is called. e.g. this routine can be
* used to detect if a Save As... operation would overwrite a
* possibly unrelated file. Not all file backends use this function.
*
* @return TRUE if the user may need to be warned about possible
* data loss, otherwise FALSE.
*/
gboolean (*save_may_clobber_data) (QofBackend *);
QofBackendProvider *provider;
QofBackendError last_err;
char * error_msg;
/** Detect if the sync operation will overwrite data
*
* File based backends tend to consider the original file
* as 'stale' immediately the data finishes loading. New data
* only exists in memory and the data in the file is completely
* replaced when qof_session_save is called. e.g. this routine can be
* used to detect if a Save As... operation would overwrite a
* possibly unrelated file. Not all file backends use this function.
*
* @return TRUE if the user may need to be warned about possible
* data loss, otherwise FALSE.
*/
gboolean (*save_may_clobber_data) (QofBackend *);
KvpFrame* backend_configuration;
gint config_count;
/** Each backend resolves a fully-qualified file path.
* This holds the filepath and communicates it to the frontends.
*/
char * fullpath;
QofBackendError last_err;
char * error_msg;
/** \deprecated price_lookup should be removed during the redesign
* of the SQL backend... prices can now be queried using
* the generic query mechanism.
*
* Note the correct signature for this call is
* void (*price_lookup) (QofBackend *, GNCPriceLookup *);
* we use gpointer to avoid an unwanted include file dependency.
*/
void (*price_lookup) (QofBackend *, gpointer);
KvpFrame* backend_configuration;
gint config_count;
/** Each backend resolves a fully-qualified file path.
* This holds the filepath and communicates it to the frontends.
*/
char * fullpath;
/** \deprecated Export should really _NOT_ be here, but is left here for now.
* I'm not sure where this should be going to. It should be
* removed ASAP. This is a temporary hack-around until period-closing
* is fully implemented.
*/
void (*export) (QofBackend *, QofBook *);
/** \deprecated price_lookup should be removed during the redesign
* of the SQL backend... prices can now be queried using
* the generic query mechanism.
*
* Note the correct signature for this call is
* void (*price_lookup) (QofBackend *, GNCPriceLookup *);
* we use gpointer to avoid an unwanted include file dependency.
*/
void (*price_lookup) (QofBackend *, gpointer);
/** \deprecated Export should really _NOT_ be here, but is left here for now.
* I'm not sure where this should be going to. It should be
* removed ASAP. This is a temporary hack-around until period-closing
* is fully implemented.
*/
void (*export) (QofBackend *, QofBook *);
};
@ -384,7 +389,7 @@ char * qof_backend_get_message(QofBackend *be);
void qof_backend_init(QofBackend *be);
void qof_backend_destroy(QofBackend *be);
/** Allow backends to see if the book is open
/** Allow backends to see if the book is open
@return 'y' if book is open, otherwise 'n'.
*/

View File

@ -42,70 +42,71 @@ static QofLogModule log_module = QOF_MOD_BACKEND;
* error handling *
\********************************************************************/
void
void
qof_backend_set_error (QofBackend *be, QofBackendError err)
{
if (!be) return;
if (!be) return;
/* use stack-push semantics. Only the earliest error counts */
if (ERR_BACKEND_NO_ERR != be->last_err) return;
be->last_err = err;
/* use stack-push semantics. Only the earliest error counts */
if (ERR_BACKEND_NO_ERR != be->last_err) return;
be->last_err = err;
}
QofBackendError
QofBackendError
qof_backend_get_error (QofBackend *be)
{
QofBackendError err;
if (!be) return ERR_BACKEND_NO_BACKEND;
QofBackendError err;
if (!be) return ERR_BACKEND_NO_BACKEND;
/* use 'stack-pop' semantics */
err = be->last_err;
be->last_err = ERR_BACKEND_NO_ERR;
return err;
/* use 'stack-pop' semantics */
err = be->last_err;
be->last_err = ERR_BACKEND_NO_ERR;
return err;
}
void
qof_backend_set_message (QofBackend *be, const char *format, ...)
qof_backend_set_message (QofBackend *be, const char *format, ...)
{
va_list args;
char * buffer;
if (!be) return;
/* If there's already something here, free it */
if (be->error_msg) g_free(be->error_msg);
va_list args;
char * buffer;
if (!format) {
be->error_msg = NULL;
return;
}
if (!be) return;
va_start(args, format);
buffer = (char *)g_strdup_vprintf(format, args);
va_end(args);
/* If there's already something here, free it */
if (be->error_msg) g_free(be->error_msg);
be->error_msg = buffer;
if (!format)
{
be->error_msg = NULL;
return;
}
va_start(args, format);
buffer = (char *)g_strdup_vprintf(format, args);
va_end(args);
be->error_msg = buffer;
}
char *
qof_backend_get_message (QofBackend *be)
qof_backend_get_message (QofBackend *be)
{
char * msg;
if (!be) return g_strdup("ERR_BACKEND_NO_BACKEND");
if (!be->error_msg) return NULL;
char * msg;
/*
* Just return the contents of the error_msg and then set it to
* NULL. This is necessary, because the Backends don't seem to
* have a destroy_backend function to take care of freeing stuff
* up. The calling function should free the copy.
* Also, this is consistent with the qof_backend_get_error() popping.
*/
if (!be) return g_strdup("ERR_BACKEND_NO_BACKEND");
if (!be->error_msg) return NULL;
msg = be->error_msg;
be->error_msg = NULL;
return msg;
/*
* Just return the contents of the error_msg and then set it to
* NULL. This is necessary, because the Backends don't seem to
* have a destroy_backend function to take care of freeing stuff
* up. The calling function should free the copy.
* Also, this is consistent with the qof_backend_get_error() popping.
*/
msg = be->error_msg;
be->error_msg = NULL;
return msg;
}
/***********************************************************************/
@ -156,102 +157,140 @@ qof_backend_destroy(QofBackend *be)
void
qof_backend_run_begin(QofBackend *be, QofInstance *inst)
{
if(!be || !inst) { return; }
if(!be->begin) { return; }
(be->begin) (be, inst);
if (!be || !inst)
{
return;
}
if (!be->begin)
{
return;
}
(be->begin) (be, inst);
}
gboolean
qof_backend_begin_exists(const QofBackend *be)
{
if(be->begin) { return TRUE; }
else { return FALSE; }
if (be->begin)
{
return TRUE;
}
else
{
return FALSE;
}
}
void
qof_backend_run_commit(QofBackend *be, QofInstance *inst)
{
if(!be || !inst) { return; }
if(!be->commit) { return; }
(be->commit) (be, inst);
if (!be || !inst)
{
return;
}
if (!be->commit)
{
return;
}
(be->commit) (be, inst);
}
/* =========== Backend Configuration ================ */
void qof_backend_prepare_frame(QofBackend *be)
{
g_return_if_fail(be);
if(!kvp_frame_is_empty(be->backend_configuration)) {
kvp_frame_delete(be->backend_configuration);
be->backend_configuration = kvp_frame_new();
}
be->config_count = 0;
g_return_if_fail(be);
if (!kvp_frame_is_empty(be->backend_configuration))
{
kvp_frame_delete(be->backend_configuration);
be->backend_configuration = kvp_frame_new();
}
be->config_count = 0;
}
void qof_backend_prepare_option(QofBackend *be, const QofBackendOption *option)
{
KvpValue *value;
gchar *temp;
gint count;
KvpValue *value;
gchar *temp;
gint count;
g_return_if_fail(be || option);
count = be->config_count;
count++;
value = NULL;
switch (option->type)
{
case KVP_TYPE_GINT64 : {
value = kvp_value_new_gint64(*(gint64*)option->value);
break;
}
case KVP_TYPE_DOUBLE : {
value = kvp_value_new_double(*(double*)option->value);
break;
}
case KVP_TYPE_NUMERIC : {
value = kvp_value_new_numeric(*(gnc_numeric*)option->value);
break;
}
case KVP_TYPE_STRING : {
value = kvp_value_new_string((const char*)option->value);
break;
}
case KVP_TYPE_GUID : { break; } /* unsupported */
case KVP_TYPE_TIMESPEC : {
value = kvp_value_new_timespec(*(Timespec*)option->value);
break;
}
case KVP_TYPE_BINARY : { break; } /* unsupported */
case KVP_TYPE_GLIST : { break; } /* unsupported */
case KVP_TYPE_FRAME : { break; } /* unsupported */
}
if(value) {
temp = g_strdup_printf("/%s", option->option_name);
kvp_frame_set_value(be->backend_configuration, temp, value);
g_free(temp);
temp = g_strdup_printf("/%s/%s", QOF_CONFIG_DESC, option->option_name);
kvp_frame_set_string(be->backend_configuration, temp, option->description);
g_free(temp);
temp = g_strdup_printf("/%s/%s", QOF_CONFIG_TIP, option->option_name);
kvp_frame_set_string(be->backend_configuration, temp, option->tooltip);
g_free(temp);
/* only increment the counter if successful */
be->config_count = count;
}
g_return_if_fail(be || option);
count = be->config_count;
count++;
value = NULL;
switch (option->type)
{
case KVP_TYPE_GINT64 :
{
value = kvp_value_new_gint64(*(gint64*)option->value);
break;
}
case KVP_TYPE_DOUBLE :
{
value = kvp_value_new_double(*(double*)option->value);
break;
}
case KVP_TYPE_NUMERIC :
{
value = kvp_value_new_numeric(*(gnc_numeric*)option->value);
break;
}
case KVP_TYPE_STRING :
{
value = kvp_value_new_string((const char*)option->value);
break;
}
case KVP_TYPE_GUID :
{
break; /* unsupported */
}
case KVP_TYPE_TIMESPEC :
{
value = kvp_value_new_timespec(*(Timespec*)option->value);
break;
}
case KVP_TYPE_BINARY :
{
break; /* unsupported */
}
case KVP_TYPE_GLIST :
{
break; /* unsupported */
}
case KVP_TYPE_FRAME :
{
break; /* unsupported */
}
}
if (value)
{
temp = g_strdup_printf("/%s", option->option_name);
kvp_frame_set_value(be->backend_configuration, temp, value);
g_free(temp);
temp = g_strdup_printf("/%s/%s", QOF_CONFIG_DESC, option->option_name);
kvp_frame_set_string(be->backend_configuration, temp, option->description);
g_free(temp);
temp = g_strdup_printf("/%s/%s", QOF_CONFIG_TIP, option->option_name);
kvp_frame_set_string(be->backend_configuration, temp, option->tooltip);
g_free(temp);
/* only increment the counter if successful */
be->config_count = count;
}
}
KvpFrame* qof_backend_complete_frame(QofBackend *be)
{
g_return_val_if_fail(be, NULL);
be->config_count = 0;
return be->backend_configuration;
g_return_val_if_fail(be, NULL);
be->config_count = 0;
return be->backend_configuration;
}
struct config_iterate {
QofBackendOptionCB fcn;
gpointer data;
gint count;
KvpFrame *recursive;
struct config_iterate
{
QofBackendOptionCB fcn;
gpointer data;
gint count;
KvpFrame *recursive;
};
/* Set the option with the default KvpValue,
@ -261,158 +300,230 @@ in the configuration frame. */
static void
config_foreach_cb (const char *key, KvpValue *value, gpointer data)
{
QofBackendOption option;
gint64 int64;
double db;
gnc_numeric num;
Timespec ts;
gchar *parent;
struct config_iterate *helper;
QofBackendOption option;
gint64 int64;
double db;
gnc_numeric num;
Timespec ts;
gchar *parent;
struct config_iterate *helper;
g_return_if_fail(key || value || data);
helper = (struct config_iterate*)data;
if(!helper->recursive) { PERR (" no parent frame"); return; }
// skip the presets.
if(0 == safe_strcmp(key, QOF_CONFIG_DESC)) { return; }
if(0 == safe_strcmp(key, QOF_CONFIG_TIP)) { return; }
ENTER (" key=%s", key);
option.option_name = key;
option.type = kvp_value_get_type(value);
if(!option.type) { return; }
switch (option.type)
{ /* set the KvpFrame value into the option */
case KVP_TYPE_GINT64 : {
int64 = kvp_value_get_gint64(value);
option.value = (gpointer)&int64;
break;
}
case KVP_TYPE_DOUBLE : {
db = kvp_value_get_double(value);
option.value = (gpointer)&db;
break;
}
case KVP_TYPE_NUMERIC : {
num = kvp_value_get_numeric(value);
option.value = (gpointer)&num;
break;
}
case KVP_TYPE_STRING : {
option.value = (gpointer)kvp_value_get_string(value);
break;
}
case KVP_TYPE_TIMESPEC : {
ts = kvp_value_get_timespec(value);
option.value = (gpointer)&ts;
break;
}
case KVP_TYPE_GUID : { break; } /* unsupported */
case KVP_TYPE_BINARY : { break; } /* unsupported */
case KVP_TYPE_GLIST : { break; } /* unsupported */
case KVP_TYPE_FRAME : { break; } /* unsupported */
}
parent = g_strdup_printf("/%s/%s", QOF_CONFIG_DESC, key);
option.description = kvp_frame_get_string(helper->recursive, parent);
g_free(parent);
parent = g_strdup_printf("/%s/%s", QOF_CONFIG_TIP, key);
option.tooltip = kvp_frame_get_string(helper->recursive, parent);
g_free(parent);
helper->count++;
g_return_if_fail(key || value || data);
helper = (struct config_iterate*)data;
if (!helper->recursive)
{
PERR (" no parent frame");
return;
}
// skip the presets.
if (0 == safe_strcmp(key, QOF_CONFIG_DESC))
{
return;
}
if (0 == safe_strcmp(key, QOF_CONFIG_TIP))
{
return;
}
ENTER (" key=%s", key);
option.option_name = key;
option.type = kvp_value_get_type(value);
if (!option.type)
{
return;
}
switch (option.type)
{ /* set the KvpFrame value into the option */
case KVP_TYPE_GINT64 :
{
int64 = kvp_value_get_gint64(value);
option.value = (gpointer) & int64;
break;
}
case KVP_TYPE_DOUBLE :
{
db = kvp_value_get_double(value);
option.value = (gpointer) & db;
break;
}
case KVP_TYPE_NUMERIC :
{
num = kvp_value_get_numeric(value);
option.value = (gpointer) & num;
break;
}
case KVP_TYPE_STRING :
{
option.value = (gpointer)kvp_value_get_string(value);
break;
}
case KVP_TYPE_TIMESPEC :
{
ts = kvp_value_get_timespec(value);
option.value = (gpointer) & ts;
break;
}
case KVP_TYPE_GUID :
{
break; /* unsupported */
}
case KVP_TYPE_BINARY :
{
break; /* unsupported */
}
case KVP_TYPE_GLIST :
{
break; /* unsupported */
}
case KVP_TYPE_FRAME :
{
break; /* unsupported */
}
}
parent = g_strdup_printf("/%s/%s", QOF_CONFIG_DESC, key);
option.description = kvp_frame_get_string(helper->recursive, parent);
g_free(parent);
parent = g_strdup_printf("/%s/%s", QOF_CONFIG_TIP, key);
option.tooltip = kvp_frame_get_string(helper->recursive, parent);
g_free(parent);
helper->count++;
/* manipulate the option */
helper->fcn (&option, helper->data);
switch (option.type)
{ /* set the option value into the KvpFrame */
case KVP_TYPE_GINT64 : {
kvp_frame_set_gint64(helper->recursive, key,
(*(gint64*)option.value));
break;
}
case KVP_TYPE_DOUBLE : {
kvp_frame_set_double(helper->recursive, key,
(*(double*)option.value));
break;
}
case KVP_TYPE_NUMERIC : {
kvp_frame_set_numeric(helper->recursive, key,
(*(gnc_numeric*)option.value));
break;
}
case KVP_TYPE_STRING : {
kvp_frame_set_string(helper->recursive, key,
(gchar*)option.value);
break;
}
case KVP_TYPE_TIMESPEC : {
kvp_frame_set_timespec(helper->recursive, key,
(*(Timespec*)option.value));
break;
}
case KVP_TYPE_GUID : { break; } /* unsupported */
case KVP_TYPE_BINARY : { break; } /* unsupported */
case KVP_TYPE_GLIST : { break; } /* unsupported */
case KVP_TYPE_FRAME : { break; } /* unsupported */
}
LEAVE (" ");
helper->fcn (&option, helper->data);
switch (option.type)
{ /* set the option value into the KvpFrame */
case KVP_TYPE_GINT64 :
{
kvp_frame_set_gint64(helper->recursive, key,
(*(gint64*)option.value));
break;
}
case KVP_TYPE_DOUBLE :
{
kvp_frame_set_double(helper->recursive, key,
(*(double*)option.value));
break;
}
case KVP_TYPE_NUMERIC :
{
kvp_frame_set_numeric(helper->recursive, key,
(*(gnc_numeric*)option.value));
break;
}
case KVP_TYPE_STRING :
{
kvp_frame_set_string(helper->recursive, key,
(gchar*)option.value);
break;
}
case KVP_TYPE_TIMESPEC :
{
kvp_frame_set_timespec(helper->recursive, key,
(*(Timespec*)option.value));
break;
}
case KVP_TYPE_GUID :
{
break; /* unsupported */
}
case KVP_TYPE_BINARY :
{
break; /* unsupported */
}
case KVP_TYPE_GLIST :
{
break; /* unsupported */
}
case KVP_TYPE_FRAME :
{
break; /* unsupported */
}
}
LEAVE (" ");
}
void qof_backend_option_foreach(KvpFrame *config, QofBackendOptionCB cb, gpointer data)
{
struct config_iterate helper;
struct config_iterate helper;
if(!config || !cb) { return; }
ENTER (" ");
helper.fcn = cb;
helper.count = 1;
helper.data = data;
helper.recursive = config;
kvp_frame_for_each_slot(config, config_foreach_cb, &helper);
LEAVE (" ");
if (!config || !cb)
{
return;
}
ENTER (" ");
helper.fcn = cb;
helper.count = 1;
helper.data = data;
helper.recursive = config;
kvp_frame_for_each_slot(config, config_foreach_cb, &helper);
LEAVE (" ");
}
void
qof_backend_load_config(QofBackend *be, KvpFrame *config)
{
if(!be || !config) { return; }
if(!be->load_config) { return; }
(be->load_config) (be, config);
if (!be || !config)
{
return;
}
if (!be->load_config)
{
return;
}
(be->load_config) (be, config);
}
KvpFrame*
qof_backend_get_config(QofBackend *be)
{
if(!be) { return NULL; }
if(!be->get_config) { return NULL; }
return (be->get_config) (be);
if (!be)
{
return NULL;
}
if (!be->get_config)
{
return NULL;
}
return (be->get_config) (be);
}
gboolean
qof_backend_commit_exists(const QofBackend *be)
{
if(!be) { return FALSE; }
if(be->commit) { return TRUE; }
else { return FALSE; }
if (!be)
{
return FALSE;
}
if (be->commit)
{
return TRUE;
}
else
{
return FALSE;
}
}
gboolean
qof_load_backend_library (const char *directory, const char* module_name)
{
gchar *fullpath;
GModule *backend;
void (*module_init_func) (void);
gchar *fullpath;
GModule *backend;
void (*module_init_func) (void);
g_return_val_if_fail(g_module_supported(), FALSE);
fullpath = g_module_build_path(directory, module_name);
backend = g_module_open(fullpath, G_MODULE_BIND_LAZY);
g_free(fullpath);
if (!backend) {
g_message ("%s: %s\n", PACKAGE, g_module_error ());
return FALSE;
}
if (g_module_symbol(backend, "qof_backend_module_init",
(gpointer)&module_init_func))
module_init_func();
g_return_val_if_fail(g_module_supported(), FALSE);
fullpath = g_module_build_path(directory, module_name);
backend = g_module_open(fullpath, G_MODULE_BIND_LAZY);
g_free(fullpath);
if (!backend)
{
g_message ("%s: %s\n", PACKAGE, g_module_error ());
return FALSE;
}
if (g_module_symbol(backend, "qof_backend_module_init",
(gpointer)&module_init_func))
module_init_func();
g_module_make_resident(backend);
return TRUE;
g_module_make_resident(backend);
return TRUE;
}
/************************* END OF FILE ********************************/

View File

@ -26,14 +26,14 @@
The QOF Backend is a pseudo-object providing an interface between the
engine and a persistant data store (e.g. a server, a database, or
a file). Backends are not meant to be used directly by an
application; instead the Session should be used to make a
application; instead the Session should be used to make a
connection with some particular backend.
There are no backend functions that are 'public' to
users of the engine. The backend can, however, report errors to
the GUI & other front-end users. This file defines these errors.
Backends are used to save and restore Entities in a Book.
@{
@{
*/
/** @file qofbackend.h
@brief API for data storage Backend
@ -49,94 +49,95 @@
#define QOF_MOD_BACKEND "qof.backend"
/** \brief The errors that can be reported to the GUI & other front-end users
* \warning (GnuCash) If you modify QofBackendError, please update
* src/engine/gw-engine-spec.scm
* \warning (GnuCash) If you modify QofBackendError, please update
* src/engine/gw-engine-spec.scm
*/
typedef enum {
ERR_BACKEND_NO_ERR = 0,
ERR_BACKEND_NO_HANDLER, /**< no backend handler found for this access method (ENOSYS) */
ERR_BACKEND_NO_BACKEND, /**< Backend * pointer was unexpectedly null */
ERR_BACKEND_BAD_URL, /**< Can't parse url */
ERR_BACKEND_NO_SUCH_DB, /**< the named database doesn't exist */
ERR_BACKEND_CANT_CONNECT, /**< bad dbname/login/passwd or network failure */
ERR_BACKEND_CONN_LOST, /**< Lost connection to server */
ERR_BACKEND_LOCKED, /**< in use by another user (ETXTBSY) */
ERR_BACKEND_READONLY, /**< cannot write to file/directory */
ERR_BACKEND_TOO_NEW, /**< file/db version newer than what we can read */
ERR_BACKEND_DATA_CORRUPT, /**< data in db is corrupt */
ERR_BACKEND_SERVER_ERR, /**< error in response from server */
ERR_BACKEND_ALLOC, /**< internal memory allocation failure */
ERR_BACKEND_PERM, /**< user login successful, but no permissions
typedef enum
{
ERR_BACKEND_NO_ERR = 0,
ERR_BACKEND_NO_HANDLER, /**< no backend handler found for this access method (ENOSYS) */
ERR_BACKEND_NO_BACKEND, /**< Backend * pointer was unexpectedly null */
ERR_BACKEND_BAD_URL, /**< Can't parse url */
ERR_BACKEND_NO_SUCH_DB, /**< the named database doesn't exist */
ERR_BACKEND_CANT_CONNECT, /**< bad dbname/login/passwd or network failure */
ERR_BACKEND_CONN_LOST, /**< Lost connection to server */
ERR_BACKEND_LOCKED, /**< in use by another user (ETXTBSY) */
ERR_BACKEND_READONLY, /**< cannot write to file/directory */
ERR_BACKEND_TOO_NEW, /**< file/db version newer than what we can read */
ERR_BACKEND_DATA_CORRUPT, /**< data in db is corrupt */
ERR_BACKEND_SERVER_ERR, /**< error in response from server */
ERR_BACKEND_ALLOC, /**< internal memory allocation failure */
ERR_BACKEND_PERM, /**< user login successful, but no permissions
to access the desired object */
ERR_BACKEND_MODIFIED, /**< commit of object update failed because
ERR_BACKEND_MODIFIED, /**< commit of object update failed because
another user has modified the object */
ERR_BACKEND_MOD_DESTROY, /**< commit of object update failed because
ERR_BACKEND_MOD_DESTROY, /**< commit of object update failed because
another user has deleted the object */
ERR_BACKEND_MISC, /**< undetermined error */
ERR_BACKEND_MISC, /**< undetermined error */
/* QSF add-ons */
ERR_QSF_INVALID_OBJ, /**< The QSF object failed to validate against the QSF object schema */
ERR_QSF_INVALID_MAP, /**< The QSF map failed to validate against the QSF map schema */
ERR_QSF_BAD_OBJ_GUID, /**< The QSF object contains one or more invalid GUIDs. */
ERR_QSF_BAD_QOF_VERSION, /**< QSF map or object doesn't match the current QOF_OBJECT_VERSION. */
ERR_QSF_BAD_MAP, /**< The selected map validates but is unusable.
This is usually because not all the required parameters for the defined objects
/* QSF add-ons */
ERR_QSF_INVALID_OBJ, /**< The QSF object failed to validate against the QSF object schema */
ERR_QSF_INVALID_MAP, /**< The QSF map failed to validate against the QSF map schema */
ERR_QSF_BAD_OBJ_GUID, /**< The QSF object contains one or more invalid GUIDs. */
ERR_QSF_BAD_QOF_VERSION, /**< QSF map or object doesn't match the current QOF_OBJECT_VERSION. */
ERR_QSF_BAD_MAP, /**< The selected map validates but is unusable.
This is usually because not all the required parameters for the defined objects
have calculations described in the map.
*/
ERR_QSF_NO_MAP, /**< The QSF object file was loaded without a map
ERR_QSF_NO_MAP, /**< The QSF object file was loaded without a map
The QSF Object file requires a map but it was not provided.
*/
ERR_QSF_WRONG_MAP, /**< The selected map validates but is for different objects.
ERR_QSF_WRONG_MAP, /**< The selected map validates but is for different objects.
The list of objects defined in this map does not include all the objects described in
the current QSF object file.
*/
ERR_QSF_MAP_NOT_OBJ, /**< Selected file is a QSF map and cannot be opened as a QSF object */
ERR_QSF_OVERFLOW, /**< EOVERFLOW - generated by strtol or strtoll.
ERR_QSF_MAP_NOT_OBJ, /**< Selected file is a QSF map and cannot be opened as a QSF object */
ERR_QSF_OVERFLOW, /**< EOVERFLOW - generated by strtol or strtoll.
When converting XML strings into numbers, an overflow has been detected. The XML file
contains invalid data in a field that is meant to hold a signed long integer or signed long long
integer.
*/
ERR_QSF_OPEN_NOT_MERGE, /** QSF files cannot be opened alone. The data must be merged.
ERR_QSF_OPEN_NOT_MERGE, /** QSF files cannot be opened alone. The data must be merged.
This error is more of a warning that can be ignored by any routine
that uses qof_book_merge on the new session.
*/
/* fileio errors */
ERR_FILEIO_FILE_BAD_READ = 1000, /**< read failed or file prematurely truncated */
ERR_FILEIO_FILE_EMPTY, /**< file exists, is readable, but is empty */
ERR_FILEIO_FILE_LOCKERR, /**< mangled locks (unspecified error) */
ERR_FILEIO_FILE_NOT_FOUND, /**< not found / no such file */
ERR_FILEIO_FILE_TOO_OLD, /**< file version so old we can't read it */
ERR_FILEIO_UNKNOWN_FILE_TYPE, /**< didn't recognize the file type */
ERR_FILEIO_PARSE_ERROR, /**< couldn't parse the data in the file */
ERR_FILEIO_BACKUP_ERROR, /**< couldn't make a backup of the file */
ERR_FILEIO_WRITE_ERROR, /**< couldn't write to the file */
ERR_FILEIO_READ_ERROR, /**< Could not open the file for reading. */
ERR_FILEIO_NO_ENCODING, /**< file does not specify encoding */
ERR_FILEIO_FILE_EACCES, /**< No read access permission for the given file */
/* fileio errors */
ERR_FILEIO_FILE_BAD_READ = 1000, /**< read failed or file prematurely truncated */
ERR_FILEIO_FILE_EMPTY, /**< file exists, is readable, but is empty */
ERR_FILEIO_FILE_LOCKERR, /**< mangled locks (unspecified error) */
ERR_FILEIO_FILE_NOT_FOUND, /**< not found / no such file */
ERR_FILEIO_FILE_TOO_OLD, /**< file version so old we can't read it */
ERR_FILEIO_UNKNOWN_FILE_TYPE, /**< didn't recognize the file type */
ERR_FILEIO_PARSE_ERROR, /**< couldn't parse the data in the file */
ERR_FILEIO_BACKUP_ERROR, /**< couldn't make a backup of the file */
ERR_FILEIO_WRITE_ERROR, /**< couldn't write to the file */
ERR_FILEIO_READ_ERROR, /**< Could not open the file for reading. */
ERR_FILEIO_NO_ENCODING, /**< file does not specify encoding */
ERR_FILEIO_FILE_EACCES, /**< No read access permission for the given file */
/* network errors */
ERR_NETIO_SHORT_READ = 2000, /**< not enough bytes received */
ERR_NETIO_WRONG_CONTENT_TYPE, /**< wrong kind of server, wrong data served */
ERR_NETIO_NOT_GNCXML, /**< whatever it is, we can't parse it. */
/* database errors */
ERR_SQL_MISSING_DATA = 3000, /**< database doesn't contain expected data */
ERR_SQL_DB_TOO_OLD, /**< database is old and needs upgrading */
ERR_SQL_DB_BUSY, /**< database is busy, cannot upgrade version */
/* RPC errors */
ERR_RPC_HOST_UNK = 4000, /**< Host unknown */
ERR_RPC_CANT_BIND, /**< can't bind to address */
ERR_RPC_CANT_ACCEPT, /**< can't accept connection */
ERR_RPC_NO_CONNECTION, /**< no connection to server */
ERR_RPC_BAD_VERSION, /**< RPC Version Mismatch */
ERR_RPC_FAILED, /**< Operation failed */
ERR_RPC_NOT_ADDED, /**< object not added */
/* network errors */
ERR_NETIO_SHORT_READ = 2000, /**< not enough bytes received */
ERR_NETIO_WRONG_CONTENT_TYPE, /**< wrong kind of server, wrong data served */
ERR_NETIO_NOT_GNCXML, /**< whatever it is, we can't parse it. */
/* database errors */
ERR_SQL_MISSING_DATA = 3000, /**< database doesn't contain expected data */
ERR_SQL_DB_TOO_OLD, /**< database is old and needs upgrading */
ERR_SQL_DB_BUSY, /**< database is busy, cannot upgrade version */
/* RPC errors */
ERR_RPC_HOST_UNK = 4000, /**< Host unknown */
ERR_RPC_CANT_BIND, /**< can't bind to address */
ERR_RPC_CANT_ACCEPT, /**< can't accept connection */
ERR_RPC_NO_CONNECTION, /**< no connection to server */
ERR_RPC_BAD_VERSION, /**< RPC Version Mismatch */
ERR_RPC_FAILED, /**< Operation failed */
ERR_RPC_NOT_ADDED, /**< object not added */
} QofBackendError;
/**
@ -148,12 +149,12 @@ typedef enum {
typedef struct QofBackendProvider_s QofBackendProvider;
/** \brief Pseudo-object providing an interface between the
* engine and a persistant data store (e.g. a server, a database,
* or a file).
* engine and a persistant data store (e.g. a server, a database,
* or a file).
*
* There are no backend functions that are 'public' to users of the
* engine. The backend can, however, report errors to the GUI & other
* front-end users.
* front-end users.
*/
typedef struct QofBackend_s QofBackend;
@ -202,13 +203,14 @@ backend is fully configured and ready for use.
*/
/** A single Backend Configuration Option. */
typedef struct QofBackendOption_s {
KvpValueType type; /**< Only GINT64, DOUBLE, NUMERIC, STRING and TIMESPEC supported. */
const gchar *option_name; /**< non-translated, key. */
const gchar *description; /**< translatable description. */
const gchar *tooltip; /**< translatable tooltip */
gpointer value; /**< The value of the option. */
}QofBackendOption;
typedef struct QofBackendOption_s
{
KvpValueType type; /**< Only GINT64, DOUBLE, NUMERIC, STRING and TIMESPEC supported. */
const gchar *option_name; /**< non-translated, key. */
const gchar *description; /**< translatable description. */
const gchar *tooltip; /**< translatable tooltip */
gpointer value; /**< The value of the option. */
} QofBackendOption;
/** Initialise the backend_configuration */
void qof_backend_prepare_frame(QofBackend *be);

View File

@ -56,50 +56,50 @@ QOF_GOBJECT_IMPL(qof_book, QofBook, QOF_TYPE_INSTANCE);
static void coll_destroy(gpointer col)
{
qof_collection_destroy((QofCollection *) col);
qof_collection_destroy((QofCollection *) col);
}
static void
qof_book_init (QofBook *book)
{
if (!book) return;
if (!book) return;
book->hash_of_collections = g_hash_table_new_full(
g_str_hash, g_str_equal,
(GDestroyNotify)qof_util_string_cache_remove, /* key_destroy_func */
coll_destroy); /* value_destroy_func */
book->hash_of_collections = g_hash_table_new_full(
g_str_hash, g_str_equal,
(GDestroyNotify)qof_util_string_cache_remove, /* key_destroy_func */
coll_destroy); /* value_destroy_func */
qof_instance_init_data (&book->inst, QOF_ID_BOOK, book);
qof_instance_init_data (&book->inst, QOF_ID_BOOK, book);
book->data_tables = g_hash_table_new (g_str_hash, g_str_equal);
book->data_table_finalizers = g_hash_table_new (g_str_hash, g_str_equal);
book->book_open = 'y';
book->version = 0;
book->data_tables = g_hash_table_new (g_str_hash, g_str_equal);
book->data_table_finalizers = g_hash_table_new (g_str_hash, g_str_equal);
book->book_open = 'y';
book->version = 0;
}
QofBook *
qof_book_new (void)
{
QofBook *book;
QofBook *book;
ENTER (" ");
book = g_object_new(QOF_TYPE_BOOK, NULL);
qof_object_book_begin (book);
ENTER (" ");
book = g_object_new(QOF_TYPE_BOOK, NULL);
qof_object_book_begin (book);
qof_event_gen (&book->inst, QOF_EVENT_CREATE, NULL);
LEAVE ("book=%p", book);
return book;
qof_event_gen (&book->inst, QOF_EVENT_CREATE, NULL);
LEAVE ("book=%p", book);
return book;
}
static void
book_final (gpointer key, gpointer value, gpointer booq)
{
QofBookFinalCB cb = value;
QofBook *book = booq;
QofBookFinalCB cb = value;
QofBook *book = booq;
gpointer user_data = g_hash_table_lookup (book->data_tables, key);
(*cb) (book, key, user_data);
gpointer user_data = g_hash_table_lookup (book->data_tables, key);
(*cb) (book, key, user_data);
}
static void
@ -113,41 +113,41 @@ qof_book_finalize_real (GObject *bookp)
}
void
qof_book_destroy (QofBook *book)
qof_book_destroy (QofBook *book)
{
GHashTable* cols;
GHashTable* cols;
if (!book) return;
ENTER ("book=%p", book);
if (!book) return;
ENTER ("book=%p", book);
book->shutting_down = TRUE;
qof_event_force (&book->inst, QOF_EVENT_DESTROY, NULL);
book->shutting_down = TRUE;
qof_event_force (&book->inst, QOF_EVENT_DESTROY, NULL);
/* Call the list of finalizers, let them do their thing.
* Do this before tearing into the rest of the book.
*/
g_hash_table_foreach (book->data_table_finalizers, book_final, book);
/* Call the list of finalizers, let them do their thing.
* Do this before tearing into the rest of the book.
*/
g_hash_table_foreach (book->data_table_finalizers, book_final, book);
qof_object_book_end (book);
qof_object_book_end (book);
g_hash_table_destroy (book->data_table_finalizers);
book->data_table_finalizers = NULL;
g_hash_table_destroy (book->data_tables);
book->data_tables = NULL;
g_hash_table_destroy (book->data_table_finalizers);
book->data_table_finalizers = NULL;
g_hash_table_destroy (book->data_tables);
book->data_tables = NULL;
/* qof_instance_release (&book->inst); */
/* qof_instance_release (&book->inst); */
/* Note: we need to save this hashtable until after we remove ourself
* from it, otherwise we'll crash in our dispose() function when we
* DO remove ourself from the collection but the collection had already
* been destroyed.
*/
cols = book->hash_of_collections;
g_object_unref (book);
g_hash_table_destroy (cols);
book->hash_of_collections = NULL;
/* Note: we need to save this hashtable until after we remove ourself
* from it, otherwise we'll crash in our dispose() function when we
* DO remove ourself from the collection but the collection had already
* been destroyed.
*/
cols = book->hash_of_collections;
g_object_unref (book);
g_hash_table_destroy (cols);
book->hash_of_collections = NULL;
LEAVE ("book=%p", book);
LEAVE ("book=%p", book);
}
/* ====================================================================== */
@ -156,9 +156,9 @@ qof_book_destroy (QofBook *book)
gboolean
qof_book_equal (const QofBook *book_1, const QofBook *book_2)
{
if (book_1 == book_2) return TRUE;
if (!book_1 || !book_2) return FALSE;
return FALSE;
if (book_1 == book_2) return TRUE;
if (!book_1 || !book_2) return FALSE;
return FALSE;
}
/* ====================================================================== */
@ -166,83 +166,85 @@ qof_book_equal (const QofBook *book_1, const QofBook *book_2)
gboolean
qof_book_not_saved (const QofBook *book)
{
if (!book) return FALSE;
if (!book) return FALSE;
return(qof_instance_get_dirty_flag(book) || qof_object_is_dirty(book));
return(qof_instance_get_dirty_flag(book) || qof_object_is_dirty(book));
}
void
qof_book_mark_saved (QofBook *book)
{
gboolean was_dirty;
gboolean was_dirty;
if (!book) return;
if (!book) return;
was_dirty = qof_instance_get_dirty_flag(book);
qof_instance_set_dirty_flag(book, FALSE);
book->dirty_time = 0;
qof_object_mark_clean (book);
if (was_dirty) {
if (book->dirty_cb)
book->dirty_cb(book, FALSE, book->dirty_data);
}
was_dirty = qof_instance_get_dirty_flag(book);
qof_instance_set_dirty_flag(book, FALSE);
book->dirty_time = 0;
qof_object_mark_clean (book);
if (was_dirty)
{
if (book->dirty_cb)
book->dirty_cb(book, FALSE, book->dirty_data);
}
}
void qof_book_mark_dirty (QofBook *book)
{
gboolean was_dirty;
gboolean was_dirty;
if (!book) return;
if (!book) return;
was_dirty = qof_instance_get_dirty_flag(book);
qof_instance_set_dirty_flag(book, TRUE);
if (!was_dirty) {
book->dirty_time = time(NULL);
if (book->dirty_cb)
book->dirty_cb(book, TRUE, book->dirty_data);
}
was_dirty = qof_instance_get_dirty_flag(book);
qof_instance_set_dirty_flag(book, TRUE);
if (!was_dirty)
{
book->dirty_time = time(NULL);
if (book->dirty_cb)
book->dirty_cb(book, TRUE, book->dirty_data);
}
}
void
qof_book_print_dirty (const QofBook *book)
{
if (qof_instance_get_dirty_flag(book))
printf("book is dirty.\n");
qof_book_foreach_collection
if (qof_instance_get_dirty_flag(book))
printf("book is dirty.\n");
qof_book_foreach_collection
(book, (QofCollectionForeachCB)qof_collection_print_dirty, NULL);
}
time_t
qof_book_get_dirty_time (const QofBook *book)
{
return book->dirty_time;
return book->dirty_time;
}
void
qof_book_set_dirty_cb(QofBook *book, QofBookDirtyCB cb, gpointer user_data)
{
if (book->dirty_cb)
g_warning("qof_book_set_dirty_cb: Already existing callback %p, will be overwritten by %p\n",
book->dirty_cb, cb);
book->dirty_data = user_data;
book->dirty_cb = cb;
if (book->dirty_cb)
g_warning("qof_book_set_dirty_cb: Already existing callback %p, will be overwritten by %p\n",
book->dirty_cb, cb);
book->dirty_data = user_data;
book->dirty_cb = cb;
}
/* ====================================================================== */
/* getters */
QofBackend *
QofBackend *
qof_book_get_backend (const QofBook *book)
{
if (!book) return NULL;
return book->backend;
if (!book) return NULL;
return book->backend;
}
gboolean
qof_book_shutting_down (const QofBook *book)
{
if (!book) return FALSE;
return book->shutting_down;
if (!book) return FALSE;
return book->shutting_down;
}
/* ====================================================================== */
@ -251,15 +253,15 @@ qof_book_shutting_down (const QofBook *book)
void
qof_book_set_backend (QofBook *book, QofBackend *be)
{
if (!book) return;
ENTER ("book=%p be=%p", book, be);
book->backend = be;
LEAVE (" ");
if (!book) return;
ENTER ("book=%p be=%p", book, be);
book->backend = be;
LEAVE (" ");
}
void qof_book_kvp_changed (QofBook *book)
{
qof_book_mark_dirty(book);
qof_book_mark_dirty(book);
}
/* ====================================================================== */
@ -267,28 +269,28 @@ void qof_book_kvp_changed (QofBook *book)
/* Store arbitrary pointers in the QofBook for data storage extensibility */
/* XXX if data is NULL, we should remove the key from the hash table!
*/
void
void
qof_book_set_data (QofBook *book, const char *key, gpointer data)
{
if (!book || !key) return;
g_hash_table_insert (book->data_tables, (gpointer)key, data);
if (!book || !key) return;
g_hash_table_insert (book->data_tables, (gpointer)key, data);
}
void
void
qof_book_set_data_fin (QofBook *book, const char *key, gpointer data, QofBookFinalCB cb)
{
if (!book || !key) return;
g_hash_table_insert (book->data_tables, (gpointer)key, data);
if (!book || !key) return;
g_hash_table_insert (book->data_tables, (gpointer)key, data);
if (!cb) return;
g_hash_table_insert (book->data_table_finalizers, (gpointer)key, cb);
if (!cb) return;
g_hash_table_insert (book->data_table_finalizers, (gpointer)key, cb);
}
gpointer
gpointer
qof_book_get_data (const QofBook *book, const char *key)
{
if (!book || !key) return NULL;
return g_hash_table_lookup (book->data_tables, (gpointer)key);
if (!book || !key) return NULL;
return g_hash_table_lookup (book->data_tables, (gpointer)key);
}
/* ====================================================================== */
@ -296,139 +298,160 @@ qof_book_get_data (const QofBook *book, const char *key)
QofCollection *
qof_book_get_collection (const QofBook *book, QofIdType entity_type)
{
QofCollection *col;
QofCollection *col;
if (!book || !entity_type) return NULL;
if (!book || !entity_type) return NULL;
col = g_hash_table_lookup (book->hash_of_collections, entity_type);
if (!col) {
col = qof_collection_new (entity_type);
g_hash_table_insert(
book->hash_of_collections,
qof_util_string_cache_insert((gpointer) entity_type), col);
}
return col;
col = g_hash_table_lookup (book->hash_of_collections, entity_type);
if (!col)
{
col = qof_collection_new (entity_type);
g_hash_table_insert(
book->hash_of_collections,
qof_util_string_cache_insert((gpointer) entity_type), col);
}
return col;
}
struct _iterate {
QofCollectionForeachCB fn;
gpointer data;
struct _iterate
{
QofCollectionForeachCB fn;
gpointer data;
};
static void
static void
foreach_cb (gpointer key, gpointer item, gpointer arg)
{
struct _iterate *iter = arg;
QofCollection *col = item;
struct _iterate *iter = arg;
QofCollection *col = item;
iter->fn (col, iter->data);
iter->fn (col, iter->data);
}
void
qof_book_foreach_collection (const QofBook *book,
void
qof_book_foreach_collection (const QofBook *book,
QofCollectionForeachCB cb, gpointer user_data)
{
struct _iterate iter;
struct _iterate iter;
g_return_if_fail (book);
g_return_if_fail (cb);
g_return_if_fail (book);
g_return_if_fail (cb);
iter.fn = cb;
iter.data = user_data;
iter.fn = cb;
iter.data = user_data;
g_hash_table_foreach (book->hash_of_collections, foreach_cb, &iter);
g_hash_table_foreach (book->hash_of_collections, foreach_cb, &iter);
}
/* ====================================================================== */
void qof_book_mark_closed (QofBook *book)
{
if(!book) { return; }
book->book_open = 'n';
if (!book)
{
return;
}
book->book_open = 'n';
}
gchar qof_book_get_open_marker(const QofBook *book)
{
if(!book) { return 'n'; }
return book->book_open;
if (!book)
{
return 'n';
}
return book->book_open;
}
gint32 qof_book_get_version (const QofBook *book)
{
if(!book) { return -1; }
return book->version;
if (!book)
{
return -1;
}
return book->version;
}
void qof_book_set_version (QofBook *book, gint32 version)
{
if(!book && version < 0) { return; }
book->version = version;
if (!book && version < 0)
{
return;
}
book->version = version;
}
gint64
qof_book_get_counter (const QofBook *book, const char *counter_name)
{
QofBackend *be;
KvpFrame *kvp;
KvpValue *value;
gint64 counter;
QofBackend *be;
KvpFrame *kvp;
KvpValue *value;
gint64 counter;
if (!book) {
PWARN ("No book!!!");
return -1;
}
if (!book)
{
PWARN ("No book!!!");
return -1;
}
if (!counter_name || *counter_name == '\0') {
PWARN ("Invalid counter name.");
return -1;
}
if (!counter_name || *counter_name == '\0')
{
PWARN ("Invalid counter name.");
return -1;
}
/* If we've got a backend with a counter method, call it */
be = book->backend;
if (be && be->counter)
return ((be->counter)(be, counter_name));
/* If we've got a backend with a counter method, call it */
be = book->backend;
if (be && be->counter)
return ((be->counter)(be, counter_name));
/* If not, then use the KVP in the book */
kvp = qof_book_get_slots (book);
/* If not, then use the KVP in the book */
kvp = qof_book_get_slots (book);
if (!kvp) {
PWARN ("Book has no KVP_Frame");
return -1;
}
if (!kvp)
{
PWARN ("Book has no KVP_Frame");
return -1;
}
value = kvp_frame_get_slot_path (kvp, "counters", counter_name, NULL);
if (value) {
/* found it */
counter = kvp_value_get_gint64 (value);
} else {
/* New counter */
counter = 0;
}
value = kvp_frame_get_slot_path (kvp, "counters", counter_name, NULL);
if (value)
{
/* found it */
counter = kvp_value_get_gint64 (value);
}
else
{
/* New counter */
counter = 0;
}
/* Counter is now valid; increment it */
counter++;
/* Counter is now valid; increment it */
counter++;
/* Save off the new counter */
value = kvp_value_new_gint64 (counter);
kvp_frame_set_slot_path (kvp, value, "counters", counter_name, NULL);
kvp_value_delete (value);
/* Save off the new counter */
value = kvp_value_new_gint64 (counter);
kvp_frame_set_slot_path (kvp, value, "counters", counter_name, NULL);
kvp_value_delete (value);
/* and return the value */
return counter;
/* and return the value */
return counter;
}
/* QofObject function implementation and registration */
gboolean qof_book_register (void)
{
static QofParam params[] = {
{ QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_entity_get_guid, NULL },
{ QOF_PARAM_KVP, QOF_TYPE_KVP, (QofAccessFunc)qof_instance_get_slots, NULL },
{ NULL },
};
static QofParam params[] =
{
{ QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_entity_get_guid, NULL },
{ QOF_PARAM_KVP, QOF_TYPE_KVP, (QofAccessFunc)qof_instance_get_slots, NULL },
{ NULL },
};
qof_class_register (QOF_ID_BOOK, NULL, params);
qof_class_register (QOF_ID_BOOK, NULL, params);
return TRUE;
return TRUE;
}
/* ========================== END OF FILE =============================== */

View File

@ -64,61 +64,61 @@ typedef void (*QofBookDirtyCB) (QofBook *, gboolean dirty, gpointer user_data);
/* Book structure */
struct _QofBook
{
QofInstance inst; /* Unique guid for this book. */
QofInstance inst; /* Unique guid for this book. */
/* The time when the book was first dirtied. This is a secondary
* indicator. It should only be used when inst.dirty is TRUE. */
time_t dirty_time;
/* The time when the book was first dirtied. This is a secondary
* indicator. It should only be used when inst.dirty is TRUE. */
time_t dirty_time;
/* This callback function is called any time the book dirty flag
* changes state. Both clean->dirty and dirty->clean transitions
* trigger a callback. */
QofBookDirtyCB dirty_cb;
/* This callback function is called any time the book dirty flag
* changes state. Both clean->dirty and dirty->clean transitions
* trigger a callback. */
QofBookDirtyCB dirty_cb;
/* This is the user supplied data that is returned in the dirty
* callback function.*/
gpointer dirty_data;
/* This is the user supplied data that is returned in the dirty
* callback function.*/
gpointer dirty_data;
/* The entity table associates the GUIDs of all the objects
* belonging to this book, with their pointers to the respective
* objects. This allows a lookup of objects based on thier guid.
*/
GHashTable * hash_of_collections;
/* The entity table associates the GUIDs of all the objects
* belonging to this book, with their pointers to the respective
* objects. This allows a lookup of objects based on thier guid.
*/
GHashTable * hash_of_collections;
/* In order to store arbitrary data, for extensibility, add a table
* that will be used to hold arbitrary pointers.
*/
GHashTable *data_tables;
/* In order to store arbitrary data, for extensibility, add a table
* that will be used to hold arbitrary pointers.
*/
GHashTable *data_tables;
/* Hash table of destroy callbacks for the data table. */
GHashTable *data_table_finalizers;
/* Hash table of destroy callbacks for the data table. */
GHashTable *data_table_finalizers;
/* state flag: 'y' means 'open for editing',
* 'n' means 'book is closed'
* xxxxx shouldn't this be replaced by the instance editlevel ???
*/
char book_open;
/* state flag: 'y' means 'open for editing',
* 'n' means 'book is closed'
* xxxxx shouldn't this be replaced by the instance editlevel ???
*/
char book_open;
/* a flag denoting whether the book is closing down, used to
* help the QOF objects shut down cleanly without maintaining
* internal consistency.
* XXX shouldn't this be replaced by instance->do_free ???
*/
gboolean shutting_down;
/* a flag denoting whether the book is closing down, used to
* help the QOF objects shut down cleanly without maintaining
* internal consistency.
* XXX shouldn't this be replaced by instance->do_free ???
*/
gboolean shutting_down;
/* version number, used for tracking multiuser updates */
gint32 version;
/* version number, used for tracking multiuser updates */
gint32 version;
/* To be technically correct, backends belong to sessions and
* not books. So the pointer below "really shouldn't be here",
* except that it provides a nice convenience, avoiding a lookup
* from the session. Better solutions welcome ... */
QofBackend *backend;
/* To be technically correct, backends belong to sessions and
* not books. So the pointer below "really shouldn't be here",
* except that it provides a nice convenience, avoiding a lookup
* from the session. Better solutions welcome ... */
QofBackend *backend;
};
struct _QofBookClass
{
QofInstanceClass parent_class;
QofInstanceClass parent_class;
};
GType qof_book_get_type(void);
@ -175,7 +175,8 @@ void qof_book_mark_closed (QofBook *book);
* a non-NULL value. (Unless the system malloc failed (out of
* memory) in which case what happens??).
*/
/*@ dependent @*/ QofCollection * qof_book_get_collection (const QofBook *, QofIdType);
/*@ dependent @*/
QofCollection * qof_book_get_collection (const QofBook *, QofIdType);
/** Invoke the indicated callback on each collection in the book. */
typedef void (*QofCollectionForeachCB) (QofCollection *, gpointer user_data);
@ -206,7 +207,7 @@ void qof_book_set_data (QofBook *book, const gchar *key, gpointer data);
* when the book is destroyed. The argument to the callback will be
* the book followed by the data pointer.
*/
void qof_book_set_data_fin (QofBook *book, const gchar *key, gpointer data,
void qof_book_set_data_fin (QofBook *book, const gchar *key, gpointer data,
QofBookFinalCB);
/** Retrieves arbitrary pointers to structs stored by qof_book_set_data. */
@ -227,7 +228,7 @@ gboolean qof_book_not_saved (const QofBook *book);
/** The qof_book_mark_saved() routine marks the book as having been
* saved (to a file, to a database). Used by backends to mark the
* notsaved flag as FALSE just after loading. Can also be used
* notsaved flag as FALSE just after loading. Can also be used
* by the frontend when the used has said to abandon any changes.
*/
void qof_book_mark_saved(QofBook *book);

File diff suppressed because it is too large Load Diff

View File

@ -39,20 +39,20 @@
that do not have a GUID match cannot be assumed to be ::MERGE_NEW - parameter
values must be checked.
-# If import contains data from closed books, store the data from the closed
books in the current book as active. i.e. re-open the books.
books in the current book as active. i.e. re-open the books.
- If a GUID match exists, set qof_book_merge_rule::mergeAbsolute to \a TRUE.
-# If ALL parameters in the import object match the target object with
the same \a GUID,
the same \a GUID,
set ::qof_book_merge_result to \a MERGE_ABSOLUTE.
-# If any parameters differ, set ::MERGE_UPDATE.
- If the import object \a GUID does not match an existing object,
mergeAbsolute is unchanged from the default \a FALSE
The parameter values of the object are compared to other objects of the same
type in the target book.
-# If the same data exists in the target book with a different GUID, the object
-# If the same data exists in the target book with a different GUID, the object
is tagged as DUPLICATE.
-# If the data has changed, the object is tagged as REPORT.
-# If the data has changed, the object is tagged as REPORT.
-# If the data does not match, the object is tagged as NEW
More information is at http://code.neil.williamsleesmill.me.uk/
@ -64,7 +64,7 @@ is only used for critical errors that arise from programming errors, not for
invalid import data which should be cleaned up before creating the import
QofBook.
Only ::qof_book_merge_update_result and ::qof_book_merge_commit return
Only ::qof_book_merge_update_result and ::qof_book_merge_commit return
any error values to the calling process. ::qof_book_merge_init returns a
pointer to the ::QofBookMergeData struct - the calling process needs to
make sure this is non-NULL to know that the Init has been successful.
@ -97,7 +97,7 @@ preferences option for each result. (Always accept new items: Y/N default NO,
ignores all MERGE_NEW if set to Y etc.) This option would not require any
changes to qofbookmerge.
\a MERGE_NEW, \a MERGE_DUPLICATE and \a MERGE_UPDATE are only actioned after
\a MERGE_NEW, \a MERGE_DUPLICATE and \a MERGE_UPDATE are only actioned after
conflicts are resolved by the user using a dialog and all \a MERGE_REPORT
objects are re-assigned to one of MERGE_NEW, MERGE_DUPLICATE or MERGE_UPDATE.
There is no automatic merge, even if no entities are tagged as MERGE_REPORT,
@ -110,37 +110,38 @@ concerns that the rest of the data may be corrupted, damaged or otherwise
altered. If any entity is tagged as MERGE_INVALID, the merge operation will
abort and leave the target book completely unchanged.
\a MERGE_ABSOLUTE is only used for a complete match. The import object contains
\a MERGE_ABSOLUTE is only used for a complete match. The import object contains
the same data in the same parameters with no omissions or amendments. If any
data is missing, amended or added, the data is labelled \a MERGE_UPDATE.
data is missing, amended or added, the data is labelled \a MERGE_UPDATE.
Every piece of data has a corresponding result. Only when the count of items
labelled \a MERGE_REPORT is equal to zero are \a MERGE_NEW and \a MERGE_UPDATE
labelled \a MERGE_REPORT is equal to zero are \a MERGE_NEW and \a MERGE_UPDATE
items added to the existing book.\n \a MERGE_DUPLICATE items are silently
ignored. Aborting the dialogue/process (by the user or in a program crash) at
any point before the final commit leaves the existing book completely untouched.
*/
typedef enum {
MERGE_UNDEF, /**< default value before comparison is made. */
MERGE_ABSOLUTE, /**< GUID exact match, no new data - \b ignore */
MERGE_NEW, /**< import object does \b not exist in the target
typedef enum
{
MERGE_UNDEF, /**< default value before comparison is made. */
MERGE_ABSOLUTE, /**< GUID exact match, no new data - \b ignore */
MERGE_NEW, /**< import object does \b not exist in the target
book - \b add */
MERGE_REPORT, /**< import object needs user intervention - \b report */
MERGE_DUPLICATE, /**< import object with different GUID exactly matches
MERGE_REPORT, /**< import object needs user intervention - \b report */
MERGE_DUPLICATE, /**< import object with different GUID exactly matches
existing GUID - \b ignore */
MERGE_UPDATE, /**< import object matches an existing entity but includes
MERGE_UPDATE, /**< import object matches an existing entity but includes
new or modified parameter data - \b update */
MERGE_INVALID /**< import object didn't match registered object or
MERGE_INVALID /**< import object didn't match registered object or
parameter types or user decided to abort - \b abort */
}QofBookMergeResult;
} QofBookMergeResult;
/** \brief One rule per entity, built into a single GList for the entire merge
/** \brief One rule per entity, built into a single GList for the entire merge
All rules are stored in the GList QofBookMergeData::mergeList.
If the ::GUID matches it's the always same semantic object,
regardless of whether other data fields are changed.
\n
\n
The boolean value mergeAbsolute defaults to \c FALSE
NOTE 1: if mergeAbsolute == \c TRUE, ::QofBookMergeResult will still be set
@ -158,22 +159,22 @@ same name in mergeData.
*/
typedef struct
typedef struct
{
/* internal counters and reference variables */
gboolean mergeAbsolute; /**< Only set if the GUID of the import matches
/* internal counters and reference variables */
gboolean mergeAbsolute; /**< Only set if the GUID of the import matches
the target */
double difference; /**< used to find best match in a book where no
double difference; /**< used to find best match in a book where no
GUID matches */
gboolean updated; /**< prevent the mergeResult from being
gboolean updated; /**< prevent the mergeResult from being
overwritten. */
/* rule objects set from or by external calls */
QofIdType mergeType; /**< type of comparison required for check for
/* rule objects set from or by external calls */
QofIdType mergeType; /**< type of comparison required for check for
collision */
const gchar* mergeLabel; /**< Descriptive label for the object type,
const gchar* mergeLabel; /**< Descriptive label for the object type,
useful for the user intervention dialogue. */
GSList *mergeParam; /**< list of usable parameters for the object type */
GSList *linkedEntList; /**< list of complex data types included in this object.
GSList *mergeParam; /**< list of usable parameters for the object type */
GSList *linkedEntList; /**< list of complex data types included in this object.
linkedEntList contains an ::QofInstance reference to any parameter that is not
one of the core QOF_TYPE data types. This entity must be already
@ -182,43 +183,43 @@ typedef struct
same value but for a different customer, the invoice will be set to
MERGE_REPORT and the customer as MERGE_NEW.
*/
QofBookMergeResult mergeResult; /**< result of comparison with main ::QofBook */
QofInstance *importEnt; /**< pointer to the current entity in the import book. */
QofInstance *targetEnt; /**< pointer to the corresponding entity in the
QofBookMergeResult mergeResult; /**< result of comparison with main ::QofBook */
QofInstance *importEnt; /**< pointer to the current entity in the import book. */
QofInstance *targetEnt; /**< pointer to the corresponding entity in the
target book, if any. */
}QofBookMergeRule;
} QofBookMergeRule;
/** \brief mergeData contains the essential context data for any merge.
Used to dictate what to merge, how to merge it, where to get the new data and
where to put the amended data.
where to put the amended data.
Combines lists of \a ::QofParam, \a ::QofInstance and \a ::QofBookMergeRule
into one struct that can be easily passed between callbacks. Also holds the
pointers to the import and target ::QofBook structures.
- targetList and mergeObjectParams change each time a new object type
is set for compare.
is set for compare.
- mergeList is the complete list of rules for all objects in the import book.
*/
typedef struct
{
GSList *mergeObjectParams; /**< GSList of ::QofParam details for each
GSList *mergeObjectParams; /**< GSList of ::QofParam details for each
parameter in the current object. */
GList *mergeList; /**< GList of all ::QofBookMergeRule rules
GList *mergeList; /**< GList of all ::QofBookMergeRule rules
for the merge operation. */
GSList *targetList; /**< GSList of ::QofInstance * for each object
GSList *targetList; /**< GSList of ::QofInstance * for each object
of this type in the target book */
QofBook *mergeBook; /**< pointer to the import book for this
QofBook *mergeBook; /**< pointer to the import book for this
merge operation. */
QofBook *targetBook; /**< pointer to the target book for this
QofBook *targetBook; /**< pointer to the target book for this
merge operation. */
gboolean abort; /**< set to TRUE if MERGE_INVALID is set. */
QofBookMergeRule *currentRule; /**< placeholder for the rule currently
gboolean abort; /**< set to TRUE if MERGE_INVALID is set. */
QofBookMergeRule *currentRule; /**< placeholder for the rule currently
being tested or applied. */
GSList *orphan_list; /**< List of QofInstance's that need to be rematched.
GSList *orphan_list; /**< List of QofInstance's that need to be rematched.
When one QofInstance has a lower difference to the targetEnt than the
previous best_match, the new match takes precedence. This list holds those
@ -226,10 +227,10 @@ typedef struct
rematched later. The ranking is handled using the private QofInstanceRating
struct and the GHashTable ::QofBookMergeData::target_table.
*/
GHashTable *target_table; /**< The GHashTable to hold the
GHashTable *target_table; /**< The GHashTable to hold the
QofInstanceRating values. */
}QofBookMergeData;
} QofBookMergeData;
/* ======================================================================== */
@ -246,7 +247,7 @@ typedef struct
Process:
-# Invoke the callback ::qof_book_merge_foreach_type on every registered
object class definition.
object class definition.
-# Callback obtains the registered parameter list for each object type.
This provides run time access to all registered objects and all object
parameters without any changes to QofBookMerge - no registered object or
@ -295,7 +296,7 @@ void test_rule_loop(QofBookMergeData *mergeData, QofBookMergeRule *rule, guint r
The dialogue is free to call ::qof_book_merge_update_result in the loop or at the end
as long as the link between the rule and the result is maintained, e.g. by using a
GHashTable.
GHashTable.
\n
The parameters are:
- data : pointer to the ::QofBookMergeData metadata context returned by init.
@ -342,8 +343,8 @@ and again the QofBookMergeRule::targetEnt to return the two specific entities.
*/
void qof_book_merge_rule_foreach( QofBookMergeData* mergeData,
QofBookMergeRuleForeachCB callback ,
QofBookMergeResult mergeResult);
QofBookMergeRuleForeachCB callback ,
QofBookMergeResult mergeResult);
/** \brief provides easy string access to parameter data for dialogue use
@ -366,8 +367,8 @@ gchar* qof_book_merge_param_as_string(QofParam *qtparam, QofInstance *qtEnt);
Set \b any rule result to ::MERGE_INVALID to abort the import when
::qof_book_merge_commit is called, without changing the target book.
The calling process should make it absolutely clear that a merge operation
\b cannot be undone and that a backup copy should always be available
The calling process should make it absolutely clear that a merge operation
\b cannot be undone and that a backup copy should always be available
\b before a merge is initialised.
Recommended method: Only offer three options to the user per rule:
@ -404,16 +405,16 @@ add an entity when mergeAbsolute is TRUE will always force a MERGE_UPDATE.
It is not possible to update the same rule more than once.
-# \b MERGE_NEW is reserved for new objects and is only pre-set if
all parameters, including GUID, have already failed to match any
relevant object. ::qof_book_merge_commit will create new
entities for all rules tagged as MERGE_NEW.
- if mergeAbsolute is TRUE and the user wants to import the
data, requests to set MERGE_NEW will be forced to MERGE_UPDATE
all parameters, including GUID, have already failed to match any
relevant object. ::qof_book_merge_commit will create new
entities for all rules tagged as MERGE_NEW.
- if mergeAbsolute is TRUE and the user wants to import the
data, requests to set MERGE_NEW will be forced to MERGE_UPDATE
because an entity with that GUID already exists in the target book.
- if MERGE_NEW is pre-set, requests to change to MERGE_UPDATE will be
- if MERGE_NEW is pre-set, requests to change to MERGE_UPDATE will be
ignored because a new entity is needed.
-# \b MERGE_UPDATE is reserved for existing objects - ::qof_book_merge_commit
will require a matching entity to update and will force a change to back to
-# \b MERGE_UPDATE is reserved for existing objects - ::qof_book_merge_commit
will require a matching entity to update and will force a change to back to
MERGE_NEW if none is known to exist, using the principle above.
-# \b MERGE_INVALID will cause an abort of the merge process.
-# \b MERGE_UNDEF and \b MERGE_REPORT cannot be set - the entity result will
@ -426,7 +427,7 @@ be unchanged.
- if mergeAbsolute is FALSE but MERGE_ABSOLUTE is requested,
force a change to MERGE_DUPLICATE.
::qof_book_merge_commit only commits entities tagged
::qof_book_merge_commit only commits entities tagged
with MERGE_NEW and MERGE_UPDATE results.
\n
Entities tagged with MERGE_ABSOLUTE and MERGE_DUPLICATE results are ignored.
@ -438,7 +439,7 @@ The calling process must check the return value and call
@param tag the result to attempt to set, ::QofBookMergeResult
\return -1 if supplied parameters are invalid or NULL, 0 on success.
*/
QofBookMergeData*
qof_book_merge_update_result(QofBookMergeData *mergeData, QofBookMergeResult tag);
@ -448,9 +449,9 @@ qof_book_merge_update_result(QofBookMergeData *mergeData, QofBookMergeResult tag
The last function in the API and the final part of any QofBookMerge operation.
qof_book_merge_commit will abort the \b entire merge operation if any rule
is set to ::MERGE_INVALID. It is the responsibility of the calling
is set to ::MERGE_INVALID. It is the responsibility of the calling
function to handle the error code from ::qof_book_merge_commit, close the
dialogue and return. qof_book_merge_commit will already have halted the merge
dialogue and return. qof_book_merge_commit will already have halted the merge
operation and freed any memory allocated to all merge structures before
returning the error code. There is no way for the dialogue process to report
back to qof_book_merge in this situation.
@ -462,9 +463,9 @@ qof_book_merge_commit checks for any entities still tagged as
<b>This final process cannot be UNDONE!</b>\n
\n
@param mergeData the merge context, ::QofBookMergeData*
@param mergeData the merge context, ::QofBookMergeData*
\return
\return
- -2 if any rules are tagged as ::MERGE_INVALID
- mergeData will have been g_free'd).
- note that this will be before any operations are done on the target
@ -472,7 +473,7 @@ qof_book_merge_commit checks for any entities still tagged as
- -1 if mergeData is invalid or no merge has been initialised with
::qof_book_merge_init - the calling process must check the value of
mergeData
- +1 if some entities are still tagged as \a MERGE_REPORT - use
- +1 if some entities are still tagged as \a MERGE_REPORT - use
::qof_book_merge_update_rule and try again (mergeData is retained).
- 0 on success - mergeData will have been freed.
*/
@ -483,7 +484,7 @@ qof_book_merge_commit(QofBookMergeData *mergeData );
Sometimes, setting ::MERGE_INVALID is insufficient: e.g. if the user aborts the
merge from outside the functions dealing with the merge ruleset. This function
causes an immediate abort - the calling process must start again at Init if
causes an immediate abort - the calling process must start again at Init if
a new merge is required.
*/
void

View File

@ -33,84 +33,96 @@ static GHashTable *qof_choice_table = NULL;
qof_object_register for the choice object. */
static gboolean qof_choice_is_initialized(void)
{
if(!qof_choice_table)
{
qof_choice_table = g_hash_table_new(g_str_hash, g_str_equal);
}
if(!qof_choice_table) { return FALSE; }
return TRUE;
if (!qof_choice_table)
{
qof_choice_table = g_hash_table_new(g_str_hash, g_str_equal);
}
if (!qof_choice_table)
{
return FALSE;
}
return TRUE;
}
gboolean qof_object_is_choice(QofIdTypeConst type)
{
gpointer value, check;
gpointer value, check;
value = NULL;
check = NULL;
if(!qof_choice_is_initialized()) { return FALSE; }
g_return_val_if_fail(type != NULL, FALSE);
value = g_hash_table_lookup(qof_choice_table, type);
if((GHashTable*)value) { return TRUE; }
DEBUG (" QOF_TYPE_CHOICE setup failed for %s\n", type);
return FALSE;
value = NULL;
check = NULL;
if (!qof_choice_is_initialized())
{
return FALSE;
}
g_return_val_if_fail(type != NULL, FALSE);
value = g_hash_table_lookup(qof_choice_table, type);
if ((GHashTable*)value)
{
return TRUE;
}
DEBUG (" QOF_TYPE_CHOICE setup failed for %s\n", type);
return FALSE;
}
gboolean
qof_choice_create(char* type)
{
GHashTable *param_table;
GHashTable *param_table;
g_return_val_if_fail(type != NULL, FALSE);
g_return_val_if_fail(qof_choice_is_initialized() == TRUE, FALSE);
param_table = g_hash_table_new(g_str_hash, g_str_equal);
g_hash_table_insert(qof_choice_table, type, param_table);
return TRUE;
g_return_val_if_fail(type != NULL, FALSE);
g_return_val_if_fail(qof_choice_is_initialized() == TRUE, FALSE);
param_table = g_hash_table_new(g_str_hash, g_str_equal);
g_hash_table_insert(qof_choice_table, type, param_table);
return TRUE;
}
gboolean qof_choice_add_class(const char* select,
char* option,
char* param_name)
char* option,
char* param_name)
{
GHashTable *param_table;
GList *option_list;
GHashTable *param_table;
GList *option_list;
option_list = NULL;
param_table = NULL;
g_return_val_if_fail(select != NULL, FALSE);
g_return_val_if_fail(qof_object_is_choice(select), FALSE);
param_table = (GHashTable*)g_hash_table_lookup(qof_choice_table, select);
g_return_val_if_fail(param_table, FALSE);
option_list = (GList*)g_hash_table_lookup(param_table, param_name);
option_list = g_list_append(option_list, option);
g_hash_table_insert(param_table, param_name, option_list);
return TRUE;
option_list = NULL;
param_table = NULL;
g_return_val_if_fail(select != NULL, FALSE);
g_return_val_if_fail(qof_object_is_choice(select), FALSE);
param_table = (GHashTable*)g_hash_table_lookup(qof_choice_table, select);
g_return_val_if_fail(param_table, FALSE);
option_list = (GList*)g_hash_table_lookup(param_table, param_name);
option_list = g_list_append(option_list, option);
g_hash_table_insert(param_table, param_name, option_list);
return TRUE;
}
GList* qof_object_get_choices(QofIdType type, QofParam *param)
{
GList *choices;
GHashTable *param_table;
GList *choices;
GHashTable *param_table;
g_return_val_if_fail(type != NULL, NULL);
g_return_val_if_fail(qof_choice_is_initialized() == TRUE, FALSE);
choices = NULL;
param_table = g_hash_table_lookup(qof_choice_table, type);
choices = g_hash_table_lookup(param_table, param->param_name);
return choices;
g_return_val_if_fail(type != NULL, NULL);
g_return_val_if_fail(qof_choice_is_initialized() == TRUE, FALSE);
choices = NULL;
param_table = g_hash_table_lookup(qof_choice_table, type);
choices = g_hash_table_lookup(param_table, param->param_name);
return choices;
}
gboolean qof_choice_check(const char* choice_obj,
const char *param_name,
const char* choice )
const char *param_name,
const char* choice )
{
GList *choices, *result;
GHashTable *param_table;
GList *choices, *result;
GHashTable *param_table;
choices = result = NULL;
g_return_val_if_fail(qof_object_is_choice(choice_obj), FALSE);
param_table = g_hash_table_lookup(qof_choice_table, choice_obj);
choices = g_hash_table_lookup(param_table, param_name);
result = g_list_find(choices, choice);
if(!result) { return FALSE; }
return TRUE;
choices = result = NULL;
g_return_val_if_fail(qof_object_is_choice(choice_obj), FALSE);
param_table = g_hash_table_lookup(qof_choice_table, choice_obj);
choices = g_hash_table_lookup(param_table, param_name);
result = g_list_find(choices, choice);
if (!result)
{
return FALSE;
}
return TRUE;
}

View File

@ -151,8 +151,8 @@ GList* qof_object_get_choices(QofIdType type, QofParam *param);
this parameter of this object. Otherwise, FALSE
*/
gboolean qof_choice_check(const char* choice_obj,
const char *param_name,
const char* choice);
const char *param_name,
const char* choice);
/** @} */
/** @} */

View File

@ -36,8 +36,8 @@ static gboolean initialized = FALSE;
static gboolean clear_table (gpointer key, gpointer value, gpointer user_data)
{
g_hash_table_destroy (value);
return TRUE;
g_hash_table_destroy (value);
return TRUE;
}
/* *******************************************************************/
@ -54,29 +54,29 @@ static gboolean check_init (void)
void
qof_class_init(void)
{
if (initialized) return;
initialized = TRUE;
if (initialized) return;
initialized = TRUE;
classTable = g_hash_table_new (g_str_hash, g_str_equal);
sortTable = g_hash_table_new (g_str_hash, g_str_equal);
classTable = g_hash_table_new (g_str_hash, g_str_equal);
sortTable = g_hash_table_new (g_str_hash, g_str_equal);
}
void
qof_class_shutdown (void)
{
if (!initialized) return;
initialized = FALSE;
if (!initialized) return;
initialized = FALSE;
g_hash_table_foreach_remove (classTable, clear_table, NULL);
g_hash_table_destroy (classTable);
g_hash_table_destroy (sortTable);
g_hash_table_foreach_remove (classTable, clear_table, NULL);
g_hash_table_destroy (classTable);
g_hash_table_destroy (sortTable);
}
QofSortFunc
qof_class_get_default_sort (QofIdTypeConst obj_name)
{
if (!obj_name) return NULL;
return g_hash_table_lookup (sortTable, obj_name);
if (!obj_name) return NULL;
return g_hash_table_lookup (sortTable, obj_name);
}
/* *******************************************************************/
@ -87,218 +87,259 @@ qof_class_register (QofIdTypeConst obj_name,
QofSortFunc default_sort_function,
const QofParam *params)
{
GHashTable *ht;
int i;
GHashTable *ht;
int i;
if (!obj_name) return;
if (!check_init()) return;
if (!obj_name) return;
if (!check_init()) return;
if (default_sort_function)
{
g_hash_table_insert (sortTable, (char *)obj_name, default_sort_function);
}
if (default_sort_function)
{
g_hash_table_insert (sortTable, (char *)obj_name, default_sort_function);
}
ht = g_hash_table_lookup (classTable, obj_name);
ht = g_hash_table_lookup (classTable, obj_name);
/* If it doesn't already exist, create a new table for this object */
if (!ht)
{
ht = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_insert (classTable, (char *)obj_name, ht);
}
/* If it doesn't already exist, create a new table for this object */
if (!ht)
{
ht = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_insert (classTable, (char *)obj_name, ht);
}
/* At least right now, we allow dummy, parameterless objects,
* for testing purposes. Although I suppose that should be
* an error.. */
/* Now insert all the parameters */
if (params)
{
for (i = 0; params[i].param_name; i++)
g_hash_table_insert (ht,
(char *)params[i].param_name,
(gpointer)&(params[i]));
}
/* At least right now, we allow dummy, parameterless objects,
* for testing purposes. Although I suppose that should be
* an error.. */
/* Now insert all the parameters */
if (params)
{
for (i = 0; params[i].param_name; i++)
g_hash_table_insert (ht,
(char *)params[i].param_name,
(gpointer)&(params[i]));
}
}
gboolean
qof_class_is_registered (QofIdTypeConst obj_name)
{
if (!obj_name) return FALSE;
if (!check_init()) return FALSE;
if (!obj_name) return FALSE;
if (!check_init()) return FALSE;
if (g_hash_table_lookup (classTable, obj_name)) return TRUE;
if (g_hash_table_lookup (classTable, obj_name)) return TRUE;
return FALSE;
return FALSE;
}
const QofParam *
qof_class_get_parameter (QofIdTypeConst obj_name,
const char *parameter)
const char *parameter)
{
GHashTable *ht;
GHashTable *ht;
g_return_val_if_fail (obj_name, NULL);
g_return_val_if_fail (parameter, NULL);
if (!check_init()) return NULL;
g_return_val_if_fail (obj_name, NULL);
g_return_val_if_fail (parameter, NULL);
if (!check_init()) return NULL;
ht = g_hash_table_lookup (classTable, obj_name);
if (!ht)
{
PWARN ("no object of type %s", obj_name);
return NULL;
}
ht = g_hash_table_lookup (classTable, obj_name);
if (!ht)
{
PWARN ("no object of type %s", obj_name);
return NULL;
}
return (g_hash_table_lookup (ht, parameter));
return (g_hash_table_lookup (ht, parameter));
}
QofAccessFunc
qof_class_get_parameter_getter (QofIdTypeConst obj_name,
const char *parameter)
const char *parameter)
{
const QofParam *prm;
const QofParam *prm;
g_return_val_if_fail (obj_name, NULL);
g_return_val_if_fail (parameter, NULL);
g_return_val_if_fail (obj_name, NULL);
g_return_val_if_fail (parameter, NULL);
prm = qof_class_get_parameter (obj_name, parameter);
if (prm)
return prm->param_getfcn;
prm = qof_class_get_parameter (obj_name, parameter);
if (prm)
return prm->param_getfcn;
return NULL;
return NULL;
}
QofSetterFunc
qof_class_get_parameter_setter (QofIdTypeConst obj_name,
const char *parameter)
const char *parameter)
{
const QofParam *prm;
const QofParam *prm;
g_return_val_if_fail (obj_name, NULL);
g_return_val_if_fail (parameter, NULL);
g_return_val_if_fail (obj_name, NULL);
g_return_val_if_fail (parameter, NULL);
prm = qof_class_get_parameter (obj_name, parameter);
if (prm)
return prm->param_setfcn;
prm = qof_class_get_parameter (obj_name, parameter);
if (prm)
return prm->param_setfcn;
return NULL;
return NULL;
}
QofType
qof_class_get_parameter_type (QofIdTypeConst obj_name,
const char *param_name)
const char *param_name)
{
const QofParam *prm;
const QofParam *prm;
if (!obj_name || !param_name) return NULL;
if (!obj_name || !param_name) return NULL;
prm = qof_class_get_parameter (obj_name, param_name);
if (!prm) return NULL;
prm = qof_class_get_parameter (obj_name, param_name);
if (!prm) return NULL;
return (prm->param_type);
return (prm->param_type);
}
/* ================================================================ */
struct class_iterate {
QofClassForeachCB fcn;
gpointer data;
struct class_iterate
{
QofClassForeachCB fcn;
gpointer data;
};
static void
class_foreach_cb (gpointer key, gpointer item, gpointer arg)
{
struct class_iterate *iter = arg;
QofIdTypeConst id = key;
struct class_iterate *iter = arg;
QofIdTypeConst id = key;
iter->fcn (id, iter->data);
iter->fcn (id, iter->data);
}
void
qof_class_foreach (QofClassForeachCB cb, gpointer user_data)
{
struct class_iterate iter;
struct class_iterate iter;
if (!cb) return;
if (!classTable) return;
if (!cb) return;
if (!classTable) return;
iter.fcn = cb;
iter.data = user_data;
iter.fcn = cb;
iter.data = user_data;
g_hash_table_foreach (classTable, class_foreach_cb, &iter);
g_hash_table_foreach (classTable, class_foreach_cb, &iter);
}
/* ================================================================ */
struct parm_iterate {
QofParamForeachCB fcn;
gpointer data;
struct parm_iterate
{
QofParamForeachCB fcn;
gpointer data;
};
static void
param_foreach_cb (gpointer key, gpointer item, gpointer arg)
{
struct parm_iterate *iter = arg;
QofParam *parm = item;
struct parm_iterate *iter = arg;
QofParam *parm = item;
iter->fcn (parm, iter->data);
iter->fcn (parm, iter->data);
}
void
qof_class_param_foreach (QofIdTypeConst obj_name,
QofParamForeachCB cb, gpointer user_data)
{
struct parm_iterate iter;
GHashTable *param_ht;
struct parm_iterate iter;
GHashTable *param_ht;
if (!obj_name || !cb) return;
if (!classTable) return;
param_ht = g_hash_table_lookup (classTable, obj_name);
if (!param_ht) return;
if (!obj_name || !cb) return;
if (!classTable) return;
param_ht = g_hash_table_lookup (classTable, obj_name);
if (!param_ht) return;
iter.fcn = cb;
iter.data = user_data;
iter.fcn = cb;
iter.data = user_data;
g_hash_table_foreach (param_ht, param_foreach_cb, &iter);
g_hash_table_foreach (param_ht, param_foreach_cb, &iter);
}
struct param_ref_list
{
GList *list;
GList *list;
};
static void
find_reference_param_cb(QofParam *param, gpointer user_data)
{
struct param_ref_list *b;
struct param_ref_list *b;
b = (struct param_ref_list*)user_data;
if((param->param_getfcn == NULL)||(param->param_setfcn == NULL)) { return; }
if(0 == safe_strcmp(param->param_type, QOF_TYPE_STRING)) { return; }
if(0 == safe_strcmp(param->param_type, QOF_TYPE_NUMERIC)) { return; }
if(0 == safe_strcmp(param->param_type, QOF_TYPE_DATE)) { return; }
if(0 == safe_strcmp(param->param_type, QOF_TYPE_CHAR)) { return; }
if(0 == safe_strcmp(param->param_type, QOF_TYPE_DEBCRED)) { return; }
if(0 == safe_strcmp(param->param_type, QOF_TYPE_GUID)) { return; }
if(0 == safe_strcmp(param->param_type, QOF_TYPE_INT32)) { return; }
if(0 == safe_strcmp(param->param_type, QOF_TYPE_INT64)) { return; }
if(0 == safe_strcmp(param->param_type, QOF_TYPE_DOUBLE)) { return; }
if(0 == safe_strcmp(param->param_type, QOF_TYPE_KVP)) { return; }
if(0 == safe_strcmp(param->param_type, QOF_TYPE_BOOLEAN)) { return; }
if(0 == safe_strcmp(param->param_type, QOF_ID_BOOK)) { return; }
b->list = g_list_append(b->list, param);
b = (struct param_ref_list*)user_data;
if ((param->param_getfcn == NULL) || (param->param_setfcn == NULL))
{
return;
}
if (0 == safe_strcmp(param->param_type, QOF_TYPE_STRING))
{
return;
}
if (0 == safe_strcmp(param->param_type, QOF_TYPE_NUMERIC))
{
return;
}
if (0 == safe_strcmp(param->param_type, QOF_TYPE_DATE))
{
return;
}
if (0 == safe_strcmp(param->param_type, QOF_TYPE_CHAR))
{
return;
}
if (0 == safe_strcmp(param->param_type, QOF_TYPE_DEBCRED))
{
return;
}
if (0 == safe_strcmp(param->param_type, QOF_TYPE_GUID))
{
return;
}
if (0 == safe_strcmp(param->param_type, QOF_TYPE_INT32))
{
return;
}
if (0 == safe_strcmp(param->param_type, QOF_TYPE_INT64))
{
return;
}
if (0 == safe_strcmp(param->param_type, QOF_TYPE_DOUBLE))
{
return;
}
if (0 == safe_strcmp(param->param_type, QOF_TYPE_KVP))
{
return;
}
if (0 == safe_strcmp(param->param_type, QOF_TYPE_BOOLEAN))
{
return;
}
if (0 == safe_strcmp(param->param_type, QOF_ID_BOOK))
{
return;
}
b->list = g_list_append(b->list, param);
}
GList*
qof_class_get_referenceList(QofIdTypeConst type)
{
GList *ref_list;
struct param_ref_list b;
GList *ref_list;
struct param_ref_list b;
ref_list = NULL;
b.list = NULL;
qof_class_param_foreach(type, find_reference_param_cb, &b);
ref_list = g_list_copy(b.list);
return ref_list;
ref_list = NULL;
b.list = NULL;
qof_class_param_foreach(type, find_reference_param_cb, &b);
ref_list = g_list_copy(b.list);
return ref_list;
}

View File

@ -25,14 +25,14 @@
/** @addtogroup Class
This file defines a class messaging system reminiscent of
traditional OO-style setter and getter interfaces to object
traditional OO-style setter and getter interfaces to object
properties. A C-language object can declare a collection
of setters and getters on itself that can then be used
to perform run-time (as opposed to compile-time) bindings
of setters and getters on itself that can then be used
to perform run-time (as opposed to compile-time) bindings
to the object.
To put it differently, a QOF class is a set of parameter
getters and setters that are associated with an object type.
getters and setters that are associated with an object type.
Given a pointer to some thing, the setters and getters can
be used to get and set values out of that thing. Note
that the pointer to "some thing" need not be a pointer
@ -44,23 +44,23 @@
Because a QOF Class associates getters and setters with
a type, one can then ask, at run time, what parameters
are associated with a given type, even if those parameters
were not known at compile time. Thus, a QOF Class is
were not known at compile time. Thus, a QOF Class is
sort-of like a DynAny implementation. QOF classes can
be used to provide "object introspection", i.e. asking
be used to provide "object introspection", i.e. asking
object to describe itself.
The QOF Query subsystem depends on QOF classes having been
declared; the Query uses the getters to get values associated
with particular instances.
A QofAccessFunc or QofSetterFunc do not need to be public
A QofAccessFunc or QofSetterFunc do not need to be public
functions, if you need to add functions to an object with an
established API, define the additional QOF routines as static.
Only the register routine needs to be public.
@{ */
/** @file qofclass.h
@brief API for registering paramters on objects
@brief API for registering paramters on objects
@author Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU>
@author Copyright (C) 2003 Linas Vepstas <linas@linas.org>
@author Copyright (c) 2005 Neil Williams <linux@codehelp.co.uk>
@ -76,7 +76,7 @@
/** \name Core types
Core data types for objects that can be used in parameters.
Note that QofIdTypes may also be used and will create a
Note that QofIdTypes may also be used and will create a
single reference between two known objects.
@{
@ -102,28 +102,28 @@ These are \b NOT the same as the main collections in the QofBook.
-# The entity type within the collection can be determined at run time.
-# Easy conversions to GList or whatever in the param_setfcn handler.
-# Each parameter can have its own collection.
-# Each entity can have a different *type* of collection to its siblings,
-# Each entity can have a different *type* of collection to its siblings,
provided that it is acceptable to the set function.
-# Each object decides which types are acceptable for which parameter in the
set functions. This is then part of the API for that object.
-# Each object decides which types are acceptable for which parameter in the
set functions. This is then part of the API for that object.
QOF_TYPE_COLLECT has two functions, both related to one-to-many
QOF_TYPE_COLLECT has two functions, both related to one-to-many
links:
- Represent a reference between 2 entities with a list of acceptable types.
- Represent a reference between 2 entities with a list of acceptable types.
(one object linked to many types of single entities)
- Represent a reference between one entity and many entities of another type.
(one object linked to many entities of a single type.)
- Represent a reference between one entity and many entities of another type.
(one object linked to many entities of a single type.)
If the set function can handle it, it could also be used for true one-to-many
If the set function can handle it, it could also be used for true one-to-many
links: one object linked to many entities of many types.
n.b. Always subject to each collection holding only one type at runtime.
(otherwise use books).
n.b. Always subject to each collection holding only one type at runtime.
(otherwise use books).
*/
/** @} */
/** Type of Paramters (String, Date, Numeric, GUID, etc.) */
typedef const char * QofType;
*/
/** @} */
/** Type of Paramters (String, Date, Numeric, GUID, etc.) */
typedef const char * QofType;
typedef struct _QofParam QofParam;
@ -166,24 +166,24 @@ typedef gint (*QofCompareFunc) (gpointer a, gpointer b,
* object (QofIdType) or it can be a core data type (QofType).
* -- param_getfcn is the function to actually obtain the parameter
* -- param_setfcn is the function to actually set the parameter
* -- param_userdata is a place where the object author can place any
* desired object-author-defined data (and thus can be used by the
* -- param_userdata is a place where the object author can place any
* desired object-author-defined data (and thus can be used by the
* author-defined setter/getter).
*
* Either the getter or the setter may be NULL.
*
* XXX todo/fixme: need to define a destroy callback, so that when
* the param memory is freed, the callback can be used to release the
* the param memory is freed, the callback can be used to release the
* user-defined data.
*/
struct _QofParam
struct _QofParam
{
const char * param_name;
QofType param_type;
QofAccessFunc param_getfcn;
QofSetterFunc param_setfcn;
QofCompareFunc param_compfcn;
gpointer param_userdata;
const char * param_name;
QofType param_type;
QofAccessFunc param_getfcn;
QofSetterFunc param_setfcn;
QofCompareFunc param_compfcn;
gpointer param_userdata;
};
/** This function is the default sort function for a particular object type */
@ -196,10 +196,10 @@ typedef int (*QofSortFunc)(gconstpointer, gconstpointer);
* is no particular requirement for there to be a setter for every
* getter or even vice-versa, nor is there any requirement for these
* to map 'cleanly' or orthogonally to the underlying object. The
* parameters are really just a set of value setting and getting
* parameters are really just a set of value setting and getting
* routines.
*
* The "params" argument must be a NULL-terminated array of QofParam.
* The "params" argument must be a NULL-terminated array of QofParam.
* It may be NULL if there are no parameters to be registered.
*/
void qof_class_register (QofIdTypeConst obj_name,
@ -225,7 +225,7 @@ void qof_class_register (QofIdTypeConst obj_name,
* qof_class_register ("myObjectName", myObjectCompare, &myParams);
*/
/** Return true if the the indicated type is registered,
/** Return true if the the indicated type is registered,
* else return FALSE.
*/
gboolean qof_class_is_registered (QofIdTypeConst obj_name);
@ -236,15 +236,15 @@ QofType qof_class_get_parameter_type (QofIdTypeConst obj_name,
/** Return the registered Parameter Definition for the requested parameter */
const QofParam * qof_class_get_parameter (QofIdTypeConst obj_name,
const char *parameter);
const char *parameter);
/** Return the object's parameter getter function */
QofAccessFunc qof_class_get_parameter_getter (QofIdTypeConst obj_name,
const char *parameter);
const char *parameter);
/** Return the object's parameter setter function */
QofSetterFunc qof_class_get_parameter_setter (QofIdTypeConst obj_name,
const char *parameter);
const char *parameter);
/** Type definition for the class callback function. */
typedef void (*QofClassForeachCB) (QofIdTypeConst, gpointer);
@ -257,7 +257,7 @@ void qof_class_foreach (QofClassForeachCB, gpointer user_data);
/** Type definition for the paramter callback function. */
typedef void (*QofParamForeachCB) (QofParam *, gpointer user_data);
/** Call the callback once for each parameter on the indicated
/** Call the callback once for each parameter on the indicated
* object class. The 'user_data' is passed back to the callback.
*/
void qof_class_param_foreach (QofIdTypeConst obj_name,

View File

@ -30,10 +30,10 @@
/* for backwards compatibility - to be moved back to qofevent.c in libqof2 */
typedef struct
{
QofEventHandler handler;
gpointer user_data;
QofEventHandler handler;
gpointer user_data;
gint handler_id;
gint handler_id;
} HandlerInfo;
/* generates an event even when events are suspended! */

View File

@ -42,202 +42,206 @@ static QofLogModule log_module = QOF_MOD_ENGINE;
static gint
find_next_handler_id(void)
{
HandlerInfo *hi;
gint handler_id;
GList *node;
HandlerInfo *hi;
gint handler_id;
GList *node;
/* look for a free handler id */
handler_id = next_handler_id;
node = handlers;
/* look for a free handler id */
handler_id = next_handler_id;
node = handlers;
while (node)
{
hi = node->data;
if (hi->handler_id == handler_id)
while (node)
{
handler_id++;
node = handlers;
continue;
}
hi = node->data;
node = node->next;
}
/* Update id for next registration */
next_handler_id = handler_id + 1;
return handler_id;
if (hi->handler_id == handler_id)
{
handler_id++;
node = handlers;
continue;
}
node = node->next;
}
/* Update id for next registration */
next_handler_id = handler_id + 1;
return handler_id;
}
gint
qof_event_register_handler (QofEventHandler handler, gpointer user_data)
{
HandlerInfo *hi;
gint handler_id;
HandlerInfo *hi;
gint handler_id;
ENTER ("(handler=%p, data=%p)", handler, user_data);
ENTER ("(handler=%p, data=%p)", handler, user_data);
/* sanity check */
if (!handler)
{
PERR ("no handler specified");
return 0;
}
/* sanity check */
if (!handler)
{
PERR ("no handler specified");
return 0;
}
/* look for a free handler id */
handler_id = find_next_handler_id();
/* look for a free handler id */
handler_id = find_next_handler_id();
/* Found one, add the handler */
hi = g_new0 (HandlerInfo, 1);
/* Found one, add the handler */
hi = g_new0 (HandlerInfo, 1);
hi->handler = handler;
hi->user_data = user_data;
hi->handler_id = handler_id;
hi->handler = handler;
hi->user_data = user_data;
hi->handler_id = handler_id;
handlers = g_list_prepend (handlers, hi);
LEAVE ("(handler=%p, data=%p) handler_id=%d", handler, user_data, handler_id);
return handler_id;
handlers = g_list_prepend (handlers, hi);
LEAVE ("(handler=%p, data=%p) handler_id=%d", handler, user_data, handler_id);
return handler_id;
}
void
qof_event_unregister_handler (gint handler_id)
{
GList *node;
GList *node;
ENTER ("(handler_id=%d)", handler_id);
for (node = handlers; node; node = node->next)
{
HandlerInfo *hi = node->data;
ENTER ("(handler_id=%d)", handler_id);
for (node = handlers; node; node = node->next)
{
HandlerInfo *hi = node->data;
if (hi->handler_id != handler_id)
continue;
if (hi->handler_id != handler_id)
continue;
/* Normally, we could actually remove the handler's node from the
list, but we may be unregistering the event handler as a result
of a generated event, such as QOF_EVENT_DESTROY. In that case,
we're in the middle of walking the GList and it is wrong to
modify the list. So, instead, we just NULL the handler. */
if(hi->handler)
LEAVE ("(handler_id=%d) handler=%p data=%p", handler_id,
hi->handler, hi->user_data);
/* Normally, we could actually remove the handler's node from the
list, but we may be unregistering the event handler as a result
of a generated event, such as QOF_EVENT_DESTROY. In that case,
we're in the middle of walking the GList and it is wrong to
modify the list. So, instead, we just NULL the handler. */
if (hi->handler)
LEAVE ("(handler_id=%d) handler=%p data=%p", handler_id,
hi->handler, hi->user_data);
/* safety -- clear the handler in case we're running events now */
hi->handler = NULL;
/* safety -- clear the handler in case we're running events now */
hi->handler = NULL;
if (handler_run_level == 0) {
handlers = g_list_remove_link (handlers, node);
g_list_free_1 (node);
g_free (hi);
} else {
pending_deletes++;
if (handler_run_level == 0)
{
handlers = g_list_remove_link (handlers, node);
g_list_free_1 (node);
g_free (hi);
}
else
{
pending_deletes++;
}
return;
}
return;
}
PERR ("no such handler: %d", handler_id);
PERR ("no such handler: %d", handler_id);
}
void
qof_event_suspend (void)
{
suspend_counter++;
suspend_counter++;
if (suspend_counter == 0)
{
PERR ("suspend counter overflow");
}
if (suspend_counter == 0)
{
PERR ("suspend counter overflow");
}
}
void
qof_event_resume (void)
{
if (suspend_counter == 0)
{
PERR ("suspend counter underflow");
return;
}
if (suspend_counter == 0)
{
PERR ("suspend counter underflow");
return;
}
suspend_counter--;
suspend_counter--;
}
static void
qof_event_generate_internal (QofInstance *entity, QofEventId event_id,
gpointer event_data)
qof_event_generate_internal (QofInstance *entity, QofEventId event_id,
gpointer event_data)
{
GList *node;
GList *next_node = NULL;
gboolean use_old_handlers = FALSE;
GList *node;
GList *next_node = NULL;
gboolean use_old_handlers = FALSE;
g_return_if_fail(entity);
g_return_if_fail(entity);
if (event_id <= QOF_EVENT__LAST)
{
use_old_handlers = TRUE;
}
switch (event_id)
{
case QOF_EVENT_NONE: {
/* if none, don't log, just return. */
return;
}
}
handler_run_level++;
for (node = handlers; node; node = next_node)
{
HandlerInfo *hi = node->data;
next_node = node->next;
if (hi->handler)
if (event_id <= QOF_EVENT__LAST)
{
PINFO("id=%d hi=%p han=%p data=%p", hi->handler_id, hi,
hi->handler, event_data);
hi->handler (entity, event_id, hi->user_data, event_data);
use_old_handlers = TRUE;
}
}
handler_run_level--;
/* If we're the outtermost event runner and we have pending deletes
* then go delete the handlers now.
*/
if (handler_run_level == 0 && pending_deletes)
{
switch (event_id)
{
case QOF_EVENT_NONE:
{
/* if none, don't log, just return. */
return;
}
}
handler_run_level++;
for (node = handlers; node; node = next_node)
{
HandlerInfo *hi = node->data;
next_node = node->next;
if (hi->handler == NULL)
{
/* remove this node from the list, then free this node */
handlers = g_list_remove_link (handlers, node);
g_list_free_1 (node);
g_free (hi);
}
HandlerInfo *hi = node->data;
next_node = node->next;
if (hi->handler)
{
PINFO("id=%d hi=%p han=%p data=%p", hi->handler_id, hi,
hi->handler, event_data);
hi->handler (entity, event_id, hi->user_data, event_data);
}
}
handler_run_level--;
/* If we're the outtermost event runner and we have pending deletes
* then go delete the handlers now.
*/
if (handler_run_level == 0 && pending_deletes)
{
for (node = handlers; node; node = next_node)
{
HandlerInfo *hi = node->data;
next_node = node->next;
if (hi->handler == NULL)
{
/* remove this node from the list, then free this node */
handlers = g_list_remove_link (handlers, node);
g_list_free_1 (node);
g_free (hi);
}
}
pending_deletes = 0;
}
pending_deletes = 0;
}
}
void
qof_event_force (QofInstance *entity, QofEventId event_id, gpointer event_data)
{
if (!entity)
return;
if (!entity)
return;
qof_event_generate_internal (entity, event_id, event_data);
qof_event_generate_internal (entity, event_id, event_data);
}
void
qof_event_gen (QofInstance *entity, QofEventId event_id, gpointer event_data)
{
if (!entity)
return;
if (!entity)
return;
if (suspend_counter)
return;
if (suspend_counter)
return;
qof_event_generate_internal (entity, event_id, event_data);
qof_event_generate_internal (entity, event_id, event_data);
}
/* =========================== END OF FILE ======================= */

View File

@ -59,7 +59,7 @@ event identifiers must be based on this when using QOF_MAKE_EVENT(). */
/** \brief Default events for backwards compatibility.
These defaults merely replicate previous behaviour,
any process can define their own events.
any process can define their own events.
\note events 5, 6, and 7 are "undefined" as of v0.6.3
for future libqof1 or libqof2 usage.
@ -82,7 +82,7 @@ for future libqof1 or libqof2 usage.
* @param event_data: data to be supplied when handler is invoked.
*/
typedef void (*QofEventHandler) (QofInstance *ent, QofEventId event_type,
gpointer handler_data, gpointer event_data);
gpointer handler_data, gpointer event_data);
/** \brief Register a handler for events.
*
@ -120,7 +120,7 @@ void qof_event_unregister_handler (gint handler_id);
@param event_data: Data to be passed to the event handler just for
this one event. Can be NULL.
*/
void qof_event_gen (QofInstance *entity, QofEventId event_type,
void qof_event_gen (QofInstance *entity, QofEventId event_type,
gpointer event_data);
/** \brief Suspend all engine events.

View File

@ -34,48 +34,48 @@ static GSList *classList = NULL;
/* =================================================================== */
#if 0
static gboolean
static gboolean
clear_table (gpointer key, gpointer value, gpointer user_data)
{
g_slist_free (value);
return TRUE;
g_slist_free (value);
return TRUE;
}
#endif
void
void
qof_gobject_init(void)
{
if (initialized) return;
initialized = TRUE;
// gobjectClassTable = g_hash_table_new (g_str_hash, g_str_equal);
if (initialized) return;
initialized = TRUE;
/* Init the other subsystems that we need */
qof_object_initialize();
qof_query_init ();
// gobjectClassTable = g_hash_table_new (g_str_hash, g_str_equal);
/* Init the other subsystems that we need */
qof_object_initialize();
qof_query_init ();
}
void
void
qof_gobject_shutdown (void)
{
GSList *n;
if (!initialized) return;
initialized = FALSE;
// GSList *n;
for (n=paramList; n; n=n->next) g_free(n->data);
g_slist_free (paramList);
GSList *n;
for (n=classList; n; n=n->next) g_free(n->data);
g_slist_free (classList);
if (!initialized) return;
initialized = FALSE;
// GSList *n;
for (n = paramList; n; n = n->next) g_free(n->data);
g_slist_free (paramList);
for (n = classList; n; n = n->next) g_free(n->data);
g_slist_free (classList);
#if 0
// XXX also need to walk over books, and collection and delete
// the collection get_data instance lists !!
// without this we have a memory leak !!
g_hash_table_foreach_remove (gobjectParamTable, clear_table, NULL);
g_hash_table_destroy (gobjectParamTable);
// XXX also need to walk over books, and collection and delete
// the collection get_data instance lists !!
// without this we have a memory leak !!
g_hash_table_foreach_remove (gobjectParamTable, clear_table, NULL);
g_hash_table_destroy (gobjectParamTable);
#endif
}
@ -83,19 +83,19 @@ qof_gobject_shutdown (void)
#define GOBJECT_TABLE "GobjectTable"
void
void
qof_gobject_register_instance (QofBook *book, QofType type, GObject *gob)
{
QofCollection *coll;
GSList *instance_list;
if (!book || !type) return;
QofCollection *coll;
GSList *instance_list;
coll = qof_book_get_collection (book, type);
if (!book || !type) return;
instance_list = qof_collection_get_data (coll);
instance_list = g_slist_prepend (instance_list, gob);
qof_collection_set_data (coll, instance_list);
coll = qof_book_get_collection (book, type);
instance_list = qof_collection_get_data (coll);
instance_list = g_slist_prepend (instance_list, gob);
qof_collection_set_data (coll, instance_list);
}
/* =================================================================== */
@ -103,98 +103,94 @@ qof_gobject_register_instance (QofBook *book, QofType type, GObject *gob)
static gpointer
qof_gobject_getter (gpointer data, QofParam *getter)
{
GObject *gob = data;
const char *str;
GObject *gob = data;
const char *str;
GParamSpec *gps = getter->param_userdata;
GParamSpec *gps = getter->param_userdata;
/* Note that the return type must actually be of type
* getter->param_type but we just follow the hard-coded
* mapping below ... */
if (G_IS_PARAM_SPEC_STRING(gps))
{
GValue gval = {G_TYPE_INVALID};
g_value_init (&gval, G_TYPE_STRING);
g_object_get_property (gob, getter->param_name, &gval);
/* Note that the return type must actually be of type
* getter->param_type but we just follow the hard-coded
* mapping below ... */
if (G_IS_PARAM_SPEC_STRING(gps))
{
GValue gval = {G_TYPE_INVALID};
g_value_init (&gval, G_TYPE_STRING);
g_object_get_property (gob, getter->param_name, &gval);
str = g_value_get_string (&gval);
return (gpointer) str;
}
else
if (G_IS_PARAM_SPEC_INT(gps))
{
long ival;
GValue gval = {G_TYPE_INVALID};
g_value_init (&gval, G_TYPE_INT);
g_object_get_property (gob, getter->param_name, &gval);
str = g_value_get_string (&gval);
return (gpointer) str;
}
else if (G_IS_PARAM_SPEC_INT(gps))
{
long ival;
ival = g_value_get_int (&gval);
return (gpointer) ival;
}
else
if (G_IS_PARAM_SPEC_UINT(gps))
{
long ival;
GValue gval = {G_TYPE_INVALID};
g_value_init (&gval, G_TYPE_UINT);
g_object_get_property (gob, getter->param_name, &gval);
GValue gval = {G_TYPE_INVALID};
g_value_init (&gval, G_TYPE_INT);
g_object_get_property (gob, getter->param_name, &gval);
ival = g_value_get_uint (&gval);
return (gpointer) ival;
}
else
if (G_IS_PARAM_SPEC_BOOLEAN(gps))
{
gboolean ival;
GValue gval = {G_TYPE_INVALID};
g_value_init (&gval, G_TYPE_BOOLEAN);
g_object_get_property (gob, getter->param_name, &gval);
ival = g_value_get_int (&gval);
return (gpointer) ival;
}
else if (G_IS_PARAM_SPEC_UINT(gps))
{
long ival;
GValue gval = {G_TYPE_INVALID};
g_value_init (&gval, G_TYPE_UINT);
g_object_get_property (gob, getter->param_name, &gval);
ival = g_value_get_boolean (&gval);
return GINT_TO_POINTER( ival);
}
ival = g_value_get_uint (&gval);
return (gpointer) ival;
}
else if (G_IS_PARAM_SPEC_BOOLEAN(gps))
{
gboolean ival;
PWARN ("unhandled parameter type %s for paramter %s",
G_PARAM_SPEC_TYPE_NAME(gps), getter->param_name);
return NULL;
GValue gval = {G_TYPE_INVALID};
g_value_init (&gval, G_TYPE_BOOLEAN);
g_object_get_property (gob, getter->param_name, &gval);
ival = g_value_get_boolean (&gval);
return GINT_TO_POINTER( ival);
}
PWARN ("unhandled parameter type %s for paramter %s",
G_PARAM_SPEC_TYPE_NAME(gps), getter->param_name);
return NULL;
}
static double
qof_gobject_double_getter (gpointer data, QofParam *getter)
{
GObject *gob = data;
double fval;
GParamSpec *gps = getter->param_userdata;
GObject *gob = data;
double fval;
/* Note that the return type must actually be of type
* getter->param_type but we just follow the hard-coded
* mapping below ... */
if (G_IS_PARAM_SPEC_FLOAT(gps))
{
GValue gval = {G_TYPE_INVALID};
g_value_init (&gval, G_TYPE_FLOAT);
g_object_get_property (gob, getter->param_name, &gval);
GParamSpec *gps = getter->param_userdata;
fval = g_value_get_float (&gval);
return fval;
}
else
if (G_IS_PARAM_SPEC_DOUBLE(gps))
{
GValue gval = {G_TYPE_INVALID};
g_value_init (&gval, G_TYPE_DOUBLE);
g_object_get_property (gob, getter->param_name, &gval);
/* Note that the return type must actually be of type
* getter->param_type but we just follow the hard-coded
* mapping below ... */
if (G_IS_PARAM_SPEC_FLOAT(gps))
{
GValue gval = {G_TYPE_INVALID};
g_value_init (&gval, G_TYPE_FLOAT);
g_object_get_property (gob, getter->param_name, &gval);
fval = g_value_get_double (&gval);
return fval;
}
fval = g_value_get_float (&gval);
return fval;
}
else if (G_IS_PARAM_SPEC_DOUBLE(gps))
{
GValue gval = {G_TYPE_INVALID};
g_value_init (&gval, G_TYPE_DOUBLE);
g_object_get_property (gob, getter->param_name, &gval);
PWARN ("unhandled parameter type %s for paramter %s",
G_PARAM_SPEC_TYPE_NAME(gps), getter->param_name);
return 0.0;
fval = g_value_get_double (&gval);
return fval;
}
PWARN ("unhandled parameter type %s for paramter %s",
G_PARAM_SPEC_TYPE_NAME(gps), getter->param_name);
return 0.0;
}
/* =================================================================== */
@ -204,125 +200,119 @@ qof_gobject_double_getter (gpointer data, QofParam *getter)
static void
qof_gobject_foreach (QofCollection *coll, QofInstanceForeachCB cb, gpointer ud)
{
GSList *n;
n = qof_collection_get_data (coll);
for (; n; n=n->next)
{
cb (n->data, ud);
}
GSList *n;
n = qof_collection_get_data (coll);
for (; n; n = n->next)
{
cb (n->data, ud);
}
}
/* =================================================================== */
void
qof_gobject_register (QofType e_type, GObjectClass *obclass)
{
int i;
int j;
QofParam *qof_param_list, *qpar;
QofObject *class_def;
GParamSpec **prop_list, *gparam;
guint n_props;
int i;
int j;
QofParam *qof_param_list, *qpar;
QofObject *class_def;
GParamSpec **prop_list, *gparam;
guint n_props;
/* Get the GObject properties, convert to QOF properties */
prop_list = g_object_class_list_properties (obclass, &n_props);
/* Get the GObject properties, convert to QOF properties */
prop_list = g_object_class_list_properties (obclass, &n_props);
qof_param_list = g_new0 (QofParam, n_props);
paramList = g_slist_prepend (paramList, qof_param_list);
qof_param_list = g_new0 (QofParam, n_props);
paramList = g_slist_prepend (paramList, qof_param_list);
PINFO ("object %s has %d props", e_type, n_props);
j=0;
for (i=0; i<n_props; i++)
{
gparam = prop_list[i];
qpar = &qof_param_list[j];
PINFO ("object %s has %d props", e_type, n_props);
j = 0;
for (i = 0; i < n_props; i++)
{
gparam = prop_list[i];
qpar = &qof_param_list[j];
PINFO ("param %d %s is type %s",
i, gparam->name, G_PARAM_SPEC_TYPE_NAME(gparam));
PINFO ("param %d %s is type %s",
i, gparam->name, G_PARAM_SPEC_TYPE_NAME(gparam));
qpar->param_name = g_param_spec_get_name (gparam);
qpar->param_getfcn = (QofAccessFunc)qof_gobject_getter;
qpar->param_setfcn = NULL;
qpar->param_userdata = gparam;
if ((G_IS_PARAM_SPEC_INT(gparam)) ||
(G_IS_PARAM_SPEC_UINT(gparam)) ||
(G_IS_PARAM_SPEC_ENUM(gparam)) ||
(G_IS_PARAM_SPEC_FLAGS(gparam)))
{
qpar->param_type = QOF_TYPE_INT32;
j++;
}
else
if ((G_IS_PARAM_SPEC_INT64(gparam)) ||
(G_IS_PARAM_SPEC_UINT64(gparam)))
{
qpar->param_type = QOF_TYPE_INT64;
j++;
}
else
if (G_IS_PARAM_SPEC_BOOLEAN(gparam))
{
qpar->param_type = QOF_TYPE_BOOLEAN;
j++;
}
else
if (G_IS_PARAM_SPEC_STRING(gparam))
{
qpar->param_type = QOF_TYPE_STRING;
j++;
}
else
if ((G_IS_PARAM_SPEC_POINTER(gparam)) ||
(G_IS_PARAM_SPEC_OBJECT(gparam)))
{
/* No-op, silently ignore. Someday we should handle this ... */
}
else
if ((G_IS_PARAM_SPEC_FLOAT(gparam)) ||
(G_IS_PARAM_SPEC_DOUBLE(gparam)))
{
qpar->param_getfcn = (QofAccessFunc) qof_gobject_double_getter;
qpar->param_type = QOF_TYPE_DOUBLE;
j++;
}
else
if (G_IS_PARAM_SPEC_CHAR(gparam))
{
qpar->param_type = QOF_TYPE_CHAR;
j++;
}
else
{
PWARN ("Unknown/unhandled parameter type %s on %s:%s\n",
G_PARAM_SPEC_TYPE_NAME(gparam), e_type, qpar->param_name);
qpar->param_name = g_param_spec_get_name (gparam);
qpar->param_getfcn = (QofAccessFunc)qof_gobject_getter;
qpar->param_setfcn = NULL;
qpar->param_userdata = gparam;
if ((G_IS_PARAM_SPEC_INT(gparam)) ||
(G_IS_PARAM_SPEC_UINT(gparam)) ||
(G_IS_PARAM_SPEC_ENUM(gparam)) ||
(G_IS_PARAM_SPEC_FLAGS(gparam)))
{
qpar->param_type = QOF_TYPE_INT32;
j++;
}
else if ((G_IS_PARAM_SPEC_INT64(gparam)) ||
(G_IS_PARAM_SPEC_UINT64(gparam)))
{
qpar->param_type = QOF_TYPE_INT64;
j++;
}
else if (G_IS_PARAM_SPEC_BOOLEAN(gparam))
{
qpar->param_type = QOF_TYPE_BOOLEAN;
j++;
}
else if (G_IS_PARAM_SPEC_STRING(gparam))
{
qpar->param_type = QOF_TYPE_STRING;
j++;
}
else if ((G_IS_PARAM_SPEC_POINTER(gparam)) ||
(G_IS_PARAM_SPEC_OBJECT(gparam)))
{
/* No-op, silently ignore. Someday we should handle this ... */
}
else if ((G_IS_PARAM_SPEC_FLOAT(gparam)) ||
(G_IS_PARAM_SPEC_DOUBLE(gparam)))
{
qpar->param_getfcn = (QofAccessFunc) qof_gobject_double_getter;
qpar->param_type = QOF_TYPE_DOUBLE;
j++;
}
else if (G_IS_PARAM_SPEC_CHAR(gparam))
{
qpar->param_type = QOF_TYPE_CHAR;
j++;
}
else
{
PWARN ("Unknown/unhandled parameter type %s on %s:%s\n",
G_PARAM_SPEC_TYPE_NAME(gparam), e_type, qpar->param_name);
}
}
}
/* NULL-terminated list! */
qof_param_list[j].param_type = NULL;
/* NULL-terminated list! */
qof_param_list[j].param_type = NULL;
qof_class_register (e_type, NULL, qof_param_list);
qof_class_register (e_type, NULL, qof_param_list);
/* ------------------------------------------------------ */
/* Now do the class itself */
class_def = g_new0 (QofObject, 1);
classList = g_slist_prepend (classList, class_def);
/* ------------------------------------------------------ */
/* Now do the class itself */
class_def = g_new0 (QofObject, 1);
classList = g_slist_prepend (classList, class_def);
class_def->interface_version = QOF_OBJECT_VERSION;
class_def->e_type = e_type;
/* We could let the user specify a "nick" here, but
* the actual class name seems reasonable, e.g. for debugging. */
class_def->type_label = G_OBJECT_CLASS_NAME (obclass);
class_def->create = NULL;
class_def->book_begin = NULL;
class_def->book_end = NULL;
class_def->is_dirty = NULL;
class_def->mark_clean = NULL;
class_def->foreach = qof_gobject_foreach;
class_def->printable = NULL;
class_def->version_cmp = NULL;
qof_object_register (class_def);
class_def->interface_version = QOF_OBJECT_VERSION;
class_def->e_type = e_type;
/* We could let the user specify a "nick" here, but
* the actual class name seems reasonable, e.g. for debugging. */
class_def->type_label = G_OBJECT_CLASS_NAME (obclass);
class_def->create = NULL;
class_def->book_begin = NULL;
class_def->book_end = NULL;
class_def->is_dirty = NULL;
class_def->mark_clean = NULL;
class_def->foreach = qof_gobject_foreach;
class_def->printable = NULL;
class_def->version_cmp = NULL;
qof_object_register (class_def);
}
/* ======================= END OF FILE ================================ */

View File

@ -31,8 +31,8 @@
with the QOF system, as a QOF Object Class. This allows
the QOF Query routines to be used to search over collections
of GObjects.
XXX Only GObject properties are searchable, data and other
XXX Only GObject properties are searchable, data and other
hanging off the GObject is not. Fix this. This needs fixing.
@{ */
@ -55,7 +55,7 @@ void qof_gobject_shutdown (void);
* this GObject searchable using the QOF subsystem.
*
* The QofType can be any string you desire, although typically
* you might want to set it to G_OBJECT_CLASS_NAME() of the
* you might want to set it to G_OBJECT_CLASS_NAME() of the
* object class. Note that this type will become the name of
* the "table" that is searched by SQL queries:
* e.g. in order to be able to say "SELECT * FROM MyStuff;"
@ -67,7 +67,7 @@ void qof_gobject_register (QofType type, GObjectClass *obclass);
/** Register an instance of a GObject with the QOF subsystem.
*
* The QofType can be any string you desire, although typically
* you might want to set it to G_OBJECT_CLASS_NAME() of the
* you might want to set it to G_OBJECT_CLASS_NAME() of the
* object class. Note that this type will become the name of
* the "table" that is searched by SQL queries:
* e.g. in order to be able to say "SELECT * FROM MyStuff;"

View File

@ -28,7 +28,7 @@
@{ */
#ifndef QOF_ID_P_H
#define QOF_ID_P_H
#define QOF_ID_P_H
#include "qofid.h"

View File

@ -35,11 +35,11 @@ static gboolean qof_alt_dirty_mode = FALSE;
struct QofCollection_s
{
QofIdType e_type;
gboolean is_dirty;
GHashTable * hash_of_entities;
gpointer data; /* place where object class can hang arbitrary data */
QofIdType e_type;
gboolean is_dirty;
GHashTable * hash_of_entities;
gpointer data; /* place where object class can hang arbitrary data */
};
/* =============================================================== */
@ -47,13 +47,13 @@ struct QofCollection_s
gboolean
qof_get_alt_dirty_mode (void)
{
return qof_alt_dirty_mode;
return qof_alt_dirty_mode;
}
void
qof_set_alt_dirty_mode (gboolean enabled)
{
qof_alt_dirty_mode = enabled;
qof_alt_dirty_mode = enabled;
}
/* =============================================================== */
@ -61,58 +61,58 @@ qof_set_alt_dirty_mode (gboolean enabled)
static guint
id_hash (gconstpointer key)
{
const GUID *guid = key;
const GUID *guid = key;
if (key == NULL)
return 0;
if (key == NULL)
return 0;
/* Compiler should optimize this all away! */
if (sizeof(guint) <= 16)
return *((guint *) guid->data);
else
{
guint hash = 0;
unsigned int i, j;
for (i = 0, j = 0; i < sizeof(guint); i++, j++)
/* Compiler should optimize this all away! */
if (sizeof(guint) <= 16)
return *((guint *) guid->data);
else
{
if (j == 16)
j = 0;
guint hash = 0;
unsigned int i, j;
hash <<= 4;
hash |= guid->data[j];
for (i = 0, j = 0; i < sizeof(guint); i++, j++)
{
if (j == 16)
j = 0;
hash <<= 4;
hash |= guid->data[j];
}
return hash;
}
return hash;
}
}
static gboolean
id_compare(gconstpointer key_1, gconstpointer key_2)
{
return guid_equal (key_1, key_2);
return guid_equal (key_1, key_2);
}
QofCollection *
qof_collection_new (QofIdType type)
{
QofCollection *col;
col = g_new0(QofCollection, 1);
col->e_type = CACHE_INSERT (type);
col->hash_of_entities = g_hash_table_new (id_hash, id_compare);
col->data = NULL;
return col;
QofCollection *col;
col = g_new0(QofCollection, 1);
col->e_type = CACHE_INSERT (type);
col->hash_of_entities = g_hash_table_new (id_hash, id_compare);
col->data = NULL;
return col;
}
void
qof_collection_destroy (QofCollection *col)
{
CACHE_REMOVE (col->e_type);
g_hash_table_destroy(col->hash_of_entities);
col->e_type = NULL;
col->hash_of_entities = NULL;
col->data = NULL; /** XXX there should be a destroy notifier for this */
g_free (col);
CACHE_REMOVE (col->e_type);
g_hash_table_destroy(col->hash_of_entities);
col->e_type = NULL;
col->hash_of_entities = NULL;
col->data = NULL; /** XXX there should be a destroy notifier for this */
g_free (col);
}
/* =============================================================== */
@ -121,7 +121,7 @@ qof_collection_destroy (QofCollection *col)
QofIdType
qof_collection_get_type (const QofCollection *col)
{
return col->e_type;
return col->e_type;
}
/* =============================================================== */
@ -129,234 +129,278 @@ qof_collection_get_type (const QofCollection *col)
void
qof_collection_remove_entity (QofInstance *ent)
{
QofCollection *col;
const GUID *guid;
QofCollection *col;
const GUID *guid;
if (!ent) return;
col = qof_instance_get_collection(ent);
if (!col) return;
guid = qof_instance_get_guid(ent);
g_hash_table_remove (col->hash_of_entities, guid);
if (!qof_alt_dirty_mode)
qof_collection_mark_dirty(col);
qof_instance_set_collection(ent, NULL);
if (!ent) return;
col = qof_instance_get_collection(ent);
if (!col) return;
guid = qof_instance_get_guid(ent);
g_hash_table_remove (col->hash_of_entities, guid);
if (!qof_alt_dirty_mode)
qof_collection_mark_dirty(col);
qof_instance_set_collection(ent, NULL);
}
void
qof_collection_insert_entity (QofCollection *col, QofInstance *ent)
{
const GUID *guid;
const GUID *guid;
if (!col || !ent) return;
guid = qof_instance_get_guid(ent);
if (guid_equal(guid, guid_null())) return;
g_return_if_fail (col->e_type == ent->e_type);
qof_collection_remove_entity (ent);
g_hash_table_insert (col->hash_of_entities, (gpointer)guid, ent);
if (!qof_alt_dirty_mode)
qof_collection_mark_dirty(col);
qof_instance_set_collection(ent, col);
if (!col || !ent) return;
guid = qof_instance_get_guid(ent);
if (guid_equal(guid, guid_null())) return;
g_return_if_fail (col->e_type == ent->e_type);
qof_collection_remove_entity (ent);
g_hash_table_insert (col->hash_of_entities, (gpointer)guid, ent);
if (!qof_alt_dirty_mode)
qof_collection_mark_dirty(col);
qof_instance_set_collection(ent, col);
}
gboolean
qof_collection_add_entity (QofCollection *coll, QofInstance *ent)
{
QofInstance *e;
const GUID *guid;
QofInstance *e;
const GUID *guid;
e = NULL;
if (!coll || !ent) { return FALSE; }
guid = qof_instance_get_guid(ent);
if (guid_equal(guid, guid_null())) { return FALSE; }
g_return_val_if_fail (coll->e_type == ent->e_type, FALSE);
e = qof_collection_lookup_entity(coll, guid);
if ( e != NULL ) { return FALSE; }
g_hash_table_insert (coll->hash_of_entities, (gpointer)guid, ent);
if (!qof_alt_dirty_mode)
qof_collection_mark_dirty(coll);
return TRUE;
e = NULL;
if (!coll || !ent)
{
return FALSE;
}
guid = qof_instance_get_guid(ent);
if (guid_equal(guid, guid_null()))
{
return FALSE;
}
g_return_val_if_fail (coll->e_type == ent->e_type, FALSE);
e = qof_collection_lookup_entity(coll, guid);
if ( e != NULL )
{
return FALSE;
}
g_hash_table_insert (coll->hash_of_entities, (gpointer)guid, ent);
if (!qof_alt_dirty_mode)
qof_collection_mark_dirty(coll);
return TRUE;
}
static void
collection_merge_cb (QofInstance *ent, gpointer data)
{
QofCollection *target;
QofCollection *target;
target = (QofCollection*)data;
qof_collection_add_entity(target, ent);
target = (QofCollection*)data;
qof_collection_add_entity(target, ent);
}
gboolean
qof_collection_merge (QofCollection *target, QofCollection *merge)
{
if(!target || !merge) { return FALSE; }
g_return_val_if_fail (target->e_type == merge->e_type, FALSE);
qof_collection_foreach(merge, collection_merge_cb, target);
return TRUE;
if (!target || !merge)
{
return FALSE;
}
g_return_val_if_fail (target->e_type == merge->e_type, FALSE);
qof_collection_foreach(merge, collection_merge_cb, target);
return TRUE;
}
static void
collection_compare_cb (QofInstance *ent, gpointer user_data)
{
QofCollection *target;
QofInstance *e;
const GUID *guid;
gint value;
QofCollection *target;
QofInstance *e;
const GUID *guid;
gint value;
e = NULL;
target = (QofCollection*)user_data;
if (!target || !ent) { return; }
value = *(gint*)qof_collection_get_data(target);
if (value != 0) { return; }
guid = qof_instance_get_guid(ent);
if (guid_equal(guid, guid_null()))
{
value = -1;
qof_collection_set_data(target, &value);
return;
}
g_return_if_fail (target->e_type == ent->e_type);
e = qof_collection_lookup_entity(target, guid);
if ( e == NULL )
{
value = 1;
qof_collection_set_data(target, &value);
return;
}
value = 0;
qof_collection_set_data(target, &value);
e = NULL;
target = (QofCollection*)user_data;
if (!target || !ent)
{
return;
}
value = *(gint*)qof_collection_get_data(target);
if (value != 0)
{
return;
}
guid = qof_instance_get_guid(ent);
if (guid_equal(guid, guid_null()))
{
value = -1;
qof_collection_set_data(target, &value);
return;
}
g_return_if_fail (target->e_type == ent->e_type);
e = qof_collection_lookup_entity(target, guid);
if ( e == NULL )
{
value = 1;
qof_collection_set_data(target, &value);
return;
}
value = 0;
qof_collection_set_data(target, &value);
}
gint
qof_collection_compare (QofCollection *target, QofCollection *merge)
{
gint value;
gint value;
value = 0;
if (!target && !merge) { return 0; }
if (target == merge) { return 0; }
if (!target && merge) { return -1; }
if (target && !merge) { return 1; }
if(target->e_type != merge->e_type) { return -1; }
qof_collection_set_data(target, &value);
qof_collection_foreach(merge, collection_compare_cb, target);
value = *(gint*)qof_collection_get_data(target);
if(value == 0) {
qof_collection_set_data(merge, &value);
qof_collection_foreach(target, collection_compare_cb, merge);
value = *(gint*)qof_collection_get_data(merge);
}
return value;
value = 0;
if (!target && !merge)
{
return 0;
}
if (target == merge)
{
return 0;
}
if (!target && merge)
{
return -1;
}
if (target && !merge)
{
return 1;
}
if (target->e_type != merge->e_type)
{
return -1;
}
qof_collection_set_data(target, &value);
qof_collection_foreach(merge, collection_compare_cb, target);
value = *(gint*)qof_collection_get_data(target);
if (value == 0)
{
qof_collection_set_data(merge, &value);
qof_collection_foreach(target, collection_compare_cb, merge);
value = *(gint*)qof_collection_get_data(merge);
}
return value;
}
QofInstance *
qof_collection_lookup_entity (const QofCollection *col, const GUID * guid)
{
QofInstance *ent;
g_return_val_if_fail (col, NULL);
if (guid == NULL) return NULL;
ent = g_hash_table_lookup (col->hash_of_entities, guid);
return ent;
QofInstance *ent;
g_return_val_if_fail (col, NULL);
if (guid == NULL) return NULL;
ent = g_hash_table_lookup (col->hash_of_entities, guid);
return ent;
}
QofCollection *
qof_collection_from_glist (QofIdType type, const GList *glist)
{
QofCollection *coll;
QofInstance *ent;
const GList *list;
QofCollection *coll;
QofInstance *ent;
const GList *list;
coll = qof_collection_new(type);
for(list = glist; list != NULL; list = list->next)
{
ent = QOF_INSTANCE(list->data);
if(FALSE == qof_collection_add_entity(coll, ent))
{
return NULL;
}
}
return coll;
coll = qof_collection_new(type);
for (list = glist; list != NULL; list = list->next)
{
ent = QOF_INSTANCE(list->data);
if (FALSE == qof_collection_add_entity(coll, ent))
{
return NULL;
}
}
return coll;
}
guint
qof_collection_count (const QofCollection *col)
{
guint c;
guint c;
c = g_hash_table_size(col->hash_of_entities);
return c;
c = g_hash_table_size(col->hash_of_entities);
return c;
}
/* =============================================================== */
gboolean
gboolean
qof_collection_is_dirty (const QofCollection *col)
{
return col ? col->is_dirty : FALSE;
return col ? col->is_dirty : FALSE;
}
void
void
qof_collection_mark_clean (QofCollection *col)
{
if (col) { col->is_dirty = FALSE; }
if (col)
{
col->is_dirty = FALSE;
}
}
void
void
qof_collection_mark_dirty (QofCollection *col)
{
if (col) { col->is_dirty = TRUE; }
if (col)
{
col->is_dirty = TRUE;
}
}
void
qof_collection_print_dirty (const QofCollection *col, gpointer dummy)
{
if (col->is_dirty)
printf("%s collection is dirty.\n", col->e_type);
qof_collection_foreach(col, (QofInstanceForeachCB)qof_instance_print_dirty, NULL);
if (col->is_dirty)
printf("%s collection is dirty.\n", col->e_type);
qof_collection_foreach(col, (QofInstanceForeachCB)qof_instance_print_dirty, NULL);
}
/* =============================================================== */
gpointer
gpointer
qof_collection_get_data (const QofCollection *col)
{
return col ? col->data : NULL;
return col ? col->data : NULL;
}
void
void
qof_collection_set_data (QofCollection *col, gpointer user_data)
{
if (col) { col->data = user_data; }
if (col)
{
col->data = user_data;
}
}
/* =============================================================== */
struct _iterate {
QofInstanceForeachCB fcn;
gpointer data;
struct _iterate
{
QofInstanceForeachCB fcn;
gpointer data;
};
static void foreach_cb (gpointer key, gpointer item, gpointer arg)
{
struct _iterate *iter = arg;
QofInstance *ent = item;
struct _iterate *iter = arg;
QofInstance *ent = item;
iter->fcn (ent, iter->data);
iter->fcn (ent, iter->data);
}
void
qof_collection_foreach (const QofCollection *col, QofInstanceForeachCB cb_func,
qof_collection_foreach (const QofCollection *col, QofInstanceForeachCB cb_func,
gpointer user_data)
{
struct _iterate iter;
struct _iterate iter;
g_return_if_fail (col);
g_return_if_fail (cb_func);
g_return_if_fail (col);
g_return_if_fail (cb_func);
iter.fcn = cb_func;
iter.data = user_data;
iter.fcn = cb_func;
iter.data = user_data;
g_hash_table_foreach (col->hash_of_entities, foreach_cb, &iter);
g_hash_table_foreach (col->hash_of_entities, foreach_cb, &iter);
}
/* =============================================================== */

View File

@ -21,33 +21,33 @@
\********************************************************************/
#ifndef QOF_ID_H
#define QOF_ID_H
#define QOF_ID_H
/** @addtogroup Entity
/** @addtogroup Entity
@{ */
/** @addtogroup Entities
This file defines an API that adds types to the GUID's.
GUID's with types can be used to identify and reference
typed entities.
GUID's with types can be used to identify and reference
typed entities.
The idea here is that a GUID can be used to uniquely identify
some thing. By adding a type, one can then talk about the
some thing. By adding a type, one can then talk about the
type of thing identified. By adding a collection, one can
then work with a handle to a collection of things of a given
type, each uniquely identified by a given ID. QOF Entities
can be used independently of any other part of the system.
In particular, Entities can be useful even if one is not using
the Query ond Object parts of the QOF system.
Identifiers are globally-unique and permanent, i.e., once
an entity has been assigned an identifier, it retains that same
identifier for its lifetime.
Identifiers can be encoded as hex strings.
GUID Identifiers are 'typed' with strings. The native ids used
Identifiers can be encoded as hex strings.
GUID Identifiers are 'typed' with strings. The native ids used
by QOF are defined below.
-# An id with type QOF_ID_NONE does not
-# An id with type QOF_ID_NONE does not
refer to any entity.
-# An id with type QOF_ID_NULL does not refer
to any entity, and will never refer to any entity.
@ -57,7 +57,7 @@
Also, creating a new entity from a data source involves creating
a temporary GUID and then setting the value from the data source.
If an id does refer to an entity, the type of the entity will match
the type of the identifier.
the type of the identifier.
If you have a type name, and you want to have a way of finding
a collection that is associated with that type, then you must use
@ -68,8 +68,8 @@
@{ */
/** @file qofid.h
@brief QOF entity type identification system
@author Copyright (C) 2000 Dave Peticolas <peticola@cs.ucdavis.edu>
@brief QOF entity type identification system
@author Copyright (C) 2000 Dave Peticolas <peticola@cs.ucdavis.edu>
@author Copyright (C) 2003 Linas Vepstas <linas@linas.org>
*/
@ -126,7 +126,7 @@ print error message if its bad */
}))
/** QofCollection declaration
/** QofCollection declaration
@param e_type QofIdType
@param is_dirty gboolean
@ -152,7 +152,7 @@ gboolean qof_get_alt_dirty_mode (void);
* collection (and therefore the book) is never changed. */
void qof_set_alt_dirty_mode (gboolean enabled);
/** @name Collections of Entities
/** @name Collections of Entities
@{ */
/** create a new collection of entities of type */
@ -168,16 +168,17 @@ void qof_collection_destroy (QofCollection *col);
QofIdType qof_collection_get_type (const QofCollection *);
/** Find the entity going only from its guid */
/*@ dependent @*/ QofInstance * qof_collection_lookup_entity (const QofCollection *, const GUID *);
/*@ dependent @*/
QofInstance * qof_collection_lookup_entity (const QofCollection *, const GUID *);
/** Callback type for qof_collection_foreach */
typedef void (*QofInstanceForeachCB) (QofInstance *, gpointer user_data);
/** Call the callback for each entity in the collection. */
void qof_collection_foreach (const QofCollection *, QofInstanceForeachCB,
void qof_collection_foreach (const QofCollection *, QofInstanceForeachCB,
gpointer user_data);
/** Store and retreive arbitrary object-defined data
/** Store and retreive arbitrary object-defined data
*
* XXX We need to add a callback for when the collection is being
* destroyed, so that the user has a chance to clean up anything
@ -206,7 +207,7 @@ of one object type as references of another entity.
Entities can be
freely added and merged across these secondary collections, they
will not be removed from the original collection as they would
by using ::qof_instance_insert_entity or ::qof_instance_remove_entity.
by using ::qof_instance_insert_entity or ::qof_instance_remove_entity.
*/
gboolean
@ -243,7 +244,7 @@ qof_collection_compare (QofCollection *target, QofCollection *merge);
/** \brief Create a secondary collection from a GList
@param type The QofIdType of the QofCollection \b and of
@param type The QofIdType of the QofCollection \b and of
\b all entities in the GList.
@param glist GList of entities of the same QofIdType.

View File

@ -22,7 +22,7 @@
/*
* Object instance holds many common fields that most
* gnucash objects use.
*
*
* Copyright (C) 2003 Linas Vepstas <linas@linas.org>
* Copyright (c) 2007 David Hampton <hampton@employees.org>
*/
@ -40,8 +40,8 @@ void qof_instance_set_collection (gconstpointer ptr, QofCollection *col);
void qof_instance_set_slots (QofInstance *, KvpFrame *);
/* Set the last_update time. Reserved for use by the SQL backend;
* used for comparing version in local memory to that in remote
* server.
* used for comparing version in local memory to that in remote
* server.
*/
void qof_instance_set_last_update (QofInstance *inst, Timespec ts);

View File

@ -40,11 +40,13 @@ static QofLogModule log_module = QOF_MOD_ENGINE;
/* ========================================================== */
enum {
enum
{
LAST_SIGNAL
};
enum {
enum
{
PROP_0,
PROP_TYPE,
PROP_GUID,
@ -72,14 +74,14 @@ typedef struct QofInstancePrivate
QofBook * book;
/* kvp_data is a key-value pair database for storing arbirtary
* information associated with this instance.
* See src/engine/kvp_doc.txt for a list and description of the
* information associated with this instance.
* See src/engine/kvp_doc.txt for a list and description of the
* important keys. */
// KvpFrame *kvp_data;
/* Timestamp used to track the last modification to this
/* Timestamp used to track the last modification to this
* instance. Typically used to compare two versions of the
* same object, to see which is newer. When used with the
* same object, to see which is newer. When used with the
* SQL backend, this field is reserved for SQL use, to compare
* the version in local memory to the remote, server version.
*/
@ -134,214 +136,217 @@ static void qof_instance_class_init(QofInstanceClass *klass)
g_type_class_add_private(klass, sizeof(QofInstancePrivate));
g_object_class_install_property
(object_class,
PROP_GUID,
g_param_spec_boxed ("guid",
"Object GUID",
"The object Globally Unique ID.",
GNC_TYPE_GUID,
G_PARAM_READWRITE));
(object_class,
PROP_GUID,
g_param_spec_boxed ("guid",
"Object GUID",
"The object Globally Unique ID.",
GNC_TYPE_GUID,
G_PARAM_READWRITE));
g_object_class_install_property
(object_class,
PROP_COLLECTION,
g_param_spec_pointer ("collection",
"Object Collection",
"A collection of like objects of which this "
"particular object is amember. E.g.. A "
"collection of accounts, or a collection of "
"splits.",
G_PARAM_READWRITE));
(object_class,
PROP_COLLECTION,
g_param_spec_pointer ("collection",
"Object Collection",
"A collection of like objects of which this "
"particular object is amember. E.g.. A "
"collection of accounts, or a collection of "
"splits.",
G_PARAM_READWRITE));
g_object_class_install_property
(object_class,
PROP_BOOK,
g_param_spec_object ("book",
"Object Book",
"The book that contains this object.",
QOF_TYPE_BOOK,
G_PARAM_READWRITE));
g_object_class_install_property
(object_class,
PROP_KVP_DATA,
g_param_spec_pointer ("kvp-data",
"Object KVP Data",
"A pointer to the key-value data associated "
"with this object.",
G_PARAM_READWRITE));
(object_class,
PROP_BOOK,
g_param_spec_object ("book",
"Object Book",
"The book that contains this object.",
QOF_TYPE_BOOK,
G_PARAM_READWRITE));
g_object_class_install_property
(object_class,
PROP_LAST_UPDATE,
g_param_spec_pointer ("last-update",
"Object Last Update",
"A pointer to the last time this object was "
"updated. This value is present for use by "
"backends and shouldnot be written by other "
"code.",
G_PARAM_READWRITE));
(object_class,
PROP_KVP_DATA,
g_param_spec_pointer ("kvp-data",
"Object KVP Data",
"A pointer to the key-value data associated "
"with this object.",
G_PARAM_READWRITE));
g_object_class_install_property
(object_class,
PROP_EDITLEVEL,
g_param_spec_int ("editlevel",
"Object Edit Level",
"The object edit level.",
0, G_MAXINT32, 0,
(object_class,
PROP_LAST_UPDATE,
g_param_spec_pointer ("last-update",
"Object Last Update",
"A pointer to the last time this object was "
"updated. This value is present for use by "
"backends and shouldnot be written by other "
"code.",
G_PARAM_READWRITE));
g_object_class_install_property
(object_class,
PROP_EDITLEVEL,
g_param_spec_int ("editlevel",
"Object Edit Level",
"The object edit level.",
0, G_MAXINT32, 0,
G_PARAM_READABLE));
g_object_class_install_property
(object_class,
PROP_DESTROYING,
g_param_spec_boolean ("destroying",
"Object Destroying",
"This flag is set to TRUE if the object is "
"about to be destroyed.",
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property
(object_class,
PROP_DIRTY,
g_param_spec_boolean ("dirty",
"Object Dirty",
"This flag is set to TRUE if the object has "
"unsaved changes.",
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property
(object_class,
PROP_INFANT,
g_param_spec_boolean ("infant",
"Object Infant",
"This flag is set to TRUE if the object has "
"never been added to a book. This implies "
"that its destruction does not affect the "
"state of the book, and therefore the saved "
"state of the data file.",
FALSE,
G_PARAM_READABLE));
g_object_class_install_property
(object_class,
PROP_DESTROYING,
g_param_spec_boolean ("destroying",
"Object Destroying",
"This flag is set to TRUE if the object is "
"about to be destroyed.",
FALSE,
G_PARAM_READWRITE));
(object_class,
PROP_VERSION,
g_param_spec_int ("version",
"Version",
"The version number of the current instance state.",
0,
G_MAXINT32,
0,
G_PARAM_READWRITE));
g_object_class_install_property
(object_class,
PROP_DIRTY,
g_param_spec_boolean ("dirty",
"Object Dirty",
"This flag is set to TRUE if the object has "
"unsaved changes.",
FALSE,
G_PARAM_READWRITE));
(object_class,
PROP_VERSION_CHECK,
g_param_spec_uint ("version-check",
"Version Check",
"The version check number of the current instance state.",
0,
G_MAXUINT32,
0,
G_PARAM_READWRITE));
g_object_class_install_property
(object_class,
PROP_INFANT,
g_param_spec_boolean ("infant",
"Object Infant",
"This flag is set to TRUE if the object has "
"never been added to a book. This implies "
"that its destruction does not affect the "
"state of the book, and therefore the saved "
"state of the data file.",
FALSE,
G_PARAM_READABLE));
g_object_class_install_property
(object_class,
PROP_VERSION,
g_param_spec_int ("version",
"Version",
"The version number of the current instance state.",
0,
G_MAXINT32,
0,
G_PARAM_READWRITE));
g_object_class_install_property
(object_class,
PROP_VERSION_CHECK,
g_param_spec_uint ("version-check",
"Version Check",
"The version check number of the current instance state.",
0,
G_MAXUINT32,
0,
G_PARAM_READWRITE));
g_object_class_install_property
(object_class,
PROP_EDITLEVEL,
g_param_spec_uint ("idata",
"Object IData",
"Per instance backend private data.",
0, G_MAXUINT32, 0,
G_PARAM_READWRITE));
(object_class,
PROP_EDITLEVEL,
g_param_spec_uint ("idata",
"Object IData",
"Per instance backend private data.",
0, G_MAXUINT32, 0,
G_PARAM_READWRITE));
}
static void
qof_instance_init (QofInstance *inst)
{
QofInstancePrivate *priv;
QofInstancePrivate *priv;
priv = GET_PRIVATE(inst);
priv->book = NULL;
inst->kvp_data = kvp_frame_new();
priv->last_update.tv_sec = 0;
priv->last_update.tv_nsec = -1;
priv->editlevel = 0;
priv->do_free = FALSE;
priv->dirty = FALSE;
priv->infant = TRUE;
priv = GET_PRIVATE(inst);
priv->book = NULL;
inst->kvp_data = kvp_frame_new();
priv->last_update.tv_sec = 0;
priv->last_update.tv_nsec = -1;
priv->editlevel = 0;
priv->do_free = FALSE;
priv->dirty = FALSE;
priv->infant = TRUE;
}
void
qof_instance_init_data (QofInstance *inst, QofIdType type, QofBook *book)
{
QofInstancePrivate *priv;
QofCollection *col;
QofIdType col_type;
QofInstancePrivate *priv;
QofCollection *col;
QofIdType col_type;
g_return_if_fail(QOF_IS_INSTANCE(inst));
priv = GET_PRIVATE(inst);
g_return_if_fail(!priv->book);
g_return_if_fail(QOF_IS_INSTANCE(inst));
priv = GET_PRIVATE(inst);
g_return_if_fail(!priv->book);
priv->book = book;
col = qof_book_get_collection (book, type);
g_return_if_fail(col != NULL);
/* XXX We passed redundant info to this routine ... but I think that's
* OK, it might eliminate programming errors. */
priv->book = book;
col = qof_book_get_collection (book, type);
g_return_if_fail(col != NULL);
col_type = qof_collection_get_type(col);
if (safe_strcmp(col_type, type)) {
PERR ("attempt to insert \"%s\" into \"%s\"", type, col_type);
return;
}
priv = GET_PRIVATE(inst);
inst->e_type = CACHE_INSERT (type);
/* XXX We passed redundant info to this routine ... but I think that's
* OK, it might eliminate programming errors. */
do {
guid_new(&priv->guid);
col_type = qof_collection_get_type(col);
if (safe_strcmp(col_type, type))
{
PERR ("attempt to insert \"%s\" into \"%s\"", type, col_type);
return;
}
priv = GET_PRIVATE(inst);
inst->e_type = CACHE_INSERT (type);
if (NULL == qof_collection_lookup_entity (col, &priv->guid))
do
{
guid_new(&priv->guid);
if (NULL == qof_collection_lookup_entity (col, &priv->guid))
break;
PWARN("duplicate id created, trying again");
} while(1);
priv->collection = col;
PWARN("duplicate id created, trying again");
}
while (1);
qof_collection_insert_entity (col, inst);
priv->collection = col;
qof_collection_insert_entity (col, inst);
}
static void
qof_instance_dispose (GObject *instp)
{
QofInstancePrivate *priv;
QofInstance* inst = QOF_INSTANCE(instp);
QofInstancePrivate *priv;
QofInstance* inst = QOF_INSTANCE(instp);
priv = GET_PRIVATE(instp);
if (!priv->collection)
return;
qof_collection_remove_entity(inst);
priv = GET_PRIVATE(instp);
if (!priv->collection)
return;
qof_collection_remove_entity(inst);
CACHE_REMOVE(inst->e_type);
inst->e_type = NULL;
CACHE_REMOVE(inst->e_type);
inst->e_type = NULL;
G_OBJECT_CLASS(qof_instance_parent_class)->dispose(instp);
G_OBJECT_CLASS(qof_instance_parent_class)->dispose(instp);
}
static void
qof_instance_finalize_real (GObject *instp)
{
QofInstancePrivate *priv;
QofInstance* inst = QOF_INSTANCE(instp);
QofInstancePrivate *priv;
QofInstance* inst = QOF_INSTANCE(instp);
kvp_frame_delete (inst->kvp_data);
inst->kvp_data = NULL;
kvp_frame_delete (inst->kvp_data);
inst->kvp_data = NULL;
priv = GET_PRIVATE(inst);
priv->editlevel = 0;
priv->do_free = FALSE;
priv->dirty = FALSE;
priv = GET_PRIVATE(inst);
priv->editlevel = 0;
priv->do_free = FALSE;
priv->dirty = FALSE;
}
static void
@ -358,46 +363,47 @@ qof_instance_get_property (GObject *object,
inst = QOF_INSTANCE(object);
priv = GET_PRIVATE(inst);
switch (prop_id) {
case PROP_GUID:
g_value_set_boxed(value, &priv->guid);
break;
case PROP_COLLECTION:
g_value_set_pointer(value, priv->collection);
break;
case PROP_BOOK:
g_value_set_object(value, priv->book);
break;
case PROP_KVP_DATA:
g_value_set_pointer(value, inst->kvp_data);
break;
case PROP_LAST_UPDATE:
g_value_set_pointer(value, &priv->last_update);
break;
case PROP_EDITLEVEL:
g_value_set_int(value, priv->editlevel);
break;
case PROP_DESTROYING:
g_value_set_boolean(value, priv->do_free);
break;
case PROP_DIRTY:
g_value_set_boolean(value, qof_instance_get_dirty(inst));
break;
case PROP_INFANT:
g_value_set_boolean(value, priv->infant);
break;
case PROP_VERSION:
g_value_set_int(value, priv->version);
break;
case PROP_VERSION_CHECK:
g_value_set_uint(value, priv->version_check);
break;
case PROP_IDATA:
g_value_set_uint(value, priv->idata);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
switch (prop_id)
{
case PROP_GUID:
g_value_set_boxed(value, &priv->guid);
break;
case PROP_COLLECTION:
g_value_set_pointer(value, priv->collection);
break;
case PROP_BOOK:
g_value_set_object(value, priv->book);
break;
case PROP_KVP_DATA:
g_value_set_pointer(value, inst->kvp_data);
break;
case PROP_LAST_UPDATE:
g_value_set_pointer(value, &priv->last_update);
break;
case PROP_EDITLEVEL:
g_value_set_int(value, priv->editlevel);
break;
case PROP_DESTROYING:
g_value_set_boolean(value, priv->do_free);
break;
case PROP_DIRTY:
g_value_set_boolean(value, qof_instance_get_dirty(inst));
break;
case PROP_INFANT:
g_value_set_boolean(value, priv->infant);
break;
case PROP_VERSION:
g_value_set_int(value, priv->version);
break;
case PROP_VERSION_CHECK:
g_value_set_uint(value, priv->version_check);
break;
case PROP_IDATA:
g_value_set_uint(value, priv->idata);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
@ -416,41 +422,42 @@ qof_instance_set_property (GObject *object,
inst = QOF_INSTANCE(object);
priv = GET_PRIVATE(inst);
switch (prop_id) {
case PROP_GUID:
qof_instance_set_guid(inst, g_value_get_boxed(value));
break;
case PROP_COLLECTION:
qof_instance_set_collection(inst, g_value_get_pointer(value));
break;
case PROP_BOOK:
qof_instance_set_book(inst, g_value_get_object(value));
break;
case PROP_KVP_DATA:
qof_instance_set_slots(inst, g_value_get_pointer(value));
break;
case PROP_LAST_UPDATE:
ts = g_value_get_pointer(value);
qof_instance_set_last_update(inst, *ts);
break;
case PROP_DESTROYING:
qof_instance_set_destroying(inst, g_value_get_boolean(value));
break;
case PROP_DIRTY:
qof_instance_set_dirty(inst);
break;
case PROP_VERSION:
qof_instance_set_version(inst, g_value_get_int(value));
break;
case PROP_VERSION_CHECK:
qof_instance_set_version_check(inst, g_value_get_uint(value));
break;
case PROP_IDATA:
qof_instance_set_idata(inst, g_value_get_uint(value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
switch (prop_id)
{
case PROP_GUID:
qof_instance_set_guid(inst, g_value_get_boxed(value));
break;
case PROP_COLLECTION:
qof_instance_set_collection(inst, g_value_get_pointer(value));
break;
case PROP_BOOK:
qof_instance_set_book(inst, g_value_get_object(value));
break;
case PROP_KVP_DATA:
qof_instance_set_slots(inst, g_value_get_pointer(value));
break;
case PROP_LAST_UPDATE:
ts = g_value_get_pointer(value);
qof_instance_set_last_update(inst, *ts);
break;
case PROP_DESTROYING:
qof_instance_set_destroying(inst, g_value_get_boolean(value));
break;
case PROP_DIRTY:
qof_instance_set_dirty(inst);
break;
case PROP_VERSION:
qof_instance_set_version(inst, g_value_get_int(value));
break;
case PROP_VERSION_CHECK:
qof_instance_set_version_check(inst, g_value_get_uint(value));
break;
case PROP_IDATA:
qof_instance_set_idata(inst, g_value_get_uint(value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
@ -517,7 +524,7 @@ qof_instance_guid_compare(gconstpointer ptr1, gconstpointer ptr2)
QofCollection *
qof_instance_get_collection (gconstpointer ptr)
{
g_return_val_if_fail(QOF_IS_INSTANCE(ptr), NULL);
return GET_PRIVATE(ptr)->collection;
}
@ -547,24 +554,24 @@ qof_instance_set_book (gconstpointer inst, QofBook *book)
void
qof_instance_copy_book (gpointer ptr1, gconstpointer ptr2)
{
g_return_if_fail(QOF_IS_INSTANCE(ptr1));
g_return_if_fail(QOF_IS_INSTANCE(ptr2));
g_return_if_fail(QOF_IS_INSTANCE(ptr1));
g_return_if_fail(QOF_IS_INSTANCE(ptr2));
GET_PRIVATE(ptr1)->book = GET_PRIVATE(ptr2)->book;
GET_PRIVATE(ptr1)->book = GET_PRIVATE(ptr2)->book;
}
gboolean
qof_instance_books_equal (gconstpointer ptr1, gconstpointer ptr2)
{
const QofInstancePrivate *priv1, *priv2;
const QofInstancePrivate *priv1, *priv2;
g_return_val_if_fail(QOF_IS_INSTANCE(ptr1), FALSE);
g_return_val_if_fail(QOF_IS_INSTANCE(ptr2), FALSE);
g_return_val_if_fail(QOF_IS_INSTANCE(ptr1), FALSE);
g_return_val_if_fail(QOF_IS_INSTANCE(ptr2), FALSE);
priv1 = GET_PRIVATE(ptr1);
priv2 = GET_PRIVATE(ptr2);
priv1 = GET_PRIVATE(ptr1);
priv2 = GET_PRIVATE(ptr2);
return (priv1->book == priv2->book);
return (priv1->book == priv2->book);
}
KvpFrame*
@ -582,7 +589,8 @@ qof_instance_set_slots (QofInstance *inst, KvpFrame *frm)
if (!inst) return;
priv = GET_PRIVATE(inst);
if (inst->kvp_data && (inst->kvp_data != frm)) {
if (inst->kvp_data && (inst->kvp_data != frm))
{
kvp_frame_delete(inst->kvp_data);
}
@ -593,8 +601,9 @@ qof_instance_set_slots (QofInstance *inst, KvpFrame *frm)
Timespec
qof_instance_get_last_update (const QofInstance *inst)
{
if (!inst) {
Timespec ts = {0,-1};
if (!inst)
{
Timespec ts = {0, -1};
return ts;
}
return GET_PRIVATE(inst)->last_update;
@ -642,19 +651,19 @@ qof_instance_check_edit(const QofInstance *inst)
int
qof_instance_version_cmp (const QofInstance *left, const QofInstance *right)
{
QofInstancePrivate *lpriv, *rpriv;
QofInstancePrivate *lpriv, *rpriv;
if (!left && !right) return 0;
if (!left) return -1;
if (!right) return +1;
if (!left && !right) return 0;
if (!left) return -1;
if (!right) return +1;
lpriv = GET_PRIVATE(left);
rpriv = GET_PRIVATE(right);
if (lpriv->last_update.tv_sec < rpriv->last_update.tv_sec) return -1;
if (lpriv->last_update.tv_sec > rpriv->last_update.tv_sec) return +1;
if (lpriv->last_update.tv_nsec < rpriv->last_update.tv_nsec) return -1;
if (lpriv->last_update.tv_nsec > rpriv->last_update.tv_nsec) return +1;
return 0;
lpriv = GET_PRIVATE(left);
rpriv = GET_PRIVATE(right);
if (lpriv->last_update.tv_sec < rpriv->last_update.tv_sec) return -1;
if (lpriv->last_update.tv_sec > rpriv->last_update.tv_sec) return +1;
if (lpriv->last_update.tv_nsec < rpriv->last_update.tv_nsec) return -1;
if (lpriv->last_update.tv_nsec > rpriv->last_update.tv_nsec) return +1;
return 0;
}
gboolean
@ -688,8 +697,8 @@ qof_instance_set_dirty_flag (gconstpointer inst, gboolean flag)
void
qof_instance_mark_clean (QofInstance *inst)
{
if(!inst) return;
GET_PRIVATE(inst)->dirty = FALSE;
if (!inst) return;
GET_PRIVATE(inst)->dirty = FALSE;
}
void
@ -698,7 +707,8 @@ qof_instance_print_dirty (const QofInstance *inst, gpointer dummy)
QofInstancePrivate *priv;
priv = GET_PRIVATE(inst);
if (priv->dirty) {
if (priv->dirty)
{
printf("%s instance %s is dirty.\n", inst->e_type,
guid_to_string(&priv->guid));
}
@ -707,32 +717,39 @@ qof_instance_print_dirty (const QofInstance *inst, gpointer dummy)
gboolean
qof_instance_get_dirty (QofInstance *inst)
{
QofInstancePrivate *priv;
QofCollection *coll;
QofInstancePrivate *priv;
QofCollection *coll;
if (!inst) { return FALSE; }
if (!inst)
{
return FALSE;
}
priv = GET_PRIVATE(inst);
if (qof_get_alt_dirty_mode())
return priv->dirty;
coll = priv->collection;
if(qof_collection_is_dirty(coll)) { return priv->dirty; }
priv->dirty = FALSE;
return FALSE;
priv = GET_PRIVATE(inst);
if (qof_get_alt_dirty_mode())
return priv->dirty;
coll = priv->collection;
if (qof_collection_is_dirty(coll))
{
return priv->dirty;
}
priv->dirty = FALSE;
return FALSE;
}
void
qof_instance_set_dirty(QofInstance* inst)
{
QofInstancePrivate *priv;
QofCollection *coll;
QofInstancePrivate *priv;
QofCollection *coll;
priv = GET_PRIVATE(inst);
priv->dirty = TRUE;
if (!qof_get_alt_dirty_mode()) {
coll = priv->collection;
qof_collection_mark_dirty(coll);
}
priv = GET_PRIVATE(inst);
priv->dirty = TRUE;
if (!qof_get_alt_dirty_mode())
{
coll = priv->collection;
qof_collection_mark_dirty(coll);
}
}
gboolean
@ -742,7 +759,7 @@ qof_instance_get_infant(const QofInstance *inst)
return GET_PRIVATE(inst)->infant;
}
gint32
gint32
qof_instance_get_version (gconstpointer inst)
{
g_return_val_if_fail(QOF_IS_INSTANCE(inst), 0);
@ -757,7 +774,7 @@ qof_instance_compare_version (gconstpointer inst1, gconstpointer inst2)
return GET_PRIVATE(inst2)->version - GET_PRIVATE(inst1)->version;
}
void
void
qof_instance_set_version (gpointer inst, gint32 vers)
{
g_return_if_fail(QOF_IS_INSTANCE(inst));
@ -808,17 +825,26 @@ qof_instance_copy_version_check (gpointer to, gconstpointer from)
guint32 qof_instance_get_idata (gconstpointer inst)
{
if(!inst) { return 0; }
g_return_val_if_fail(QOF_IS_INSTANCE(inst), 0);
return GET_PRIVATE(inst)->idata;
if (!inst)
{
return 0;
}
g_return_val_if_fail(QOF_IS_INSTANCE(inst), 0);
return GET_PRIVATE(inst)->idata;
}
void qof_instance_set_idata(gpointer inst, guint32 idata)
{
if(!inst) { return; }
if(idata < 0) { return; }
g_return_if_fail(QOF_IS_INSTANCE(inst));
GET_PRIVATE(inst)->idata = idata;
if (!inst)
{
return;
}
if (idata < 0)
{
return;
}
g_return_if_fail(QOF_IS_INSTANCE(inst));
GET_PRIVATE(inst)->idata = idata;
}
/* ========================================================== */
@ -826,59 +852,59 @@ void qof_instance_set_idata(gpointer inst, guint32 idata)
void
qof_instance_gemini (QofInstance *to, const QofInstance *from)
{
QofInstancePrivate *from_priv, *to_priv, *fb_priv, *tb_priv;
time_t now;
QofInstancePrivate *from_priv, *to_priv, *fb_priv, *tb_priv;
time_t now;
g_return_if_fail(QOF_IS_INSTANCE(to));
g_return_if_fail(QOF_IS_INSTANCE(from));
g_return_if_fail(QOF_IS_INSTANCE(to));
g_return_if_fail(QOF_IS_INSTANCE(from));
from_priv = GET_PRIVATE(from);
to_priv = GET_PRIVATE(to);
fb_priv = GET_PRIVATE(from_priv->book);
tb_priv = GET_PRIVATE(to_priv->book);
from_priv = GET_PRIVATE(from);
to_priv = GET_PRIVATE(to);
fb_priv = GET_PRIVATE(from_priv->book);
tb_priv = GET_PRIVATE(to_priv->book);
/* Books must differ for a gemini to be meaningful */
if (from_priv->book == to_priv->book)
return;
/* Books must differ for a gemini to be meaningful */
if (from_priv->book == to_priv->book)
return;
now = time(0);
now = time(0);
/* Make a note of where the copy came from */
gnc_kvp_bag_add (to->kvp_data, "gemini", now,
"inst_guid", &from_priv->guid,
"book_guid", &fb_priv->guid,
NULL);
gnc_kvp_bag_add (from->kvp_data, "gemini", now,
"inst_guid", &to_priv->guid,
"book_guid", &tb_priv->guid,
NULL);
/* Make a note of where the copy came from */
gnc_kvp_bag_add (to->kvp_data, "gemini", now,
"inst_guid", &from_priv->guid,
"book_guid", &fb_priv->guid,
NULL);
gnc_kvp_bag_add (from->kvp_data, "gemini", now,
"inst_guid", &to_priv->guid,
"book_guid", &tb_priv->guid,
NULL);
to_priv->dirty = TRUE;
to_priv->dirty = TRUE;
}
QofInstance *
qof_instance_lookup_twin (const QofInstance *src, QofBook *target_book)
{
QofCollection *col;
KvpFrame *fr;
GUID * twin_guid;
QofInstance * twin;
QofInstancePrivate *bpriv;
QofCollection *col;
KvpFrame *fr;
GUID * twin_guid;
QofInstance * twin;
QofInstancePrivate *bpriv;
if (!src || !target_book) return NULL;
ENTER (" ");
if (!src || !target_book) return NULL;
ENTER (" ");
bpriv = GET_PRIVATE(QOF_INSTANCE(target_book));
fr = gnc_kvp_bag_find_by_guid (src->kvp_data, "gemini",
"book_guid", &bpriv->guid);
bpriv = GET_PRIVATE(QOF_INSTANCE(target_book));
fr = gnc_kvp_bag_find_by_guid (src->kvp_data, "gemini",
"book_guid", &bpriv->guid);
twin_guid = kvp_frame_get_guid (fr, "inst_guid");
twin_guid = kvp_frame_get_guid (fr, "inst_guid");
col = qof_book_get_collection (target_book, src->e_type);
twin = (QofInstance *) qof_collection_lookup_entity (col, twin_guid);
col = qof_book_get_collection (target_book, src->e_type);
twin = (QofInstance *) qof_collection_lookup_entity (col, twin_guid);
LEAVE (" found twin=%p", twin);
return twin;
LEAVE (" found twin=%p", twin);
return twin;
}
/* =================================================================== */
@ -896,15 +922,15 @@ qof_begin_edit (QofInstance *inst)
priv = GET_PRIVATE(inst);
priv->editlevel++;
if (1 < priv->editlevel) return FALSE;
if (0 >= priv->editlevel)
if (0 >= priv->editlevel)
priv->editlevel = 1;
be = qof_book_get_backend(priv->book);
if (be && qof_backend_begin_exists(be))
qof_backend_run_begin(be, inst);
else
priv->dirty = TRUE;
priv->dirty = TRUE;
return TRUE;
}
@ -920,14 +946,17 @@ gboolean qof_commit_edit (QofInstance *inst)
if (0 < priv->editlevel) return FALSE;
#if 0
if ((0 == priv->editlevel) && priv->dirty) {
if ((0 == priv->editlevel) && priv->dirty)
{
be = qof_book_get_backend(priv->book);
if (be && qof_backend_commit_exists(be)) {
if (be && qof_backend_commit_exists(be))
{
qof_backend_run_commit(be, inst);
}
}
#endif
if (0 > priv->editlevel) {
if (0 > priv->editlevel)
{
PERR ("unbalanced call - resetting (was %d)", priv->editlevel);
priv->editlevel = 0;
}
@ -935,10 +964,10 @@ gboolean qof_commit_edit (QofInstance *inst)
}
gboolean
qof_commit_edit_part2(QofInstance *inst,
void (*on_error)(QofInstance *, QofBackendError),
void (*on_done)(QofInstance *),
void (*on_free)(QofInstance *))
qof_commit_edit_part2(QofInstance *inst,
void (*on_error)(QofInstance *, QofBackendError),
void (*on_done)(QofInstance *),
void (*on_free)(QofInstance *))
{
QofInstancePrivate *priv;
QofBackend * be;
@ -949,17 +978,21 @@ qof_commit_edit_part2(QofInstance *inst,
/* See if there's a backend. If there is, invoke it. */
be = qof_book_get_backend(priv->book);
if (be && qof_backend_commit_exists(be)) {
if (be && qof_backend_commit_exists(be))
{
QofBackendError errcode;
/* clear errors */
do {
do
{
errcode = qof_backend_get_error(be);
} while (ERR_BACKEND_NO_ERR != errcode);
}
while (ERR_BACKEND_NO_ERR != errcode);
qof_backend_run_commit(be, inst);
errcode = qof_backend_get_error(be);
if (ERR_BACKEND_NO_ERR != errcode) {
if (ERR_BACKEND_NO_ERR != errcode)
{
/* XXX Should perform a rollback here */
priv->do_free = FALSE;
@ -968,23 +1001,24 @@ qof_commit_edit_part2(QofInstance *inst,
if (on_error)
on_error(inst, errcode);
return FALSE;
}
}
/* XXX the backend commit code should clear dirty!! */
priv->dirty = FALSE;
}
// if (dirty && qof_get_alt_dirty_mode() &&
// if (dirty && qof_get_alt_dirty_mode() &&
// !(priv->infant && priv->do_free)) {
// qof_collection_mark_dirty(priv->collection);
// qof_book_mark_dirty(priv->book);
// }
priv->infant = FALSE;
if (priv->do_free) {
if (priv->do_free)
{
if (on_free)
on_free(inst);
return TRUE;
}
if (on_done)
on_done(inst);
return TRUE;

View File

@ -27,9 +27,9 @@
will want to use.
@{ */
/** @file qofinstance.h
/** @file qofinstance.h
* @brief Object instance holds common fields that most gnucash objects use.
*
*
* @author Copyright (C) 2003,2004 Linas Vepstas <linas@linas.org>
* @author Copyright (c) 2007 David Hampton <hampton@employees.org>
*/
@ -64,20 +64,20 @@ typedef struct _QofBook QofBook;
struct QofInstance_s
{
GObject object;
GObject object;
QofIdType e_type; /**< Entity type */
QofIdType e_type; /**< Entity type */
/* kvp_data is a key-value pair database for storing arbirtary
* information associated with this instance.
* See src/engine/kvp_doc.txt for a list and description of the
* important keys. */
KvpFrame *kvp_data;
/* kvp_data is a key-value pair database for storing arbirtary
* information associated with this instance.
* See src/engine/kvp_doc.txt for a list and description of the
* important keys. */
KvpFrame *kvp_data;
};
struct _QofInstanceClass
{
GObjectClass parent_class;
GObjectClass parent_class;
};
/** Return the GType of a QofInstance */
@ -87,7 +87,8 @@ GType qof_instance_get_type(void);
void qof_instance_init_data (QofInstance *, QofIdType, QofBook *);
/** Return the book pointer */
/*@ dependent @*/ QofBook *qof_instance_get_book (gconstpointer);
/*@ dependent @*/
QofBook *qof_instance_get_book (gconstpointer);
/** Set the book pointer */
void qof_instance_set_book (gconstpointer inst, QofBook *book);
@ -99,14 +100,17 @@ void qof_instance_copy_book (gpointer ptr1, gconstpointer ptr2);
gboolean qof_instance_books_equal (gconstpointer ptr1, gconstpointer ptr2);
/** Return the GUID of this instance */
/*@ dependent @*/ const GUID * qof_instance_get_guid (gconstpointer);
/*@ dependent @*/
const GUID * qof_instance_get_guid (gconstpointer);
/** \deprecated Use qof_instance_get_guid instead.
* Works like qof_instance_get_guid, but returns NULL on NULL */
/*@ dependent @*/ const GUID * qof_entity_get_guid (gconstpointer);
/*@ dependent @*/
const GUID * qof_entity_get_guid (gconstpointer);
/** Return the collection this instance belongs to */
/*@ dependent @*/ QofCollection* qof_instance_get_collection (gconstpointer inst);
/*@ dependent @*/
QofCollection* qof_instance_get_collection (gconstpointer inst);
/** Set the GUID of this instance */
void qof_instance_set_guid (gpointer inst, const GUID *guid);
@ -125,13 +129,14 @@ gint qof_instance_guid_compare(const gconstpointer ptr1, const gconstpointer ptr
//void qof_instance_set_e_type (QofInstance *ent, QofIdType e_type);
/** Return the pointer to the kvp_data */
/*@ dependent @*/ KvpFrame* qof_instance_get_slots (const QofInstance *);
/*@ dependent @*/
KvpFrame* qof_instance_get_slots (const QofInstance *);
/** Return the last time this instance was modified. If QofInstances
* are used with the QofObject storage backends, then the instance
* update times are reserved for use by the backend, for managing
* multi-user updates. Non-backend code should not set the update
* times.
* multi-user updates. Non-backend code should not set the update
* times.
*/
Timespec qof_instance_get_last_update (const QofInstance *inst);
@ -140,9 +145,9 @@ void qof_instance_increase_editlevel (gpointer ptr);
void qof_instance_decrease_editlevel (gpointer ptr);
void qof_instance_reset_editlevel (gpointer ptr);
/** Compare two instances, based on thier last update times.
* Returns a negative, zero or positive value, respectively,
* if 'left' is earlier, same as or later than 'right'.
/** Compare two instances, based on thier last update times.
* Returns a negative, zero or positive value, respectively,
* if 'left' is earlier, same as or later than 'right'.
* Accepts NULL pointers, NULL's are by definition earlier
* than any value.
*/
@ -250,7 +255,7 @@ void qof_instance_gemini (QofInstance *to, const QofInstance *from);
* That's what this routine does. Given some book 'book', and an
* instance 'src', it will find the sibling instance of 'src' that is
* in 'book', and return it. If not found, it returns NULL. This
* routine uses the 'gemini' kvp values to do its work.
* routine uses the 'gemini' kvp values to do its work.
*/
QofInstance * qof_instance_lookup_twin (const QofInstance *src, QofBook *book);

View File

@ -24,7 +24,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#include "config.h"
#include <glib.h>
@ -62,29 +62,33 @@ static GLogFunc previous_handler = NULL;
void
qof_log_indent(void)
{
qof_log_num_spaces += QOF_LOG_INDENT_WIDTH;
qof_log_num_spaces += QOF_LOG_INDENT_WIDTH;
}
void
qof_log_dedent(void)
{
qof_log_num_spaces
= (qof_log_num_spaces < QOF_LOG_INDENT_WIDTH)
? 0
: qof_log_num_spaces - QOF_LOG_INDENT_WIDTH;
qof_log_num_spaces
= (qof_log_num_spaces < QOF_LOG_INDENT_WIDTH)
? 0
: qof_log_num_spaces - QOF_LOG_INDENT_WIDTH;
}
void
qof_log_set_file(FILE *outfile)
{
if (!outfile) { fout = stderr; return; }
fout = outfile;
if (!outfile)
{
fout = stderr;
return;
}
fout = outfile;
}
void
void
qof_log_init(void)
{
qof_log_init_filename(NULL);
qof_log_init_filename(NULL);
}
static void
@ -93,221 +97,230 @@ log4glib_handler(const gchar *log_domain,
const gchar *message,
gpointer user_data)
{
if (G_LIKELY(!qof_log_check(log_domain, log_level)))
return;
if (G_LIKELY(!qof_log_check(log_domain, log_level)))
return;
{
char timestamp_buf[10];
time_t now;
struct tm now_tm;
gchar *level_str = qof_log_level_to_string(log_level);
now = time(NULL);
localtime_r(&now, &now_tm);
qof_strftime(timestamp_buf, 9, "%T", &now_tm);
{
char timestamp_buf[10];
time_t now;
struct tm now_tm;
gchar *level_str = qof_log_level_to_string(log_level);
now = time(NULL);
localtime_r(&now, &now_tm);
qof_strftime(timestamp_buf, 9, "%T", &now_tm);
fprintf(fout, "* %s %*s <%s> %*s%s%s",
timestamp_buf,
5, level_str,
(log_domain == NULL ? "" : log_domain),
qof_log_num_spaces, "",
message,
(g_str_has_suffix(message, "\n") ? "" : "\n"));
fflush(fout);
}
fprintf(fout, "* %s %*s <%s> %*s%s%s",
timestamp_buf,
5, level_str,
(log_domain == NULL ? "" : log_domain),
qof_log_num_spaces, "",
message,
(g_str_has_suffix(message, "\n") ? "" : "\n"));
fflush(fout);
}
/* chain? ignore? Only chain if it's going to be quiet...
else
{
// chain
previous_handler(log_domain, log_level, message, NULL);
}
*/
/* chain? ignore? Only chain if it's going to be quiet...
else
{
// chain
previous_handler(log_domain, log_level, message, NULL);
}
*/
}
void
qof_log_init_filename(const gchar* log_filename)
{
if (log_table == NULL)
log_table = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, NULL);
if (log_table == NULL)
log_table = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, NULL);
if (log_filename)
{
int fd;
gchar *fname;
if (log_filename)
{
int fd;
gchar *fname;
if (fout != NULL && fout != stderr && fout != stdout)
fclose(fout);
if (fout != NULL && fout != stderr && fout != stdout)
fclose(fout);
fname = g_strconcat(log_filename, ".XXXXXX", NULL);
fname = g_strconcat(log_filename, ".XXXXXX", NULL);
if ((fd = g_mkstemp(fname)) != -1)
{
g_rename(fname, log_filename);
fout = fdopen(fd, "w");
}
else
{
fout = stderr;
}
g_free(fname);
}
if ((fd = g_mkstemp(fname)) != -1)
{
g_rename(fname, log_filename);
fout = fdopen(fd, "w");
}
else
{
fout = stderr;
}
g_free(fname);
}
if (!fout)
fout = stderr;
if (!fout)
fout = stderr;
// @@fixme really, the userdata is a struct { log_table, fout, previous_handler }
if (previous_handler == NULL)
previous_handler = g_log_set_default_handler(log4glib_handler, log_table);
// @@fixme really, the userdata is a struct { log_table, fout, previous_handler }
if (previous_handler == NULL)
previous_handler = g_log_set_default_handler(log4glib_handler, log_table);
}
void
qof_log_shutdown (void)
{
if (fout && fout != stderr && fout != stdout)
if (fout && fout != stderr && fout != stdout)
{
fclose(fout);
fout = NULL;
fclose(fout);
fout = NULL;
}
if (function_buffer)
if (function_buffer)
{
g_free(function_buffer);
function_buffer = NULL;
g_free(function_buffer);
function_buffer = NULL;
}
if (log_table != NULL)
{
g_hash_table_destroy(log_table);
log_table = NULL;
g_hash_table_destroy(log_table);
log_table = NULL;
}
if (previous_handler != NULL)
{
g_log_set_default_handler(previous_handler, NULL);
previous_handler = NULL;
g_log_set_default_handler(previous_handler, NULL);
previous_handler = NULL;
}
}
void
qof_log_set_level(QofLogModule log_module, QofLogLevel level)
{
if (!log_module || level == 0) { return; }
if (!log_table)
{
log_table = g_hash_table_new(g_str_hash, g_str_equal);
}
g_hash_table_insert(log_table, g_strdup((gchar*)log_module), GINT_TO_POINTER((gint)level));
if (!log_module || level == 0)
{
return;
}
if (!log_table)
{
log_table = g_hash_table_new(g_str_hash, g_str_equal);
}
g_hash_table_insert(log_table, g_strdup((gchar*)log_module), GINT_TO_POINTER((gint)level));
}
const char *
qof_log_prettify (const char *name)
{
gchar *p, *buffer;
gint length;
if (!name) { return ""; }
buffer = g_strndup(name, QOF_LOG_MAX_CHARS - 1);
length = strlen(buffer);
p = g_strstr_len(buffer, length, "(");
if (p)
{
*(p+1) = ')';
*(p+2) = 0x0;
}
else { strcpy (&buffer[QOF_LOG_MAX_CHARS - 6], "...()"); }
if (function_buffer)
g_free(function_buffer);
function_buffer = g_strdup(buffer);
g_free(buffer);
return function_buffer;
gchar *p, *buffer;
gint length;
if (!name)
{
return "";
}
buffer = g_strndup(name, QOF_LOG_MAX_CHARS - 1);
length = strlen(buffer);
p = g_strstr_len(buffer, length, "(");
if (p)
{
*(p + 1) = ')';
*(p + 2) = 0x0;
}
else
{
strcpy (&buffer[QOF_LOG_MAX_CHARS - 6], "...()");
}
if (function_buffer)
g_free(function_buffer);
function_buffer = g_strdup(buffer);
g_free(buffer);
return function_buffer;
}
void
qof_log_init_filename_special(const char *log_to_filename)
{
if (g_ascii_strcasecmp("stderr", log_to_filename) == 0)
{
qof_log_set_file(stderr);
}
else if (g_ascii_strcasecmp("stdout", log_to_filename) == 0)
{
qof_log_set_file(stdout);
}
else
{
qof_log_init_filename(log_to_filename);
}
if (g_ascii_strcasecmp("stderr", log_to_filename) == 0)
{
qof_log_set_file(stderr);
}
else if (g_ascii_strcasecmp("stdout", log_to_filename) == 0)
{
qof_log_set_file(stdout);
}
else
{
qof_log_init_filename(log_to_filename);
}
}
void
qof_log_parse_log_config(const char *filename)
{
const gchar *levels_group = "levels", *output_group = "output";
GError *err = NULL;
GKeyFile *conf = g_key_file_new();
const gchar *levels_group = "levels", *output_group = "output";
GError *err = NULL;
GKeyFile *conf = g_key_file_new();
if (!g_key_file_load_from_file(conf, filename, G_KEY_FILE_NONE, &err))
{
g_warning("unable to parse [%s]: %s", filename, err->message);
g_error_free(err);
return;
}
if (!g_key_file_load_from_file(conf, filename, G_KEY_FILE_NONE, &err))
{
g_warning("unable to parse [%s]: %s", filename, err->message);
g_error_free(err);
return;
}
g_debug("parsing log config from [%s]", filename);
if (g_key_file_has_group(conf, levels_group))
{
gsize num_levels;
int key_idx;
gchar **levels;
g_debug("parsing log config from [%s]", filename);
if (g_key_file_has_group(conf, levels_group))
{
gsize num_levels;
int key_idx;
gchar **levels;
levels = g_key_file_get_keys(conf, levels_group, &num_levels, NULL);
levels = g_key_file_get_keys(conf, levels_group, &num_levels, NULL);
for (key_idx = 0; key_idx < num_levels && levels[key_idx] != NULL; key_idx++)
{
QofLogLevel level;
gchar *logger_name = NULL, *level_str = NULL;
for (key_idx = 0; key_idx < num_levels && levels[key_idx] != NULL; key_idx++)
{
QofLogLevel level;
gchar *logger_name = NULL, *level_str = NULL;
logger_name = g_strdup(levels[key_idx]);
level_str = g_key_file_get_string(conf, levels_group, logger_name, NULL);
level = qof_log_level_from_string(level_str);
logger_name = g_strdup(levels[key_idx]);
level_str = g_key_file_get_string(conf, levels_group, logger_name, NULL);
level = qof_log_level_from_string(level_str);
g_debug("setting log [%s] to level [%s=%d]", logger_name, level_str, level);
qof_log_set_level(logger_name, level);
g_debug("setting log [%s] to level [%s=%d]", logger_name, level_str, level);
qof_log_set_level(logger_name, level);
g_free(logger_name);
g_free(level_str);
}
g_strfreev(levels);
}
g_free(logger_name);
g_free(level_str);
}
g_strfreev(levels);
}
if (g_key_file_has_group(conf, output_group))
{
gsize num_outputs;
int output_idx;
gchar **outputs;
outputs = g_key_file_get_keys(conf, output_group, &num_outputs, NULL);
for (output_idx = 0; output_idx < num_outputs && outputs[output_idx] != NULL; output_idx++)
{
gchar *key = outputs[output_idx];
gchar *value;
if (g_key_file_has_group(conf, output_group))
{
gsize num_outputs;
int output_idx;
gchar **outputs;
if (g_ascii_strcasecmp("to", key) != 0)
{
g_warning("unknown key [%s] in [outputs], skipping", key);
continue;
}
outputs = g_key_file_get_keys(conf, output_group, &num_outputs, NULL);
for (output_idx = 0; output_idx < num_outputs && outputs[output_idx] != NULL; output_idx++)
{
gchar *key = outputs[output_idx];
gchar *value;
value = g_key_file_get_string(conf, output_group, key, NULL);
g_debug("setting [output].to=[%s]", value);
qof_log_init_filename_special(value);
g_free(value);
}
g_strfreev(outputs);
}
if (g_ascii_strcasecmp("to", key) != 0)
{
g_warning("unknown key [%s] in [outputs], skipping", key);
continue;
}
g_key_file_free(conf);
value = g_key_file_get_string(conf, output_group, key, NULL);
g_debug("setting [output].to=[%s]", value);
qof_log_init_filename_special(value);
g_free(value);
}
g_strfreev(outputs);
}
g_key_file_free(conf);
}
gboolean
@ -315,47 +328,47 @@ qof_log_check(QofLogModule log_domain, QofLogLevel log_level)
{
//#define _QLC_DBG(x) x
#define _QLC_DBG(x)
GHashTable *log_levels = log_table;
gchar *domain_copy = g_strdup(log_domain == NULL ? "" : log_domain);
gchar *dot_pointer = domain_copy;
static const QofLogLevel default_log_thresh = QOF_LOG_WARNING;
QofLogLevel longest_match_level = default_log_thresh;
GHashTable *log_levels = log_table;
gchar *domain_copy = g_strdup(log_domain == NULL ? "" : log_domain);
gchar *dot_pointer = domain_copy;
static const QofLogLevel default_log_thresh = QOF_LOG_WARNING;
QofLogLevel longest_match_level = default_log_thresh;
{
gpointer match_level;
if ((match_level = g_hash_table_lookup(log_levels, "")) != NULL)
longest_match_level = (QofLogLevel)GPOINTER_TO_INT(match_level);
}
{
gpointer match_level;
if ((match_level = g_hash_table_lookup(log_levels, "")) != NULL)
longest_match_level = (QofLogLevel)GPOINTER_TO_INT(match_level);
}
_QLC_DBG({ printf("trying [%s] (%d):", log_domain, g_hash_table_size(log_levels)); });
if (G_LIKELY(log_levels))
{
// e.g., "a.b.c\0" -> "a\0b.c\0" -> "a.b\0c\0", "a.b.c\0"
gpointer match_level;
while ((dot_pointer = g_strstr_len(dot_pointer, strlen(dot_pointer), ".")) != NULL)
{
*dot_pointer = '\0';
_QLC_DBG({ printf(" [%s]", domain_copy); });
if (g_hash_table_lookup_extended(log_levels, domain_copy, NULL, &match_level))
{
longest_match_level = (QofLogLevel)GPOINTER_TO_INT(match_level);
_QLC_DBG(printf("*"););
}
*dot_pointer = '.';
dot_pointer++;
}
_QLC_DBG( { printf("trying [%s] (%d):", log_domain, g_hash_table_size(log_levels)); });
if (G_LIKELY(log_levels))
{
// e.g., "a.b.c\0" -> "a\0b.c\0" -> "a.b\0c\0", "a.b.c\0"
gpointer match_level;
while ((dot_pointer = g_strstr_len(dot_pointer, strlen(dot_pointer), ".")) != NULL)
{
*dot_pointer = '\0';
_QLC_DBG( { printf(" [%s]", domain_copy); });
if (g_hash_table_lookup_extended(log_levels, domain_copy, NULL, &match_level))
{
longest_match_level = (QofLogLevel)GPOINTER_TO_INT(match_level);
_QLC_DBG(printf("*"););
}
*dot_pointer = '.';
dot_pointer++;
}
_QLC_DBG({ printf(" [%s]", domain_copy); });
if (g_hash_table_lookup_extended(log_levels, domain_copy, NULL, &match_level))
{
longest_match_level = (QofLogLevel)GPOINTER_TO_INT(match_level);
_QLC_DBG({ printf("*"); });
}
}
_QLC_DBG({ printf(" found [%d]\n", longest_match_level); });
g_free(domain_copy);
_QLC_DBG( { printf(" [%s]", domain_copy); });
if (g_hash_table_lookup_extended(log_levels, domain_copy, NULL, &match_level))
{
longest_match_level = (QofLogLevel)GPOINTER_TO_INT(match_level);
_QLC_DBG( { printf("*"); });
}
}
_QLC_DBG( { printf(" found [%d]\n", longest_match_level); });
g_free(domain_copy);
return log_level <= longest_match_level;
return log_level <= longest_match_level;
}
void
@ -368,114 +381,130 @@ qof_log_set_default(QofLogLevel log_level)
gchar*
qof_log_level_to_string(QofLogLevel log_level)
{
gchar *level_str = "unknw";
switch (log_level)
{
case G_LOG_LEVEL_ERROR: level_str = "ERROR"; break;
case G_LOG_LEVEL_CRITICAL:level_str = "CRIT"; break;
case G_LOG_LEVEL_WARNING: level_str = "WARN"; break;
case G_LOG_LEVEL_MESSAGE: level_str = "MESSG"; break;
case G_LOG_LEVEL_INFO: level_str = "INFO"; break;
case G_LOG_LEVEL_DEBUG: level_str = "DEBUG"; break;
default: level_str = "OTHER"; break;
}
return level_str;
gchar *level_str = "unknw";
switch (log_level)
{
case G_LOG_LEVEL_ERROR:
level_str = "ERROR";
break;
case G_LOG_LEVEL_CRITICAL:
level_str = "CRIT";
break;
case G_LOG_LEVEL_WARNING:
level_str = "WARN";
break;
case G_LOG_LEVEL_MESSAGE:
level_str = "MESSG";
break;
case G_LOG_LEVEL_INFO:
level_str = "INFO";
break;
case G_LOG_LEVEL_DEBUG:
level_str = "DEBUG";
break;
default:
level_str = "OTHER";
break;
}
return level_str;
}
QofLogLevel
qof_log_level_from_string(const gchar *str)
{
if (g_ascii_strncasecmp("error", str, 5) == 0) return QOF_LOG_FATAL;
if (g_ascii_strncasecmp("crit", str, 4) == 0) return QOF_LOG_ERROR;
if (g_ascii_strncasecmp("warn", str, 4) == 0) return QOF_LOG_WARNING;
if (g_ascii_strncasecmp("mess", str, 4) == 0) return G_LOG_LEVEL_MESSAGE;
if (g_ascii_strncasecmp("info", str, 4) == 0) return QOF_LOG_INFO;
if (g_ascii_strncasecmp("debug", str, 5) == 0) return QOF_LOG_DEBUG;
return QOF_LOG_DEBUG;
if (g_ascii_strncasecmp("error", str, 5) == 0) return QOF_LOG_FATAL;
if (g_ascii_strncasecmp("crit", str, 4) == 0) return QOF_LOG_ERROR;
if (g_ascii_strncasecmp("warn", str, 4) == 0) return QOF_LOG_WARNING;
if (g_ascii_strncasecmp("mess", str, 4) == 0) return G_LOG_LEVEL_MESSAGE;
if (g_ascii_strncasecmp("info", str, 4) == 0) return QOF_LOG_INFO;
if (g_ascii_strncasecmp("debug", str, 5) == 0) return QOF_LOG_DEBUG;
return QOF_LOG_DEBUG;
}
static
struct timeval qof_clock[NUM_CLOCKS] = {
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
struct timeval qof_clock[NUM_CLOCKS] =
{
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
};
static
struct timeval qof_clock_total[NUM_CLOCKS] = {
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
struct timeval qof_clock_total[NUM_CLOCKS] =
{
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
};
void
qof_start_clock (int clockno, QofLogModule log_module, QofLogLevel log_level,
const gchar *function_name, const gchar *format, ...)
{
va_list ap;
va_list ap;
if ((0>clockno) || (NUM_CLOCKS <= clockno)) return;
if ((0 > clockno) || (NUM_CLOCKS <= clockno)) return;
#ifdef HAVE_GETTIMEOFDAY
gettimeofday (&qof_clock[clockno], NULL);
gettimeofday (&qof_clock[clockno], NULL);
#else
time (&(qof_clock[clockno].tv_sec));
qof_clock[clockno].tv_usec = 0;
time (&(qof_clock[clockno].tv_sec));
qof_clock[clockno].tv_usec = 0;
#endif
if (!fout) qof_log_init();
if (!fout) qof_log_init();
fprintf (fout, "Clock %d Start: %s: ",
clockno, qof_log_prettify (function_name));
fprintf (fout, "Clock %d Start: %s: ",
clockno, qof_log_prettify (function_name));
va_start (ap, format);
va_start (ap, format);
vfprintf (fout, format, ap);
vfprintf (fout, format, ap);
va_end (ap);
va_end (ap);
fprintf (fout, "\n");
fflush (fout);
fprintf (fout, "\n");
fflush (fout);
}
void
qof_report_clock (gint clockno, QofLogModule log_module, QofLogLevel log_level,
const gchar *function_name, const gchar *format, ...)
{
struct timeval now;
va_list ap;
struct timeval now;
va_list ap;
if ((0>clockno) || (NUM_CLOCKS <= clockno)) return;
if ((0 > clockno) || (NUM_CLOCKS <= clockno)) return;
#ifdef HAVE_GETTIMEOFDAY
gettimeofday (&now, NULL);
gettimeofday (&now, NULL);
#else
time (&(now.tv_sec));
now.tv_usec = 0;
time (&(now.tv_sec));
now.tv_usec = 0;
#endif
/* need to borrow to make difference */
if (now.tv_usec < qof_clock[clockno].tv_usec)
{
now.tv_sec --;
now.tv_usec += 1000000;
}
now.tv_sec -= qof_clock[clockno].tv_sec;
now.tv_usec -= qof_clock[clockno].tv_usec;
/* need to borrow to make difference */
if (now.tv_usec < qof_clock[clockno].tv_usec)
{
now.tv_sec --;
now.tv_usec += 1000000;
}
now.tv_sec -= qof_clock[clockno].tv_sec;
now.tv_usec -= qof_clock[clockno].tv_usec;
qof_clock_total[clockno].tv_sec += now.tv_sec;
qof_clock_total[clockno].tv_usec += now.tv_usec;
qof_clock_total[clockno].tv_sec += now.tv_sec;
qof_clock_total[clockno].tv_usec += now.tv_usec;
if (!fout) qof_log_init();
if (!fout) qof_log_init();
fprintf (fout, "Clock %d Elapsed: %ld.%06lds %s: ",
clockno, (long int) now.tv_sec, (long int) now.tv_usec,
qof_log_prettify (function_name));
fprintf (fout, "Clock %d Elapsed: %ld.%06lds %s: ",
clockno, (long int) now.tv_sec, (long int) now.tv_usec,
qof_log_prettify (function_name));
va_start (ap, format);
va_start (ap, format);
vfprintf (fout, format, ap);
vfprintf (fout, format, ap);
va_end (ap);
va_end (ap);
fprintf (fout, "\n");
fflush (fout);
fprintf (fout, "\n");
fflush (fout);
}
void
@ -483,31 +512,31 @@ qof_report_clock_total (gint clockno,
QofLogModule log_module, QofLogLevel log_level,
const gchar *function_name, const gchar *format, ...)
{
va_list ap;
va_list ap;
if ((0>clockno) || (NUM_CLOCKS <= clockno)) return;
if ((0 > clockno) || (NUM_CLOCKS <= clockno)) return;
/* need to normalize usec */
while (qof_clock_total[clockno].tv_usec >= 1000000)
{
qof_clock_total[clockno].tv_sec ++;
qof_clock_total[clockno].tv_usec -= 1000000;
}
/* need to normalize usec */
while (qof_clock_total[clockno].tv_usec >= 1000000)
{
qof_clock_total[clockno].tv_sec ++;
qof_clock_total[clockno].tv_usec -= 1000000;
}
if (!fout) qof_log_init();
if (!fout) qof_log_init();
fprintf (fout, "Clock %d Total Elapsed: %ld.%06lds %s: ",
clockno,
(long int) qof_clock_total[clockno].tv_sec,
(long int) qof_clock_total[clockno].tv_usec,
qof_log_prettify (function_name));
fprintf (fout, "Clock %d Total Elapsed: %ld.%06lds %s: ",
clockno,
(long int) qof_clock_total[clockno].tv_sec,
(long int) qof_clock_total[clockno].tv_usec,
qof_log_prettify (function_name));
va_start (ap, format);
va_start (ap, format);
vfprintf (fout, format, ap);
vfprintf (fout, format, ap);
va_end (ap);
va_end (ap);
fprintf (fout, "\n");
fflush (fout);
fprintf (fout, "\n");
fflush (fout);
}

View File

@ -28,7 +28,7 @@
* @ingroup QOF
* @brief Logging and tracing facility.
* @sa "Logging overhaul" announcement <http://lists.gnucash.org/pipermail/gnucash-devel/2007-February/019836.html>
*
*
* qof_log_init(void) installs a handler that interprets the "log_domain"
* as a "."-separated path. Log level thresholds can be set for each level
* in the tree. When a message is logged, the longest level match is
@ -59,7 +59,7 @@
* The timestamp and level are constant width (level is 5 characters). The
* log domain is re-iterated, which gives some context, but could become
* annoying if they get long.
*
*
* Trailing newlines (e.g. <tt>PINFO("...\n", ...)</tt>) are removed; the logger
* will newline separate output.
*
@ -136,7 +136,7 @@ void qof_log_init_filename_special(const char *log_to_filename);
/**
* Parse a log-configuration file. A GKeyFile-format file of the schema:
* @verbatim
[levels]
[levels]
# log.ger.path=level
gnc.engine.sx=debug
gnc.gui.sx=debug
@ -231,8 +231,8 @@ void qof_log_set_default(QofLogLevel log_level);
/* -------------------------------------------------------- */
/** Infrastructure to make timing measurements for critical pieces
* of code. Used for only for performance tuning & debugging.
/** Infrastructure to make timing measurements for critical pieces
* of code. Used for only for performance tuning & debugging.
*/
void qof_start_clock (gint clockno, QofLogModule log_module, QofLogLevel log_level,

View File

@ -34,143 +34,143 @@
#define HIBIT (0x8000000000000000ULL)
/** Multiply a pair of signed 64-bit numbers,
/** Multiply a pair of signed 64-bit numbers,
* returning a signed 128-bit number.
*/
inline qofint128
mult128 (gint64 a, gint64 b)
{
qofint128 prod;
guint64 a0, a1;
guint64 b0, b1;
guint64 d, d0, d1;
guint64 e, e0, e1;
guint64 f, f0, f1;
guint64 g, g0, g1;
guint64 sum, carry, roll, pmax;
qofint128 prod;
guint64 a0, a1;
guint64 b0, b1;
guint64 d, d0, d1;
guint64 e, e0, e1;
guint64 f, f0, f1;
guint64 g, g0, g1;
guint64 sum, carry, roll, pmax;
prod.isneg = 0;
if (0>a)
{
prod.isneg = !prod.isneg;
a = -a;
}
prod.isneg = 0;
if (0 > a)
{
prod.isneg = !prod.isneg;
a = -a;
}
if (0>b)
{
prod.isneg = !prod.isneg;
b = -b;
}
if (0 > b)
{
prod.isneg = !prod.isneg;
b = -b;
}
a1 = a >> 32;
a0 = a - (a1<<32);
a1 = a >> 32;
a0 = a - (a1 << 32);
b1 = b >> 32;
b0 = b - (b1<<32);
b1 = b >> 32;
b0 = b - (b1 << 32);
d = a0*b0;
d1 = d >> 32;
d0 = d - (d1<<32);
d = a0 * b0;
d1 = d >> 32;
d0 = d - (d1 << 32);
e = a0*b1;
e1 = e >> 32;
e0 = e - (e1<<32);
e = a0 * b1;
e1 = e >> 32;
e0 = e - (e1 << 32);
f = a1*b0;
f1 = f >> 32;
f0 = f - (f1<<32);
f = a1 * b0;
f1 = f >> 32;
f0 = f - (f1 << 32);
g = a1*b1;
g1 = g >> 32;
g0 = g - (g1<<32);
g = a1 * b1;
g1 = g >> 32;
g0 = g - (g1 << 32);
sum = d1+e0+f0;
carry = 0;
/* Can't say 1<<32 cause cpp will goof it up; 1ULL<<32 might work */
roll = 1<<30;
roll <<= 2;
sum = d1 + e0 + f0;
carry = 0;
/* Can't say 1<<32 cause cpp will goof it up; 1ULL<<32 might work */
roll = 1 << 30;
roll <<= 2;
pmax = roll-1;
while (pmax < sum)
{
sum -= roll;
carry ++;
}
pmax = roll - 1;
while (pmax < sum)
{
sum -= roll;
carry ++;
}
prod.lo = d0 + (sum<<32);
prod.hi = carry + e1 + f1 + g0 + (g1<<32);
// prod.isbig = (prod.hi || (sum >> 31));
prod.isbig = prod.hi || (prod.lo >> 63);
prod.lo = d0 + (sum << 32);
prod.hi = carry + e1 + f1 + g0 + (g1 << 32);
// prod.isbig = (prod.hi || (sum >> 31));
prod.isbig = prod.hi || (prod.lo >> 63);
return prod;
return prod;
}
/** Shift right by one bit (i.e. divide by two) */
inline qofint128
shift128 (qofint128 x)
{
guint64 sbit = x.hi & 0x1;
x.hi >>= 1;
x.lo >>= 1;
x.isbig = 0;
if (sbit)
{
x.lo |= HIBIT;
x.isbig = 1;
guint64 sbit = x.hi & 0x1;
x.hi >>= 1;
x.lo >>= 1;
x.isbig = 0;
if (sbit)
{
x.lo |= HIBIT;
x.isbig = 1;
return x;
}
if (x.hi)
{
x.isbig = 1;
}
return x;
}
if (x.hi)
{
x.isbig = 1;
}
return x;
}
/** Shift leftt by one bit (i.e. multiply by two) */
inline qofint128
shiftleft128 (qofint128 x)
{
guint64 sbit;
sbit = x.lo & HIBIT;
x.hi <<= 1;
x.lo <<= 1;
x.isbig = 0;
if (sbit)
{
x.hi |= 1;
x.isbig = 1;
guint64 sbit;
sbit = x.lo & HIBIT;
x.hi <<= 1;
x.lo <<= 1;
x.isbig = 0;
if (sbit)
{
x.hi |= 1;
x.isbig = 1;
return x;
}
if (x.hi)
{
x.isbig = 1;
}
return x;
}
if (x.hi)
{
x.isbig = 1;
}
return x;
}
/** increment a 128-bit number by one */
inline qofint128
inc128 (qofint128 a)
{
if (0 == a.isneg)
{
a.lo ++;
if (0 == a.lo)
if (0 == a.isneg)
{
a.hi ++;
a.lo ++;
if (0 == a.lo)
{
a.hi ++;
}
}
}
else
{
if (0 == a.lo)
else
{
a.hi --;
if (0 == a.lo)
{
a.hi --;
}
a.lo --;
}
a.lo --;
}
a.isbig = (a.hi != 0) || (a.lo >> 63);
return a;
a.isbig = (a.hi != 0) || (a.lo >> 63);
return a;
}
/** Divide a signed 128-bit number by a signed 64-bit,
@ -179,152 +179,152 @@ inc128 (qofint128 a)
inline qofint128
div128 (qofint128 n, gint64 d)
{
qofint128 quotient;
int i;
guint64 remainder = 0;
qofint128 quotient;
int i;
guint64 remainder = 0;
quotient = n;
if (0 > d)
{
d = -d;
quotient.isneg = !quotient.isneg;
}
/* Use grade-school long division algorithm */
for (i=0; i<128; i++)
{
guint64 sbit = HIBIT & quotient.hi;
remainder <<= 1;
if (sbit) remainder |= 1;
quotient = shiftleft128 (quotient);
if (remainder >= d)
quotient = n;
if (0 > d)
{
remainder -= d;
quotient.lo |= 1;
d = -d;
quotient.isneg = !quotient.isneg;
}
}
/* compute the carry situation */
quotient.isbig = (quotient.hi || (quotient.lo >> 63));
/* Use grade-school long division algorithm */
for (i = 0; i < 128; i++)
{
guint64 sbit = HIBIT & quotient.hi;
remainder <<= 1;
if (sbit) remainder |= 1;
quotient = shiftleft128 (quotient);
if (remainder >= d)
{
remainder -= d;
quotient.lo |= 1;
}
}
return quotient;
/* compute the carry situation */
quotient.isbig = (quotient.hi || (quotient.lo >> 63));
return quotient;
}
/** Return the remainder of a signed 128-bit number modulo
/** Return the remainder of a signed 128-bit number modulo
* a signed 64-bit. That is, return n%d in 128-bit math.
* I beleive that ths algo is overflow-free, but should be
* audited some more ...
* I beleive that ths algo is overflow-free, but should be
* audited some more ...
*/
inline gint64
rem128 (qofint128 n, gint64 d)
{
qofint128 quotient = div128 (n,d);
qofint128 quotient = div128 (n, d);
qofint128 mu = mult128 (quotient.lo, d);
qofint128 mu = mult128 (quotient.lo, d);
gint64 nn = 0x7fffffffffffffffULL & n.lo;
gint64 rr = 0x7fffffffffffffffULL & mu.lo;
return nn - rr;
gint64 nn = 0x7fffffffffffffffULL & n.lo;
gint64 rr = 0x7fffffffffffffffULL & mu.lo;
return nn - rr;
}
/** Return true of two numbers are equal */
inline gboolean
equal128 (qofint128 a, qofint128 b)
{
if (a.lo != b.lo) return 0;
if (a.hi != b.hi) return 0;
if (a.isneg != b.isneg) return 0;
return 1;
if (a.lo != b.lo) return 0;
if (a.hi != b.hi) return 0;
if (a.isneg != b.isneg) return 0;
return 1;
}
/** Return returns 1 if a>b, -1 if b>a, 0 if a == b */
inline int
cmp128 (qofint128 a, qofint128 b)
{
if ((0 == a.isneg) && b.isneg) return 1;
if (a.isneg && (0 == b.isneg)) return -1;
if (0 == a.isneg)
{
if (a.hi > b.hi) return 1;
if (a.hi < b.hi) return -1;
if (a.lo > b.lo) return 1;
if (a.lo < b.lo) return -1;
return 0;
}
if ((0 == a.isneg) && b.isneg) return 1;
if (a.isneg && (0 == b.isneg)) return -1;
if (0 == a.isneg)
{
if (a.hi > b.hi) return 1;
if (a.hi < b.hi) return -1;
if (a.lo > b.lo) return 1;
if (a.lo < b.lo) return -1;
return 0;
}
if (a.hi > b.hi) return -1;
if (a.hi < b.hi) return 1;
if (a.lo > b.lo) return -1;
if (a.lo < b.lo) return 1;
return 0;
if (a.hi > b.hi) return -1;
if (a.hi < b.hi) return 1;
if (a.lo > b.lo) return -1;
if (a.lo < b.lo) return 1;
return 0;
}
/** Return the greatest common factor of two 64-bit numbers */
inline guint64
gcf64(guint64 num, guint64 denom)
{
guint64 t;
guint64 t;
t = num % denom;
num = denom;
denom = t;
/* The strategy is to use Euclid's algorithm */
while (0 != denom)
{
t = num % denom;
t = num % denom;
num = denom;
denom = t;
}
/* num now holds the GCD (Greatest Common Divisor) */
return num;
/* The strategy is to use Euclid's algorithm */
while (0 != denom)
{
t = num % denom;
num = denom;
denom = t;
}
/* num now holds the GCD (Greatest Common Divisor) */
return num;
}
/** Return the least common multiple of two 64-bit numbers. */
inline qofint128
lcm128 (guint64 a, guint64 b)
{
guint64 gcf = gcf64 (a,b);
b /= gcf;
return mult128 (a,b);
guint64 gcf = gcf64 (a, b);
b /= gcf;
return mult128 (a, b);
}
/** Add a pair of 128-bit numbers, returning a 128-bit number */
inline qofint128
add128 (qofint128 a, qofint128 b)
{
qofint128 sum;
if (a.isneg == b.isneg)
{
sum.isneg = a.isneg;
sum.hi = a.hi + b.hi;
sum.lo = a.lo + b.lo;
if ((sum.lo < a.lo) || (sum.lo < b.lo))
qofint128 sum;
if (a.isneg == b.isneg)
{
sum.hi ++;
sum.isneg = a.isneg;
sum.hi = a.hi + b.hi;
sum.lo = a.lo + b.lo;
if ((sum.lo < a.lo) || (sum.lo < b.lo))
{
sum.hi ++;
}
sum.isbig = sum.hi || (sum.lo >> 63);
return sum;
}
if ((b.hi > a.hi) ||
((b.hi == a.hi) && (b.lo > a.lo)))
{
qofint128 tmp = a;
a = b;
b = tmp;
}
sum.isneg = a.isneg;
sum.hi = a.hi - b.hi;
sum.lo = a.lo - b.lo;
if (sum.lo > a.lo)
{
sum.hi --;
}
sum.isbig = sum.hi || (sum.lo >> 63);
return sum;
}
if ((b.hi > a.hi) ||
((b.hi == a.hi) && (b.lo > a.lo)))
{
qofint128 tmp = a;
a = b;
b = tmp;
}
sum.isneg = a.isneg;
sum.hi = a.hi - b.hi;
sum.lo = a.lo - b.lo;
if (sum.lo > a.lo)
{
sum.hi --;
}
sum.isbig = sum.hi || (sum.lo >> 63);
return sum;
}
@ -332,84 +332,85 @@ add128 (qofint128 a, qofint128 b)
static void pr (gint64 a, gint64 b)
{
qofint128 prod = mult128 (a,b);
printf ("%" G_GINT64_FORMAT " * %" G_GINT64_FORMAT " = %"
G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " (0x%"
G_GINT64_MODIFIER "x %" G_GINT64_MODIFIER "x) %hd\n",
a, b, prod.hi, prod.lo, prod.hi, prod.lo, prod.isbig);
qofint128 prod = mult128 (a, b);
printf ("%" G_GINT64_FORMAT " * %" G_GINT64_FORMAT " = %"
G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " (0x%"
G_GINT64_MODIFIER "x %" G_GINT64_MODIFIER "x) %hd\n",
a, b, prod.hi, prod.lo, prod.hi, prod.lo, prod.isbig);
}
static void prd (gint64 a, gint64 b, gint64 c)
{
qofint128 prod = mult128 (a,b);
qofint128 quot = div128 (prod, c);
gint64 rem = rem128 (prod, c);
printf ("%" G_GINT64_FORMAT " * %" G_GINT64_FORMAT " / %" G_GINT64_FORMAT
" = %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " + %"
G_GINT64_FORMAT " (0x%" G_GINT64_MODIFIER "x %"
G_GINT64_MODIFIER "x) %hd\n",
a, b, c, quot.hi, quot.lo, rem, quot.hi, quot.lo, quot.isbig);
qofint128 prod = mult128 (a, b);
qofint128 quot = div128 (prod, c);
gint64 rem = rem128 (prod, c);
printf ("%" G_GINT64_FORMAT " * %" G_GINT64_FORMAT " / %" G_GINT64_FORMAT
" = %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " + %"
G_GINT64_FORMAT " (0x%" G_GINT64_MODIFIER "x %"
G_GINT64_MODIFIER "x) %hd\n",
a, b, c, quot.hi, quot.lo, rem, quot.hi, quot.lo, quot.isbig);
}
int main ()
{
gint64 x;
qofint128 n;
gint64 d;
qofint128 quot;
int i;
gint64 x;
qofint128 n;
gint64 d;
qofint128 quot;
int i;
pr (2,2);
pr (2, 2);
x = 1<<30;
x <<= 2;
x = 1 << 30;
x <<= 2;
pr (x,x);
pr (x+1,x);
pr (x+1,x+1);
pr (x, x);
pr (x + 1, x);
pr (x + 1, x + 1);
pr (x,-x);
pr (-x,-x);
pr (x-1,x);
pr (x-1,x-1);
pr (x-2,x-2);
pr (x, -x);
pr (-x, -x);
pr (x - 1, x);
pr (x - 1, x - 1);
pr (x - 2, x - 2);
x <<= 1;
pr (x,x);
pr (x,-x);
x <<= 1;
pr (x, x);
pr (x, -x);
pr (1000000, G_GINT64_CONSTANT(10000000000000));
pr (1000000, G_GINT64_CONSTANT(10000000000000));
prd (x,x,2);
prd (x,x,3);
prd (x,x,4);
prd (x,x,5);
prd (x,x,6);
prd (x, x, 2);
prd (x, x, 3);
prd (x, x, 4);
prd (x, x, 5);
prd (x, x, 6);
x <<= 29;
prd (3,x,3);
prd (6,x,3);
prd (99,x,3);
prd (100,x,5);
prd (540,x,5);
prd (777,x,7);
prd (1111,x,11);
x <<= 29;
prd (3, x, 3);
prd (6, x, 3);
prd (99, x, 3);
prd (100, x, 5);
prd (540, x, 5);
prd (777, x, 7);
prd (1111, x, 11);
/* Really test division */
n.hi = 0xdd91;
n.lo = 0x6c5abefbb9e13480ULL;
/* Really test division */
n.hi = 0xdd91;
n.lo = 0x6c5abefbb9e13480ULL;
d = 0x2ae79964d3ae1d04ULL;
for (i=0; i<20; i++) {
d = 0x2ae79964d3ae1d04ULL;
quot = div128 (n, d);
printf ("%d result = %" G_GINT64_MODIFIER "x %" G_GINT64_MODIFIER "x\n",
i, quot.hi, quot.lo);
d >>=1;
n = shift128 (n);
}
return 0;
for (i = 0; i < 20; i++)
{
quot = div128 (n, d);
printf ("%d result = %" G_GINT64_MODIFIER "x %" G_GINT64_MODIFIER "x\n",
i, quot.hi, quot.lo);
d >>= 1;
n = shift128 (n);
}
return 0;
}
#endif /* TEST_128_BIT_MULT */

View File

@ -32,11 +32,12 @@
* @{
*/
typedef struct {
guint64 hi;
guint64 lo;
short isneg; /**< sign-bit -- T if number is negative */
short isbig; /**< sizeflag -- T if number won't fit in signed 64-bit */
typedef struct
{
guint64 hi;
guint64 lo;
short isneg; /**< sign-bit -- T if number is negative */
short isbig; /**< sizeflag -- T if number won't fit in signed 64-bit */
} qofint128;
/** Return true of two numbers are equal */
@ -57,7 +58,7 @@ inline qofint128 inc128 (qofint128 a);
/** Add a pair of 128-bit numbers, returning a 128-bit number */
inline qofint128 add128 (qofint128 a, qofint128 b);
/** Multiply a pair of signed 64-bit numbers,
/** Multiply a pair of signed 64-bit numbers,
* returning a signed 128-bit number.
*/
inline qofint128 mult128 (gint64 a, gint64 b);
@ -67,10 +68,10 @@ inline qofint128 mult128 (gint64 a, gint64 b);
*/
inline qofint128 div128 (qofint128 n, gint64 d);
/** Return the remainder of a signed 128-bit number modulo
/** Return the remainder of a signed 128-bit number modulo
* a signed 64-bit. That is, return n%d in 128-bit math.
* I beleive that ths algo is overflow-free, but should be
* audited some more ...
* I beleive that ths algo is overflow-free, but should be
* audited some more ...
*/
inline gint64 rem128 (qofint128 n, gint64 d);

View File

@ -21,7 +21,7 @@
/** @addtogroup Object
@{ */
/** @addtogroup Object_Private
Private interfaces, not meant to be used by applications.
Private interfaces, not meant to be used by applications.
@{ */
/** @name Objects_Private
@{ */
@ -52,7 +52,7 @@ calling more than once, pass FALSE.
\return TRUE if object can be created and supports iteration, else FALSE.
*/
gboolean
gboolean
qof_object_compliance (QofIdTypeConst type_name, gboolean warn);
#endif /* QOF_OBJECT_P_H_ */

View File

@ -41,200 +41,210 @@ static GHashTable *backend_data = NULL;
gpointer
qof_object_new_instance (QofIdTypeConst type_name, QofBook *book)
{
const QofObject *obj;
const QofObject *obj;
if (!type_name) return NULL;
if (!type_name) return NULL;
obj = qof_object_lookup (type_name);
if (!obj) return NULL;
obj = qof_object_lookup (type_name);
if (!obj) return NULL;
if (obj->create)
return (obj->create (book));
if (obj->create)
return (obj->create (book));
return NULL;
return NULL;
}
void qof_object_book_begin (QofBook *book)
{
GList *l;
GList *l;
if (!book) return;
ENTER (" ");
for (l = object_modules; l; l = l->next) {
QofObject *obj = l->data;
if (obj->book_begin)
obj->book_begin (book);
}
if (!book) return;
ENTER (" ");
for (l = object_modules; l; l = l->next)
{
QofObject *obj = l->data;
if (obj->book_begin)
obj->book_begin (book);
}
/* Remember this book for later */
book_list = g_list_prepend (book_list, book);
LEAVE (" ");
/* Remember this book for later */
book_list = g_list_prepend (book_list, book);
LEAVE (" ");
}
void qof_object_book_end (QofBook *book)
{
GList *l;
GList *l;
if (!book) return;
ENTER (" ");
for (l = object_modules; l; l = l->next) {
QofObject *obj = l->data;
if (obj->book_end)
obj->book_end (book);
}
if (!book) return;
ENTER (" ");
for (l = object_modules; l; l = l->next)
{
QofObject *obj = l->data;
if (obj->book_end)
obj->book_end (book);
}
/* Remove it from the list */
book_list = g_list_remove (book_list, book);
LEAVE (" ");
/* Remove it from the list */
book_list = g_list_remove (book_list, book);
LEAVE (" ");
}
gboolean
gboolean
qof_object_is_dirty (const QofBook *book)
{
GList *l;
GList *l;
if (!book) return FALSE;
for (l = object_modules; l; l = l->next)
{
QofObject *obj = l->data;
if (obj->is_dirty)
if (!book) return FALSE;
for (l = object_modules; l; l = l->next)
{
QofCollection *col;
col = qof_book_get_collection (book, obj->e_type);
if (obj->is_dirty (col)) return TRUE;
QofObject *obj = l->data;
if (obj->is_dirty)
{
QofCollection *col;
col = qof_book_get_collection (book, obj->e_type);
if (obj->is_dirty (col)) return TRUE;
}
}
}
return FALSE;
return FALSE;
}
void
void
qof_object_mark_clean (QofBook *book)
{
GList *l;
GList *l;
if (!book) return;
for (l = object_modules; l; l = l->next)
{
QofObject *obj = l->data;
if (obj->mark_clean)
if (!book) return;
for (l = object_modules; l; l = l->next)
{
QofCollection *col;
col = qof_book_get_collection (book, obj->e_type);
(obj->mark_clean) (col);
QofObject *obj = l->data;
if (obj->mark_clean)
{
QofCollection *col;
col = qof_book_get_collection (book, obj->e_type);
(obj->mark_clean) (col);
}
}
}
}
void qof_object_foreach_type (QofForeachTypeCB cb, gpointer user_data)
{
GList *l;
GList *l;
if (!cb) return;
if (!cb) return;
for (l = object_modules; l; l = l->next) {
QofObject *obj = l->data;
(cb) (obj, user_data);
}
for (l = object_modules; l; l = l->next)
{
QofObject *obj = l->data;
(cb) (obj, user_data);
}
}
gboolean
gboolean
qof_object_compliance (QofIdTypeConst type_name, gboolean warn)
{
const QofObject *obj;
const QofObject *obj;
obj = qof_object_lookup(type_name);
if((obj->create == NULL)||(obj->foreach == NULL)){
if(warn)
{
PINFO (" Object type %s is not fully QOF compliant", obj->e_type);
}
return FALSE;
}
return TRUE;
obj = qof_object_lookup(type_name);
if ((obj->create == NULL) || (obj->foreach == NULL))
{
if (warn)
{
PINFO (" Object type %s is not fully QOF compliant", obj->e_type);
}
return FALSE;
}
return TRUE;
}
void
qof_object_foreach (QofIdTypeConst type_name, QofBook *book,
void
qof_object_foreach (QofIdTypeConst type_name, QofBook *book,
QofInstanceForeachCB cb, gpointer user_data)
{
QofCollection *col;
const QofObject *obj;
QofCollection *col;
const QofObject *obj;
if (!book || !type_name) { return; }
PINFO ("type=%s", type_name);
if (!book || !type_name)
{
return;
}
PINFO ("type=%s", type_name);
obj = qof_object_lookup (type_name);
if (!obj)
{
PERR ("No object of type %s", type_name);
obj = qof_object_lookup (type_name);
if (!obj)
{
PERR ("No object of type %s", type_name);
return;
}
col = qof_book_get_collection (book, obj->e_type);
if (!obj)
{
return;
}
if (obj->foreach)
{
obj->foreach (col, cb, user_data);
}
return;
}
col = qof_book_get_collection (book, obj->e_type);
if (!obj) { return; }
if (obj->foreach)
{
obj->foreach (col, cb, user_data);
}
return;
}
const char *
qof_object_printable (QofIdTypeConst type_name, gpointer obj)
{
const QofObject *b_obj;
const QofObject *b_obj;
if (!type_name || !obj) return NULL;
if (!type_name || !obj) return NULL;
b_obj = qof_object_lookup (type_name);
if (!b_obj) return NULL;
b_obj = qof_object_lookup (type_name);
if (!b_obj) return NULL;
if (b_obj->printable)
return (b_obj->printable (obj));
if (b_obj->printable)
return (b_obj->printable (obj));
return NULL;
return NULL;
}
const char * qof_object_get_type_label (QofIdTypeConst type_name)
{
const QofObject *obj;
const QofObject *obj;
if (!type_name) return NULL;
if (!type_name) return NULL;
obj = qof_object_lookup (type_name);
if (!obj) return NULL;
obj = qof_object_lookup (type_name);
if (!obj) return NULL;
return (obj->type_label);
return (obj->type_label);
}
static gboolean clear_table (gpointer key, gpointer value, gpointer user_data)
{
g_hash_table_destroy (value);
return TRUE;
g_hash_table_destroy (value);
return TRUE;
}
/* INITIALIZATION and PRIVATE FUNCTIONS */
void qof_object_initialize (void)
{
if (object_is_initialized) return;
backend_data = g_hash_table_new (g_str_hash, g_str_equal);
object_is_initialized = TRUE;
if (object_is_initialized) return;
backend_data = g_hash_table_new (g_str_hash, g_str_equal);
object_is_initialized = TRUE;
}
void qof_object_shutdown (void)
{
g_return_if_fail (object_is_initialized == TRUE);
g_return_if_fail (object_is_initialized == TRUE);
g_hash_table_foreach_remove (backend_data, clear_table, NULL);
g_hash_table_destroy (backend_data);
backend_data = NULL;
g_hash_table_foreach_remove (backend_data, clear_table, NULL);
g_hash_table_destroy (backend_data);
backend_data = NULL;
g_list_free (object_modules);
object_modules = NULL;
g_list_free (book_list);
book_list = NULL;
object_is_initialized = FALSE;
g_list_free (object_modules);
object_modules = NULL;
g_list_free (book_list);
book_list = NULL;
object_is_initialized = FALSE;
}
/* Register new types of object objects.
@ -244,119 +254,123 @@ void qof_object_shutdown (void)
*/
gboolean qof_object_register (const QofObject *object)
{
g_return_val_if_fail (object_is_initialized, FALSE);
g_return_val_if_fail (object_is_initialized, FALSE);
if (!object) return FALSE;
g_return_val_if_fail (object->interface_version == QOF_OBJECT_VERSION, FALSE);
if (!object) return FALSE;
g_return_val_if_fail (object->interface_version == QOF_OBJECT_VERSION, FALSE);
if (g_list_index (object_modules, (gpointer)object) == -1)
object_modules = g_list_prepend (object_modules, (gpointer)object);
else
return FALSE;
if (g_list_index (object_modules, (gpointer)object) == -1)
object_modules = g_list_prepend (object_modules, (gpointer)object);
else
return FALSE;
/* Now initialize all the known books */
if (object->book_begin && book_list) {
GList *node;
for (node = book_list; node; node = node->next)
object->book_begin (node->data);
}
/* Now initialize all the known books */
if (object->book_begin && book_list)
{
GList *node;
for (node = book_list; node; node = node->next)
object->book_begin (node->data);
}
return TRUE;
return TRUE;
}
const QofObject * qof_object_lookup (QofIdTypeConst name)
{
GList *iter;
const QofObject *obj;
GList *iter;
const QofObject *obj;
g_return_val_if_fail (object_is_initialized, NULL);
g_return_val_if_fail (object_is_initialized, NULL);
if (!name) return NULL;
if (!name) return NULL;
for (iter = object_modules; iter; iter = iter->next) {
obj = iter->data;
if (!safe_strcmp (obj->e_type, name))
return obj;
}
return NULL;
for (iter = object_modules; iter; iter = iter->next)
{
obj = iter->data;
if (!safe_strcmp (obj->e_type, name))
return obj;
}
return NULL;
}
gboolean qof_object_register_backend (QofIdTypeConst type_name,
const char *backend_name,
gpointer be_data)
const char *backend_name,
gpointer be_data)
{
GHashTable *ht;
g_return_val_if_fail (object_is_initialized, FALSE);
GHashTable *ht;
g_return_val_if_fail (object_is_initialized, FALSE);
if (!type_name || *type_name == '\0' ||
!backend_name || *backend_name == '\0' ||
!be_data)
return FALSE;
if (!type_name || *type_name == '\0' ||
!backend_name || *backend_name == '\0' ||
!be_data)
return FALSE;
ht = g_hash_table_lookup (backend_data, backend_name);
ht = g_hash_table_lookup (backend_data, backend_name);
/* If it doesn't already exist, create a new table for this backend */
if (!ht) {
ht = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_insert (backend_data, (char *)backend_name, ht);
}
/* If it doesn't already exist, create a new table for this backend */
if (!ht)
{
ht = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_insert (backend_data, (char *)backend_name, ht);
}
/* Now insert the data */
g_hash_table_insert (ht, (char *)type_name, be_data);
/* Now insert the data */
g_hash_table_insert (ht, (char *)type_name, be_data);
return TRUE;
return TRUE;
}
gpointer qof_object_lookup_backend (QofIdTypeConst type_name,
const char *backend_name)
const char *backend_name)
{
GHashTable *ht;
GHashTable *ht;
if (!type_name || *type_name == '\0' ||
!backend_name || *backend_name == '\0')
return NULL;
if (!type_name || *type_name == '\0' ||
!backend_name || *backend_name == '\0')
return NULL;
ht = g_hash_table_lookup (backend_data, (char *)backend_name);
if (!ht)
return NULL;
ht = g_hash_table_lookup (backend_data, (char *)backend_name);
if (!ht)
return NULL;
return g_hash_table_lookup (ht, (char *)type_name);
return g_hash_table_lookup (ht, (char *)type_name);
}
struct foreach_data {
QofForeachBackendTypeCB cb;
gpointer user_data;
struct foreach_data
{
QofForeachBackendTypeCB cb;
gpointer user_data;
};
static void foreach_backend (gpointer key, gpointer be_item, gpointer arg)
{
char *data_type = key;
struct foreach_data *cb_data = arg;
char *data_type = key;
struct foreach_data *cb_data = arg;
g_return_if_fail (key && be_item && arg);
g_return_if_fail (key && be_item && arg);
/* Call the callback for this data type */
(cb_data->cb) (data_type, be_item, cb_data->user_data);
/* Call the callback for this data type */
(cb_data->cb) (data_type, be_item, cb_data->user_data);
}
void qof_object_foreach_backend (const char *backend_name,
QofForeachBackendTypeCB cb,
gpointer user_data)
{
GHashTable *ht;
struct foreach_data cb_data;
GHashTable *ht;
struct foreach_data cb_data;
if (!backend_name || *backend_name == '\0' || !cb)
return;
if (!backend_name || *backend_name == '\0' || !cb)
return;
ht = g_hash_table_lookup (backend_data, (char *)backend_name);
if (!ht)
return;
ht = g_hash_table_lookup (backend_data, (char *)backend_name);
if (!ht)
return;
cb_data.cb = cb;
cb_data.user_data = user_data;
cb_data.cb = cb;
cb_data.user_data = user_data;
g_hash_table_foreach (ht, foreach_backend, &cb_data);
g_hash_table_foreach (ht, foreach_backend, &cb_data);
}
/* ========================= END OF FILE =================== */

View File

@ -28,14 +28,14 @@
QOF Object provides for a way to associate instances with
a storage backend. Storage might be file or SQL storage.
QOF Objects are also used by the query system ....
QOF Objects are also used by the query system ....
To work with your own QOF Objects, you can use the QOF
Generator to create sample objects and a mini-application
with the SQL-type query interface.
http://qof-gen.sourceforge.net/
XXX todo, we should split out the storage aspects of this
XXX todo, we should split out the storage aspects of this
thing from the 'foreach' that query depends on. These are
kinda unrelated concepts.
@ -64,61 +64,61 @@ typedef struct _QofObject QofObject;
typedef void (*QofForeachCB) (gpointer obj, gpointer user_data);
typedef void (*QofForeachTypeCB) (QofObject *type, gpointer user_data);
typedef void (*QofForeachBackendTypeCB) (QofIdTypeConst type,
gpointer backend_data,
gpointer user_data);
gpointer backend_data,
gpointer user_data);
/** This is the QofObject Class descriptor
/** This is the QofObject Class descriptor
*/
struct _QofObject
struct _QofObject
{
gint interface_version; /* of this object interface */
QofIdType e_type; /* the Object's QOF_ID */
const char * type_label; /* "Printable" type-label string */
gint interface_version; /* of this object interface */
QofIdType e_type; /* the Object's QOF_ID */
const char * type_label; /* "Printable" type-label string */
/** Create a new instance of this object type. This routine might be
* NULL if the object type doesn't provide a way of creating new
* instances.
*/
gpointer (*create)(QofBook *);
/** Create a new instance of this object type. This routine might be
* NULL if the object type doesn't provide a way of creating new
* instances.
*/
gpointer (*create)(QofBook *);
/** book_begin is called from within the Book routines to create
* module-specific hooks in a book whenever a book is created.
*/
void (*book_begin)(QofBook *);
/** book_begin is called from within the Book routines to create
* module-specific hooks in a book whenever a book is created.
*/
void (*book_begin)(QofBook *);
/** book_end is called when the book is being closed, to clean
* up (and free memory).
*/
void (*book_end)(QofBook *);
/** book_end is called when the book is being closed, to clean
* up (and free memory).
*/
void (*book_end)(QofBook *);
/** Determine if there are any dirty items in this book */
gboolean (*is_dirty)(const QofCollection *);
/** Determine if there are any dirty items in this book */
gboolean (*is_dirty)(const QofCollection *);
/** Mark this object's book clean (for after a load) */
void (*mark_clean)(QofCollection *);
/** Mark this object's book clean (for after a load) */
void (*mark_clean)(QofCollection *);
/** Traverse over all of the items in the collection, calling
* the callback on each item. The third argument can be any
* arbitrary caller-supplied data, and is passed to the callback.
* Although (*foreach) may be NULL, allmost all objects should
* provide this routine, as without it, little of interest can
* be done.
*/
void (*foreach)(const QofCollection *, QofInstanceForeachCB, gpointer);
/** Traverse over all of the items in the collection, calling
* the callback on each item. The third argument can be any
* arbitrary caller-supplied data, and is passed to the callback.
* Although (*foreach) may be NULL, allmost all objects should
* provide this routine, as without it, little of interest can
* be done.
*/
void (*foreach)(const QofCollection *, QofInstanceForeachCB, gpointer);
/** Given a particular item of this type, return a printable string.
*/
const char * (*printable)(gpointer instance);
/** Given a particular item of this type, return a printable string.
*/
const char * (*printable)(gpointer instance);
/** Given a pair of items of this type, this routine returns value
* indicating which item is 'newer'. This routine is used by storage
* backends to determine if the local or the remote copy of a
* particular item is the latest, 'uptodate' version. Tis routine
* should return an integer less than, equal to, or greater than zero
* if 'instance_left' is found to be, respecitvely, earlier than, equal
* to or later than than 'instance_right'.
*/
int (*version_cmp)(gpointer instance_left, gpointer instance_right);
/** Given a pair of items of this type, this routine returns value
* indicating which item is 'newer'. This routine is used by storage
* backends to determine if the local or the remote copy of a
* particular item is the latest, 'uptodate' version. Tis routine
* should return an integer less than, equal to, or greater than zero
* if 'instance_left' is found to be, respecitvely, earlier than, equal
* to or later than than 'instance_right'.
*/
int (*version_cmp)(gpointer instance_left, gpointer instance_right);
};
/* -------------------------------------------------------------- */
@ -137,7 +137,7 @@ const QofObject * qof_object_lookup (QofIdTypeConst type_name);
/** Create an instance of the indicated type, returning a pointer to that
* instance. This routine just calls the (*new) callback on the object
* definition.
* definition.
*/
gpointer qof_object_new_instance (QofIdTypeConst type_name, QofBook *book);
@ -156,10 +156,10 @@ void qof_object_foreach_type (QofForeachTypeCB cb, gpointer user_data);
/** Invoke the callback 'cb' on every instance ov a particular
* object type. It is presumed that the 'book' stores or somehow
* identifies a colllection of instances; thus the callback will
* identifies a colllection of instances; thus the callback will
* be invoked only for those instances stored in the book.
*/
void qof_object_foreach (QofIdTypeConst type_name, QofBook *book,
void qof_object_foreach (QofIdTypeConst type_name, QofBook *book,
QofInstanceForeachCB cb, gpointer user_data);
/** Register and lookup backend-specific data for this particular object */
@ -167,7 +167,8 @@ gboolean qof_object_register_backend (QofIdTypeConst type_name,
const char *backend_name,
gpointer be_data);
/*@ dependent @*/ gpointer qof_object_lookup_backend (QofIdTypeConst type_name,
/*@ dependent @*/
gpointer qof_object_lookup_backend (QofIdTypeConst type_name,
const char *backend_name);
void qof_object_foreach_backend (const char *backend_name,

View File

@ -207,79 +207,91 @@ SIMPLE_PRED_HANDLER (qof_query_pred_double_from_xml,
double,
GET_DBL,
"qofquery:double",
qof_query_double_predicate);
qof_query_double_predicate);
SIMPLE_PRED_HANDLER (qof_query_pred_int64_from_xml,
gint64,
GET_INT64,
"qofquery:int64",
qof_query_int64_predicate);
qof_query_int64_predicate);
SIMPLE_PRED_HANDLER (qof_query_pred_int32_from_xml,
gint32,
GET_INT32,
"qofquery:int32",
qof_query_int32_predicate);
qof_query_int32_predicate);
SIMPLE_PRED_HANDLER (qof_query_pred_boolean_from_xml,
gboolean,
GET_BOOL,
"qofquery:boolean",
qof_query_boolean_predicate);
qof_query_boolean_predicate);
/* =============================================================== */
static void wrap_new_gint64(KvpValue **v, gint64 value) {
*v = kvp_value_new_gint64 (value); }
static void wrap_new_double(KvpValue **v, double value) {
*v = kvp_value_new_double (value); }
static void wrap_new_numeric(KvpValue **v, gnc_numeric value) {
*v = kvp_value_new_gnc_numeric (value); }
static void wrap_new_string(KvpValue **v, const char * value) {
*v = kvp_value_new_string (value); }
static void wrap_new_guid(KvpValue **v, const GUID * value) {
*v = kvp_value_new_guid (value); }
static void wrap_new_timespec(KvpValue **v, Timespec value) {
*v = kvp_value_new_timespec (value); }
static void wrap_new_gint64(KvpValue **v, gint64 value)
{
*v = kvp_value_new_gint64 (value);
}
static void wrap_new_double(KvpValue **v, double value)
{
*v = kvp_value_new_double (value);
}
static void wrap_new_numeric(KvpValue **v, gnc_numeric value)
{
*v = kvp_value_new_gnc_numeric (value);
}
static void wrap_new_string(KvpValue **v, const char * value)
{
*v = kvp_value_new_string (value);
}
static void wrap_new_guid(KvpValue **v, const GUID * value)
{
*v = kvp_value_new_guid (value);
}
static void wrap_new_timespec(KvpValue **v, Timespec value)
{
*v = kvp_value_new_timespec (value);
}
static QofQueryPredData *
qof_query_pred_kvp_from_xml (xmlNodePtr root)
{
QofQueryCompare how;
GSList *path;
KvpValue *value;
QofQueryPredData *pred;
xmlNodePtr xp;
xmlNodePtr node;
QofQueryCompare how;
GSList *path;
KvpValue *value;
QofQueryPredData *pred;
xmlNodePtr xp;
xmlNodePtr node;
how = QOF_COMPARE_EQUAL;
xp = root->xmlChildrenNode;
path = NULL;
value = NULL;
how = QOF_COMPARE_EQUAL;
xp = root->xmlChildrenNode;
path = NULL;
value = NULL;
for (node=xp; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
for (node = xp; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
GET_HOW (how, "qofquery:compare", LT, LTE, EQUAL, GT, GTE, NEQ);
if (0 == strcmp ("qofquery:kvp-path", node->name))
{
const char *str = GET_TEXT (node);
path = g_slist_append (path, (gpointer) str);
}
else
GET_INT64(&value, wrap_new_gint64, "qofquery:int64");
GET_DBL(&value, wrap_new_double, "qofquery:double");
GET_NUMERIC(&value, wrap_new_numeric, "qofquery:numeric");
GET_STR(&value, wrap_new_string, "qofquery:string");
GET_GUID(&value, wrap_new_guid, "qofquery:guid");
GET_DATE(&value, wrap_new_timespec, "qofquery:date");
}
GET_HOW (how, "qofquery:compare", LT, LTE, EQUAL, GT, GTE, NEQ);
if (0 == strcmp ("qofquery:kvp-path", node->name))
{
const char *str = GET_TEXT (node);
path = g_slist_append (path, (gpointer) str);
}
else
GET_INT64(&value, wrap_new_gint64, "qofquery:int64");
GET_DBL(&value, wrap_new_double, "qofquery:double");
GET_NUMERIC(&value, wrap_new_numeric, "qofquery:numeric");
GET_STR(&value, wrap_new_string, "qofquery:string");
GET_GUID(&value, wrap_new_guid, "qofquery:guid");
GET_DATE(&value, wrap_new_timespec, "qofquery:date");
}
pred = qof_query_kvp_predicate (how, path, value);
g_slist_free (path);
return pred;
pred = qof_query_kvp_predicate (how, path, value);
g_slist_free (path);
return pred;
}
/* =============================================================== */
@ -287,52 +299,52 @@ qof_query_pred_kvp_from_xml (xmlNodePtr root)
static QofQueryPredData *
qof_query_pred_guid_from_xml (xmlNodePtr root)
{
GList *guid_list, *n;
const char *str;
GUID *guid;
gboolean decode;
QofQueryPredData *pred;
QofGuidMatch sm;
xmlNodePtr xp;
xmlNodePtr node;
guid_list = NULL;
GList *guid_list, *n;
const char *str;
GUID *guid;
gboolean decode;
QofQueryPredData *pred;
QofGuidMatch sm;
xmlNodePtr xp;
xmlNodePtr node;
guid_list = NULL;
sm = QOF_GUID_MATCH_ANY;
xp = root->xmlChildrenNode;
for (node=xp; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
sm = QOF_GUID_MATCH_ANY;
xp = root->xmlChildrenNode;
for (node = xp; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
/* char pred doesn't have GET_HOW */
GET_MATCH5 (sm, "qofquery:guid-match",
GUID_MATCH, ANY, NONE, NULL, ALL, LIST_ANY);
/* char pred doesn't have GET_HOW */
GET_MATCH5 (sm, "qofquery:guid-match",
GUID_MATCH, ANY, NONE, NULL, ALL, LIST_ANY);
if (0 == strcmp ("qofquery:guid", node->name))
{
str = GET_TEXT (node);
guid = guid_malloc ();
decode = string_to_guid (str, guid);
if (decode)
{
guid_list = g_list_append (guid_list, guid);
}
else
{
guid_free (guid);
// XXX error! let someone know!
}
}
}
if (0 == strcmp ("qofquery:guid", node->name))
{
str = GET_TEXT (node);
guid = guid_malloc ();
decode = string_to_guid (str, guid);
if (decode)
{
guid_list = g_list_append (guid_list, guid);
}
else
{
guid_free (guid);
// XXX error! let someone know!
}
}
}
pred = qof_query_guid_predicate (sm, guid_list);
pred = qof_query_guid_predicate (sm, guid_list);
/* The predicate made a copy of everything, so free our stuff */
for (n=guid_list; n; n=n->next)
{
guid_free (n->data);
}
g_list_free (guid_list);
return pred;
/* The predicate made a copy of everything, so free our stuff */
for (n = guid_list; n; n = n->next)
{
guid_free (n->data);
}
g_list_free (guid_list);
return pred;
}
/* =============================================================== */
@ -340,29 +352,29 @@ qof_query_pred_guid_from_xml (xmlNodePtr root)
static QofQueryPredData *
qof_query_pred_char_from_xml (xmlNodePtr root)
{
QofQueryPredData *pred;
QofCharMatch sm;
const char * char_list;
xmlNodePtr xp;
xmlNodePtr node;
QofQueryPredData *pred;
QofCharMatch sm;
const char * char_list;
xmlNodePtr xp;
xmlNodePtr node;
char_list = NULL;
xp = root->xmlChildrenNode;
sm = QOF_CHAR_MATCH_ANY;
xp = root->xmlChildrenNode;
sm = QOF_CHAR_MATCH_ANY;
for (node=xp; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
for (node = xp; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
/* char pred doesn't have GET_HOW */
GET_MATCH2 (sm, "qofquery:char-match",
CHAR_MATCH, ANY, NONE);
GET_STR (0, char_list=, "qofquery:char-list");
{}
}
/* char pred doesn't have GET_HOW */
GET_MATCH2 (sm, "qofquery:char-match",
CHAR_MATCH, ANY, NONE);
GET_STR (0, char_list = , "qofquery:char-list");
{}
}
pred = qof_query_char_predicate (sm, char_list);
return pred;
pred = qof_query_char_predicate (sm, char_list);
return pred;
}
/* =============================================================== */
@ -370,30 +382,30 @@ qof_query_pred_char_from_xml (xmlNodePtr root)
static QofQueryPredData *
qof_query_pred_numeric_from_xml (xmlNodePtr root)
{
QofQueryPredData *pred;
xmlNodePtr node;
QofQueryCompare how;
QofNumericMatch sm;
gnc_numeric num;
xmlNodePtr xp;
xp = root->xmlChildrenNode;
how = QOF_COMPARE_EQUAL;
sm = QOF_NUMERIC_MATCH_ANY;
QofQueryPredData *pred;
xmlNodePtr node;
QofQueryCompare how;
QofNumericMatch sm;
gnc_numeric num;
xmlNodePtr xp;
for (node=xp; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
xp = root->xmlChildrenNode;
how = QOF_COMPARE_EQUAL;
sm = QOF_NUMERIC_MATCH_ANY;
GET_HOW (how, "qofquery:compare", LT, LTE, EQUAL, GT, GTE, NEQ);
GET_MATCH3 (sm, "qofquery:numeric-match",
NUMERIC_MATCH, DEBIT, CREDIT, ANY);
GET_NUMERIC (0, num=, "qofquery:numeric");
{}
}
for (node = xp; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
pred = qof_query_numeric_predicate (how, sm, num);
return pred;
GET_HOW (how, "qofquery:compare", LT, LTE, EQUAL, GT, GTE, NEQ);
GET_MATCH3 (sm, "qofquery:numeric-match",
NUMERIC_MATCH, DEBIT, CREDIT, ANY);
GET_NUMERIC (0, num = , "qofquery:numeric");
{}
}
pred = qof_query_numeric_predicate (how, sm, num);
return pred;
}
/* =============================================================== */
@ -401,32 +413,35 @@ qof_query_pred_numeric_from_xml (xmlNodePtr root)
static QofQueryPredData *
qof_query_pred_date_from_xml (xmlNodePtr root)
{
xmlNodePtr xp;
xmlNodePtr node;
QofQueryCompare how;
QofDateMatch sm;
Timespec date;
QofQueryPredData *pred;
xp = root->xmlChildrenNode;
xmlNodePtr xp;
xmlNodePtr node;
QofQueryCompare how;
QofDateMatch sm;
Timespec date;
QofQueryPredData *pred;
how = QOF_COMPARE_EQUAL;
sm = QOF_DATE_MATCH_DAY;
date = (Timespec){0,0};
xp = root->xmlChildrenNode;
for (node=xp; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
how = QOF_COMPARE_EQUAL;
sm = QOF_DATE_MATCH_DAY;
date = (Timespec)
{
0, 0
};
GET_HOW (how, "qofquery:compare", LT, LTE, EQUAL, GT, GTE, NEQ);
GET_MATCH2 (sm, "qofquery:date-match",
DATE_MATCH, NORMAL, DAY);
GET_DATE (0, date=, "qofquery:date");
{}
}
for (node = xp; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
pred = qof_query_date_predicate (how, sm, date);
return pred;
GET_HOW (how, "qofquery:compare", LT, LTE, EQUAL, GT, GTE, NEQ);
GET_MATCH2 (sm, "qofquery:date-match",
DATE_MATCH, NORMAL, DAY);
GET_DATE (0, date = , "qofquery:date");
{}
}
pred = qof_query_date_predicate (how, sm, date);
return pred;
}
/* =============================================================== */
@ -434,194 +449,183 @@ qof_query_pred_date_from_xml (xmlNodePtr root)
static QofQueryPredData *
qof_query_pred_string_from_xml (xmlNodePtr root)
{
QofQueryPredData *pred;
xmlNodePtr xp;
xmlNodePtr node;
QofQueryCompare how;
QofStringMatch sm;
gboolean is_regex;
const char *pstr;
xp = root->xmlChildrenNode;
how = QOF_COMPARE_EQUAL;
sm = QOF_STRING_MATCH_CASEINSENSITIVE;
is_regex = FALSE;
pstr = NULL;
QofQueryPredData *pred;
xmlNodePtr xp;
xmlNodePtr node;
QofQueryCompare how;
QofStringMatch sm;
gboolean is_regex;
const char *pstr;
for (node=xp; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
xp = root->xmlChildrenNode;
how = QOF_COMPARE_EQUAL;
sm = QOF_STRING_MATCH_CASEINSENSITIVE;
is_regex = FALSE;
pstr = NULL;
GET_HOW (how, "qofquery:compare", LT, LTE, EQUAL, GT, GTE, NEQ);
GET_BOOL (0, is_regex=, "qofquery:is-regex");
GET_STR (0, pstr=, "qofquery:string");
GET_MATCH2 (sm, "qofquery:string-match",
STRING_MATCH, NORMAL, CASEINSENSITIVE);
{}
}
pred = qof_query_string_predicate (how, pstr, sm , is_regex);
return pred;
for (node = xp; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
GET_HOW (how, "qofquery:compare", LT, LTE, EQUAL, GT, GTE, NEQ);
GET_BOOL (0, is_regex = , "qofquery:is-regex");
GET_STR (0, pstr = , "qofquery:string");
GET_MATCH2 (sm, "qofquery:string-match",
STRING_MATCH, NORMAL, CASEINSENSITIVE);
{}
}
pred = qof_query_string_predicate (how, pstr, sm , is_regex);
return pred;
}
/* =============================================================== */
static GSList *
static GSList *
qof_query_param_path_from_xml (xmlNodePtr root)
{
xmlNodePtr pterms;
GSList *plist;
xmlNodePtr node;
xmlNodePtr pterms;
GSList *plist;
xmlNodePtr node;
pterms = root->xmlChildrenNode;
plist = NULL;
for (node=pterms; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
pterms = root->xmlChildrenNode;
plist = NULL;
for (node = pterms; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
if (0 == strcmp (node->name, "qofquery:param"))
{
const char *str = GET_TEXT (node);
plist = g_slist_append (plist, CACHE_INSERT(str));
}
}
return plist;
if (0 == strcmp (node->name, "qofquery:param"))
{
const char *str = GET_TEXT (node);
plist = g_slist_append (plist, CACHE_INSERT(str));
}
}
return plist;
}
/* =============================================================== */
static void
static void
qof_query_term_from_xml (QofQuery *q, xmlNodePtr root)
{
xmlNodePtr node;
xmlNodePtr term;
QofQueryPredData *pred;
GSList *path;
QofQuery *qt;
QofQuery *qinv;
pred = NULL;
path = NULL;
term = root->xmlChildrenNode;
for (node=term; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
if (0 == strcmp (node->name, "qofquery:invert"))
{
qt = qof_query_create();
qof_query_term_from_xml (qt, node);
qinv = qof_query_invert (qt);
qof_query_merge_in_place (q, qinv, QOF_QUERY_AND);
qof_query_destroy (qinv);
qof_query_destroy (qt);
return;
}
else
if (0 == strcmp (node->name, "qofquery:param-path"))
{
path = qof_query_param_path_from_xml (node);
}
else
if (0 == strcmp (node->name, "qofquery:pred-string"))
{
pred = qof_query_pred_string_from_xml (node);
}
else
if (0 == strcmp (node->name, "qofquery:pred-date"))
{
pred = qof_query_pred_date_from_xml (node);
}
else
if (0 == strcmp (node->name, "qofquery:pred-numeric"))
{
pred = qof_query_pred_numeric_from_xml (node);
}
else
if (0 == strcmp (node->name, "qofquery:pred-int32"))
{
pred = qof_query_pred_int32_from_xml (node);
}
else
if (0 == strcmp (node->name, "qofquery:pred-int64"))
{
pred = qof_query_pred_int64_from_xml (node);
}
else
if (0 == strcmp (node->name, "qofquery:pred-double"))
{
pred = qof_query_pred_double_from_xml (node);
}
else
if (0 == strcmp (node->name, "qofquery:pred-boolean"))
{
pred = qof_query_pred_boolean_from_xml (node);
}
else
if (0 == strcmp (node->name, "qofquery:pred-char"))
{
pred = qof_query_pred_char_from_xml (node);
}
else
if (0 == strcmp (node->name, "qofquery:pred-guid"))
{
pred = qof_query_pred_guid_from_xml (node);
}
else
if (0 == strcmp (node->name, "qofquery:pred-kvp"))
{
pred = qof_query_pred_kvp_from_xml (node);
}
else
{
// warning unhandled predicate type
}
}
xmlNodePtr node;
xmlNodePtr term;
QofQueryPredData *pred;
GSList *path;
QofQuery *qt;
QofQuery *qinv;
/* At this level, the terms should always be anded */
qof_query_add_term (q, path, pred, QOF_QUERY_AND);
pred = NULL;
path = NULL;
term = root->xmlChildrenNode;
for (node = term; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
if (0 == strcmp (node->name, "qofquery:invert"))
{
qt = qof_query_create();
qof_query_term_from_xml (qt, node);
qinv = qof_query_invert (qt);
qof_query_merge_in_place (q, qinv, QOF_QUERY_AND);
qof_query_destroy (qinv);
qof_query_destroy (qt);
return;
}
else if (0 == strcmp (node->name, "qofquery:param-path"))
{
path = qof_query_param_path_from_xml (node);
}
else if (0 == strcmp (node->name, "qofquery:pred-string"))
{
pred = qof_query_pred_string_from_xml (node);
}
else if (0 == strcmp (node->name, "qofquery:pred-date"))
{
pred = qof_query_pred_date_from_xml (node);
}
else if (0 == strcmp (node->name, "qofquery:pred-numeric"))
{
pred = qof_query_pred_numeric_from_xml (node);
}
else if (0 == strcmp (node->name, "qofquery:pred-int32"))
{
pred = qof_query_pred_int32_from_xml (node);
}
else if (0 == strcmp (node->name, "qofquery:pred-int64"))
{
pred = qof_query_pred_int64_from_xml (node);
}
else if (0 == strcmp (node->name, "qofquery:pred-double"))
{
pred = qof_query_pred_double_from_xml (node);
}
else if (0 == strcmp (node->name, "qofquery:pred-boolean"))
{
pred = qof_query_pred_boolean_from_xml (node);
}
else if (0 == strcmp (node->name, "qofquery:pred-char"))
{
pred = qof_query_pred_char_from_xml (node);
}
else if (0 == strcmp (node->name, "qofquery:pred-guid"))
{
pred = qof_query_pred_guid_from_xml (node);
}
else if (0 == strcmp (node->name, "qofquery:pred-kvp"))
{
pred = qof_query_pred_kvp_from_xml (node);
}
else
{
// warning unhandled predicate type
}
}
/* At this level, the terms should always be anded */
qof_query_add_term (q, path, pred, QOF_QUERY_AND);
}
/* =============================================================== */
static void
static void
qof_query_and_terms_from_xml (QofQuery *q, xmlNodePtr root)
{
xmlNodePtr andterms;
xmlNodePtr node;
andterms = root->xmlChildrenNode;
for (node=andterms; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
xmlNodePtr andterms;
xmlNodePtr node;
if (0 == strcmp (node->name, "qofquery:term"))
{
qof_query_term_from_xml (q, node);
}
}
andterms = root->xmlChildrenNode;
for (node = andterms; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
if (0 == strcmp (node->name, "qofquery:term"))
{
qof_query_term_from_xml (q, node);
}
}
}
/* =============================================================== */
static void
static void
qof_query_or_terms_from_xml (QofQuery *q, xmlNodePtr root)
{
xmlNodePtr andterms;
xmlNodePtr node;
QofQuery *qand;
xmlNodePtr andterms;
xmlNodePtr node;
QofQuery *qand;
andterms = root->xmlChildrenNode;
for (node=andterms; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
andterms = root->xmlChildrenNode;
for (node = andterms; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
if (0 == strcmp (node->name, "qofquery:and-terms"))
{
qand = qof_query_create ();
qof_query_and_terms_from_xml (qand, node);
qof_query_merge_in_place (q, qand, QOF_QUERY_OR);
qof_query_destroy (qand);
}
}
if (0 == strcmp (node->name, "qofquery:and-terms"))
{
qand = qof_query_create ();
qof_query_and_terms_from_xml (qand, node);
qof_query_merge_in_place (q, qand, QOF_QUERY_OR);
qof_query_destroy (qand);
}
}
}
/* =============================================================== */
@ -629,45 +633,44 @@ qof_query_or_terms_from_xml (QofQuery *q, xmlNodePtr root)
QofQuery *
qof_query_from_xml (xmlNodePtr root)
{
QofQuery *q;
xmlChar *version;
xmlNodePtr qpart;
xmlNodePtr node;
if (!root) return NULL;
version = xmlGetProp(root, "version");
QofQuery *q;
xmlChar *version;
xmlNodePtr qpart;
xmlNodePtr node;
if (!root) return NULL;
version = xmlGetProp(root, "version");
if (!root->name || strcmp ("qof:qofquery", root->name))
{
// XXX something is wrong. warn ...
return NULL;
// XXX something is wrong. warn ...
return NULL;
}
q = qof_query_create ();
q = qof_query_create ();
qpart = root->xmlChildrenNode;
for (node=qpart; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
qpart = root->xmlChildrenNode;
for (node = qpart; node; node = node->next)
{
if (node->type != XML_ELEMENT_NODE) continue;
GET_STR (q, qof_query_search_for, "qofquery:search-for");
GET_INT32 (q, qof_query_set_max_results, "qofquery:max-results");
if (0 == strcmp (node->name, "qofquery:or-terms"))
{
qof_query_or_terms_from_xml (q, node);
}
else
if (0 == strcmp (node->name, "qofquery:sort-list"))
{
GET_STR (q, qof_query_search_for, "qofquery:search-for");
GET_INT32 (q, qof_query_set_max_results, "qofquery:max-results");
if (0 == strcmp (node->name, "qofquery:or-terms"))
{
qof_query_or_terms_from_xml (q, node);
}
else if (0 == strcmp (node->name, "qofquery:sort-list"))
{
// XXX unfinished I'm bored
}
else
{
// XXX unknown node type tell someone about it
}
}
}
else
{
// XXX unknown node type tell someone about it
}
}
return q;
return q;
}
/* =============================================================== */
@ -679,78 +682,79 @@ qof_query_from_xml (xmlNodePtr root)
int main (int argc, char * argv[])
{
QofQuery *q, *qnew;
QofSqlQuery *sq;
xmlNodePtr topnode;
QofQuery *q, *qnew;
QofSqlQuery *sq;
xmlNodePtr topnode;
guid_init();
qof_query_init();
qof_object_initialize ();
guid_init();
qof_query_init();
qof_object_initialize ();
static QofParam params[] = {
{ "adate", QOF_TYPE_DATE, NULL, NULL},
{ "aint", QOF_TYPE_INT32, NULL, NULL},
{ "aint64", QOF_TYPE_INT64, NULL, NULL},
{ "aflt", QOF_TYPE_DOUBLE, NULL, NULL},
{ "abool", QOF_TYPE_BOOLEAN, NULL, NULL},
{ "astr", QOF_TYPE_STRING, NULL, NULL},
{ "adate", QOF_TYPE_DATE, NULL, NULL},
{ "anum", QOF_TYPE_NUMERIC, NULL, NULL},
{ "achar", QOF_TYPE_CHAR, NULL, NULL},
{ "aguid", QOF_TYPE_GUID, NULL, NULL},
{ "akvp", QOF_TYPE_KVP, NULL, NULL},
{ NULL },
};
static QofParam params[] =
{
{ "adate", QOF_TYPE_DATE, NULL, NULL},
{ "aint", QOF_TYPE_INT32, NULL, NULL},
{ "aint64", QOF_TYPE_INT64, NULL, NULL},
{ "aflt", QOF_TYPE_DOUBLE, NULL, NULL},
{ "abool", QOF_TYPE_BOOLEAN, NULL, NULL},
{ "astr", QOF_TYPE_STRING, NULL, NULL},
{ "adate", QOF_TYPE_DATE, NULL, NULL},
{ "anum", QOF_TYPE_NUMERIC, NULL, NULL},
{ "achar", QOF_TYPE_CHAR, NULL, NULL},
{ "aguid", QOF_TYPE_GUID, NULL, NULL},
{ "akvp", QOF_TYPE_KVP, NULL, NULL},
{ NULL },
};
qof_class_register ("GncABC", NULL, params);
sq = qof_sql_query_new();
qof_class_register ("GncABC", NULL, params);
sq = qof_sql_query_new();
qof_sql_query_parse (sq,
"SELECT * from GncABC WHERE aint = 123 "
"and not aint64 = 6123123456789 "
"or abool = TRUE "
"and not aflt >= \'3.14159265358979\' "
"and not astr=\'asdf\' "
"and adate<\'01-01-01\' "
"or anum<\'12301/100\' "
"or achar != asdf "
"and aguid != abcdef01234567890fedcba987654321 "
"and akvp != \'/some/path:abcdef01234567890fedcba987654321\' "
"and not akvp != \'/some/path/glop:1234\' "
"and akvp = \'/arf/arf/arf:10.234\' "
"and akvp != \'/some/other/path:qwerty1234uiop\' "
"and not akvp = \'/some/final/path:123401/100\' "
);
// qof_sql_query_parse (sq, "SELECT * from GncABC;");
q = qof_sql_query_get_query (sq);
qof_sql_query_parse (sq,
"SELECT * from GncABC WHERE aint = 123 "
"and not aint64 = 6123123456789 "
"or abool = TRUE "
"and not aflt >= \'3.14159265358979\' "
"and not astr=\'asdf\' "
"and adate<\'01-01-01\' "
"or anum<\'12301/100\' "
"or achar != asdf "
"and aguid != abcdef01234567890fedcba987654321 "
"and akvp != \'/some/path:abcdef01234567890fedcba987654321\' "
"and not akvp != \'/some/path/glop:1234\' "
"and akvp = \'/arf/arf/arf:10.234\' "
"and akvp != \'/some/other/path:qwerty1234uiop\' "
"and not akvp = \'/some/final/path:123401/100\' "
);
// qof_sql_query_parse (sq, "SELECT * from GncABC;");
q = qof_sql_query_get_query (sq);
qof_query_print (q);
qof_query_print (q);
xmlNodePtr topnode = qof_query_to_xml (q);
xmlNodePtr topnode = qof_query_to_xml (q);
qnew = qof_query_from_xml (topnode);
printf (" ------------------------------------------------------- \n");
qof_query_print (qnew);
qnew = qof_query_from_xml (topnode);
printf (" ------------------------------------------------------- \n");
qof_query_print (qnew);
/* If the before and after trees are the same, the test pases. */
gboolean eq = qof_query_equal (q, qnew);
printf ("Are the two equal? answer=%d\n", eq);
/* If the before and after trees are the same, the test pases. */
gboolean eq = qof_query_equal (q, qnew);
printf ("Are the two equal? answer=%d\n", eq);
#define DOPRINT 1
#ifdef DOPRINT
xmlDocPtr doc = doc = xmlNewDoc("1.0");
xmlDocSetRootElement(doc,topnode);
xmlDocPtr doc = doc = xmlNewDoc("1.0");
xmlDocSetRootElement(doc, topnode);
xmlChar *xbuf;
int bufsz;
xmlDocDumpFormatMemory (doc, &xbuf, &bufsz, 1);
xmlChar *xbuf;
int bufsz;
xmlDocDumpFormatMemory (doc, &xbuf, &bufsz, 1);
printf ("%s\n", xbuf);
xmlFree (xbuf);
xmlFreeDoc(doc);
printf ("%s\n", xbuf);
xmlFree (xbuf);
xmlFreeDoc(doc);
#endif
return 0;
return 0;
}
#endif /* UNIT_TEST */

View File

@ -20,9 +20,9 @@
* Boston, MA 02110-1301, USA gnu@gnu.org *
* *
\********************************************************************/
/*
/*
qofquery-deserial.h
Convert Qof-Query XML to QofQuery
Convert Qof-Query XML to QofQuery
author Copyright (C) 2004 Linas Vepstas <linas@linas.org>
*/
@ -38,7 +38,7 @@ author Copyright (C) 2004 Linas Vepstas <linas@linas.org>
routine needed to convert the XML back into a C struct.
Unfinished. XXX Why is this easier than reading a text/sql
file?
file?
NOTE: Development of this idea has ceased and this file is
no longer included in the QOF library. It remains in CVS for now.

View File

@ -43,10 +43,13 @@ int qof_query_get_max_results (const QofQuery *q);
* Note that you should NOT modify this list in any way. It belongs
* to the query.
*/
/*@ dependent @*/ GList * qof_query_get_terms (const QofQuery *q);
/*@ dependent @*/
GList * qof_query_get_terms (const QofQuery *q);
/*@ dependent @*/ GSList * qof_query_term_get_param_path (const QofQueryTerm *queryterm);
/*@ dependent @*/ QofQueryPredData *qof_query_term_get_pred_data (const QofQueryTerm *queryterm);
/*@ dependent @*/
GSList * qof_query_term_get_param_path (const QofQueryTerm *queryterm);
/*@ dependent @*/
QofQueryPredData *qof_query_term_get_pred_data (const QofQueryTerm *queryterm);
gboolean qof_query_term_is_inverted (const QofQueryTerm *queryterm);
@ -56,9 +59,10 @@ gboolean qof_query_term_is_inverted (const QofQueryTerm *queryterm);
* These are part of the query and should NOT be changed!
*/
void qof_query_get_sorts (QofQuery *q, QofQuerySort **primary,
QofQuerySort **secondary, QofQuerySort **tertiary);
QofQuerySort **secondary, QofQuerySort **tertiary);
/*@ dependent @*/ GSList * qof_query_sort_get_param_path (const QofQuerySort *querysort);
/*@ dependent @*/
GSList * qof_query_sort_get_param_path (const QofQuerySort *querysort);
gint qof_query_sort_get_sort_options (const QofQuerySort *querysort);
gboolean qof_query_sort_get_increasing (const QofQuerySort *querysort);

View File

@ -176,34 +176,34 @@ no longer included in the QOF library. It remains in CVS for now.*/
static void
qof_kvp_value_to_xml (KvpValue *kval, xmlNodePtr topnode)
{
KvpValueType kvt = kvp_value_get_type (kval);
KvpValueType kvt = kvp_value_get_type (kval);
switch (kvt)
{
case KVP_TYPE_GINT64:
PUT_INT64 ("qofquery:int64", kvp_value_get_gint64(kval));
break;
case KVP_TYPE_DOUBLE:
PUT_DBL ("qofquery:double", kvp_value_get_double(kval));
break;
case KVP_TYPE_NUMERIC:
PUT_NUMERIC ("qofquery:numeric", kvp_value_get_numeric(kval));
break;
case KVP_TYPE_GUID:
PUT_GUID ("qofquery:guid", kvp_value_get_guid(kval));
break;
case KVP_TYPE_STRING:
PUT_STR ("qofquery:string", kvp_value_get_string(kval));
break;
case KVP_TYPE_TIMESPEC:
PUT_DATE ("qofquery:date", kvp_value_get_timespec(kval));
break;
case KVP_TYPE_BINARY:
case KVP_TYPE_GLIST:
case KVP_TYPE_FRAME:
// XXX don't know how to support these.
break;
}
switch (kvt)
{
case KVP_TYPE_GINT64:
PUT_INT64 ("qofquery:int64", kvp_value_get_gint64(kval));
break;
case KVP_TYPE_DOUBLE:
PUT_DBL ("qofquery:double", kvp_value_get_double(kval));
break;
case KVP_TYPE_NUMERIC:
PUT_NUMERIC ("qofquery:numeric", kvp_value_get_numeric(kval));
break;
case KVP_TYPE_GUID:
PUT_GUID ("qofquery:guid", kvp_value_get_guid(kval));
break;
case KVP_TYPE_STRING:
PUT_STR ("qofquery:string", kvp_value_get_string(kval));
break;
case KVP_TYPE_TIMESPEC:
PUT_DATE ("qofquery:date", kvp_value_get_timespec(kval));
break;
case KVP_TYPE_BINARY:
case KVP_TYPE_GLIST:
case KVP_TYPE_FRAME:
// XXX don't know how to support these.
break;
}
}
/* ======================================================= */
@ -211,137 +211,137 @@ qof_kvp_value_to_xml (KvpValue *kval, xmlNodePtr topnode)
static xmlNodePtr
qof_query_pred_data_to_xml (QofQueryPredData *pd)
{
GList *n;
GSList *ns;
xmlNodePtr topnode;
query_guid_t pdata_g;
query_string_t pdata_s;
query_numeric_t pdata_n;
query_kvp_t pdata_k;
query_date_t pdata_d;
query_int64_t pdata_i64;
query_int32_t pdata_i32;
query_double_t pdata_db;
query_boolean_t pdata_bool;
query_char_t pdata_c;
if (!safe_strcmp (pd->type_name, QOF_TYPE_GUID))
{
topnode = xmlNewNode (NULL, "qofquery:pred-guid");
/* GUID Predicate doesn't do a PUT_HOW */
GList *n;
GSList *ns;
xmlNodePtr topnode;
query_guid_t pdata_g;
query_string_t pdata_s;
query_numeric_t pdata_n;
query_kvp_t pdata_k;
query_date_t pdata_d;
query_int64_t pdata_i64;
query_int32_t pdata_i32;
query_double_t pdata_db;
query_boolean_t pdata_bool;
query_char_t pdata_c;
pdata_g = (query_guid_t) pd;
PUT_MATCH5("qofquery:guid-match", pdata_g->options,
GUID_MATCH, ANY, ALL, NONE, NULL, LIST_ANY);
if (!safe_strcmp (pd->type_name, QOF_TYPE_GUID))
{
topnode = xmlNewNode (NULL, "qofquery:pred-guid");
/* GUID Predicate doesn't do a PUT_HOW */
for (n = pdata_g->guids; n; n = n->next)
{
PUT_GUID ("qofquery:guid", n->data);
}
return topnode;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_STRING))
{
topnode = xmlNewNode (NULL, "qofquery:pred-string");
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
pdata_g = (query_guid_t) pd;
PUT_MATCH5("qofquery:guid-match", pdata_g->options,
GUID_MATCH, ANY, ALL, NONE, NULL, LIST_ANY);
pdata_s = (query_string_t) pd;
PUT_MATCH2("qofquery:string-match", pdata_s->options,
STRING_MATCH, NORMAL, CASEINSENSITIVE);
PUT_BOOL ("qofquery:is-regex", pdata_s->is_regex);
PUT_STR ("qofquery:string", pdata_s->matchstring);
return topnode;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_NUMERIC))
{
topnode = xmlNewNode (NULL, "qofquery:pred-numeric");
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
for (n = pdata_g->guids; n; n = n->next)
{
PUT_GUID ("qofquery:guid", n->data);
}
return topnode;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_STRING))
{
topnode = xmlNewNode (NULL, "qofquery:pred-string");
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
pdata_n = (query_numeric_t) pd;
PUT_MATCH3("qofquery:numeric-match", pdata_n->options,
NUMERIC_MATCH, DEBIT, CREDIT, ANY);
PUT_NUMERIC ("qofquery:numeric", pdata_n->amount);
return topnode;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_KVP))
{
topnode = xmlNewNode (NULL, "qofquery:pred-kvp");
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
pdata_s = (query_string_t) pd;
PUT_MATCH2("qofquery:string-match", pdata_s->options,
STRING_MATCH, NORMAL, CASEINSENSITIVE);
PUT_BOOL ("qofquery:is-regex", pdata_s->is_regex);
PUT_STR ("qofquery:string", pdata_s->matchstring);
return topnode;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_NUMERIC))
{
topnode = xmlNewNode (NULL, "qofquery:pred-numeric");
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
pdata_k = (query_kvp_t) pd;
for (ns=pdata_k->path; ns; ns=ns->next)
{
PUT_STR ("qofquery:kvp-path", ns->data);
}
qof_kvp_value_to_xml (pdata_k->value, topnode);
return topnode;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_DATE))
{
topnode = xmlNewNode (NULL, "qofquery:pred-date");
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
pdata_n = (query_numeric_t) pd;
PUT_MATCH3("qofquery:numeric-match", pdata_n->options,
NUMERIC_MATCH, DEBIT, CREDIT, ANY);
pdata_d = (query_date_t) pd;
PUT_MATCH2("qofquery:date-match", pdata_d->options,
DATE_MATCH, NORMAL, DAY);
PUT_NUMERIC ("qofquery:numeric", pdata_n->amount);
return topnode;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_KVP))
{
topnode = xmlNewNode (NULL, "qofquery:pred-kvp");
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
PUT_DATE ("qofquery:date", pdata_d->date);
return topnode;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_INT64))
{
topnode = xmlNewNode (NULL, "qofquery:pred-int64");
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
pdata_k = (query_kvp_t) pd;
for (ns = pdata_k->path; ns; ns = ns->next)
{
PUT_STR ("qofquery:kvp-path", ns->data);
}
qof_kvp_value_to_xml (pdata_k->value, topnode);
return topnode;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_DATE))
{
topnode = xmlNewNode (NULL, "qofquery:pred-date");
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
pdata_i64 = (query_int64_t) pd;
PUT_INT64 ("qofquery:int64", pdata_i64->val);
return topnode;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_INT32))
{
topnode = xmlNewNode (NULL, "qofquery:pred-int32");
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
pdata_d = (query_date_t) pd;
pdata_i32 = (query_int32_t) pd;
PUT_INT32 ("qofquery:int32", pdata_i32->val);
return topnode;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_DOUBLE))
{
topnode = xmlNewNode (NULL, "qofquery:pred-double");
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
PUT_MATCH2("qofquery:date-match", pdata_d->options,
DATE_MATCH, NORMAL, DAY);
pdata_db = (query_double_t) pd;
PUT_DBL ("qofquery:double", pdata_db->val);
return topnode;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_BOOLEAN))
{
topnode = xmlNewNode (NULL, "qofquery:pred-boolean");
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
PUT_DATE ("qofquery:date", pdata_d->date);
return topnode;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_INT64))
{
topnode = xmlNewNode (NULL, "qofquery:pred-int64");
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
pdata_bool = (query_boolean_t) pd;
PUT_BOOL ("qofquery:boolean", pdata_bool->val);
return topnode;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_CHAR))
{
topnode = xmlNewNode (NULL, "qofquery:pred-char");
/* There is no PUT_HOW for char-match */
pdata_c = (query_char_t) pd;
PUT_MATCH2("qofquery:char-match", pdata_c->options,
CHAR_MATCH, ANY, NONE);
PUT_STR ("qofquery:char-list", pdata_c->char_list);
return topnode;
}
return NULL;
pdata_i64 = (query_int64_t) pd;
PUT_INT64 ("qofquery:int64", pdata_i64->val);
return topnode;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_INT32))
{
topnode = xmlNewNode (NULL, "qofquery:pred-int32");
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
pdata_i32 = (query_int32_t) pd;
PUT_INT32 ("qofquery:int32", pdata_i32->val);
return topnode;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_DOUBLE))
{
topnode = xmlNewNode (NULL, "qofquery:pred-double");
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
pdata_db = (query_double_t) pd;
PUT_DBL ("qofquery:double", pdata_db->val);
return topnode;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_BOOLEAN))
{
topnode = xmlNewNode (NULL, "qofquery:pred-boolean");
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
pdata_bool = (query_boolean_t) pd;
PUT_BOOL ("qofquery:boolean", pdata_bool->val);
return topnode;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_CHAR))
{
topnode = xmlNewNode (NULL, "qofquery:pred-char");
/* There is no PUT_HOW for char-match */
pdata_c = (query_char_t) pd;
PUT_MATCH2("qofquery:char-match", pdata_c->options,
CHAR_MATCH, ANY, NONE);
PUT_STR ("qofquery:char-list", pdata_c->char_list);
return topnode;
}
return NULL;
}
/* ======================================================= */
@ -349,19 +349,19 @@ qof_query_pred_data_to_xml (QofQueryPredData *pd)
static xmlNodePtr
qof_query_param_path_to_xml (GSList *param_path)
{
xmlNodePtr topnode;
GSList *n;
QofIdTypeConst path;
n = param_path;
topnode = xmlNewNode (NULL, "qofquery:param-path");
for ( ; n; n=n->next)
{
path = n->data;
if (!path) continue;
PUT_STR ("qofquery:param", path);
}
return topnode;
xmlNodePtr topnode;
GSList *n;
QofIdTypeConst path;
n = param_path;
topnode = xmlNewNode (NULL, "qofquery:param-path");
for ( ; n; n = n->next)
{
path = n->data;
if (!path) continue;
PUT_STR ("qofquery:param", path);
}
return topnode;
}
/* ======================================================= */
@ -369,32 +369,32 @@ qof_query_param_path_to_xml (GSList *param_path)
static xmlNodePtr
qof_query_one_term_to_xml (QofQueryTerm *qt)
{
xmlNodePtr node;
xmlNodePtr term;
xmlNodePtr topnode;
gboolean invert;
GSList *path;
QofQueryPredData *pd;
xmlNodePtr node;
xmlNodePtr term;
xmlNodePtr topnode;
gboolean invert;
GSList *path;
QofQueryPredData *pd;
invert = qof_query_term_is_inverted (qt);
term = xmlNewNode (NULL, "qofquery:term");
topnode = term;
path = qof_query_term_get_param_path (qt);
pd = qof_query_term_get_pred_data (qt);
if (invert)
{
/* inverter becomes new top mode */
topnode = xmlNewNode (NULL, "qofquery:invert");
xmlAddChild (term, topnode);
}
invert = qof_query_term_is_inverted (qt);
term = xmlNewNode (NULL, "qofquery:term");
topnode = term;
path = qof_query_term_get_param_path (qt);
pd = qof_query_term_get_pred_data (qt);
if (invert)
{
/* inverter becomes new top mode */
topnode = xmlNewNode (NULL, "qofquery:invert");
xmlAddChild (term, topnode);
}
node = qof_query_param_path_to_xml (path);
if (node) xmlAddChild (topnode, node);
node = qof_query_param_path_to_xml (path);
if (node) xmlAddChild (topnode, node);
node = qof_query_pred_data_to_xml (pd);
if (node) xmlAddChild (topnode, node);
node = qof_query_pred_data_to_xml (pd);
if (node) xmlAddChild (topnode, node);
return term;
return term;
}
/* ======================================================= */
@ -402,22 +402,22 @@ qof_query_one_term_to_xml (QofQueryTerm *qt)
static xmlNodePtr
qof_query_and_terms_to_xml (GList *and_terms)
{
xmlNodePtr terms;
GList *n;
QofQueryTerm *qt;
xmlNodePtr t;
terms = xmlNewNode (NULL, "qofquery:and-terms");
n = and_terms;
for ( ; n; n=n->next)
{
qt = n->data;
if (!qt) continue;
xmlNodePtr terms;
GList *n;
QofQueryTerm *qt;
xmlNodePtr t;
t = qof_query_one_term_to_xml (n->data);
if (t) xmlAddChild (terms, t);
}
return terms;
terms = xmlNewNode (NULL, "qofquery:and-terms");
n = and_terms;
for ( ; n; n = n->next)
{
qt = n->data;
if (!qt) continue;
t = qof_query_one_term_to_xml (n->data);
if (t) xmlAddChild (terms, t);
}
return terms;
}
/* ======================================================= */
@ -425,21 +425,21 @@ qof_query_and_terms_to_xml (GList *and_terms)
static xmlNodePtr
qof_query_terms_to_xml (QofQuery *q)
{
xmlNodePtr terms;
GList *n;
xmlNodePtr andt;
terms = NULL;
n = qof_query_get_terms (q);
if (!n) return NULL;
terms = xmlNewNode (NULL, "qofquery:or-terms");
xmlNodePtr terms;
GList *n;
xmlNodePtr andt;
for ( ; n; n=n->next)
{
andt = qof_query_and_terms_to_xml (n->data);
if (andt) xmlAddChild (terms, andt);
}
return terms;
terms = NULL;
n = qof_query_get_terms (q);
if (!n) return NULL;
terms = xmlNewNode (NULL, "qofquery:or-terms");
for ( ; n; n = n->next)
{
andt = qof_query_and_terms_to_xml (n->data);
if (andt) xmlAddChild (terms, andt);
}
return terms;
}
/* ======================================================= */
@ -447,44 +447,44 @@ qof_query_terms_to_xml (QofQuery *q)
static xmlNodePtr
qof_query_sorts_to_xml (QofQuery *q)
{
QofQuerySort *s[3];
xmlNodePtr sortlist;
GSList *plist;
xmlNodePtr sort;
xmlNodePtr topnode;
gboolean increasing;
gint opt;
xmlNodePtr pl;
int i;
qof_query_get_sorts (q, &s[0], &s[1], &s[2]);
QofQuerySort *s[3];
xmlNodePtr sortlist;
GSList *plist;
xmlNodePtr sort;
xmlNodePtr topnode;
gboolean increasing;
gint opt;
xmlNodePtr pl;
int i;
if (NULL == s[0]) return NULL;
qof_query_get_sorts (q, &s[0], &s[1], &s[2]);
sortlist = xmlNewNode (NULL, "qofquery:sort-list");
for (i=0; i<3; i++)
{
if (NULL == s[i]) continue;
if (NULL == s[0]) return NULL;
plist = qof_query_sort_get_param_path (s[i]);
if (!plist) continue;
sortlist = xmlNewNode (NULL, "qofquery:sort-list");
for (i = 0; i < 3; i++)
{
if (NULL == s[i]) continue;
sort = xmlNewNode (NULL, "qofquery:sort");
xmlAddChild (sortlist, sort);
plist = qof_query_sort_get_param_path (s[i]);
if (!plist) continue;
topnode = sort;
sort = xmlNewNode (NULL, "qofquery:sort");
xmlAddChild (sortlist, sort);
increasing = qof_query_sort_get_increasing (s[i]);
PUT_STR ("qofquery:order", increasing ? "DESCENDING" : "ASCENDING");
topnode = sort;
opt = qof_query_sort_get_sort_options (s[i]);
PUT_INT32 ("qofquery:options", opt);
increasing = qof_query_sort_get_increasing (s[i]);
PUT_STR ("qofquery:order", increasing ? "DESCENDING" : "ASCENDING");
pl = qof_query_param_path_to_xml (plist);
if (pl) xmlAddChild (sort, pl);
}
opt = qof_query_sort_get_sort_options (s[i]);
PUT_INT32 ("qofquery:options", opt);
return sortlist;
pl = qof_query_param_path_to_xml (plist);
if (pl) xmlAddChild (sort, pl);
}
return sortlist;
}
/* ======================================================= */
@ -492,22 +492,22 @@ qof_query_sorts_to_xml (QofQuery *q)
static void
do_qof_query_to_xml (QofQuery *q, xmlNodePtr topnode)
{
QofIdType search_for;
xmlNodePtr terms;
xmlNodePtr sorts;
gint max_results;
search_for = qof_query_get_search_for (q);
PUT_STR ("qofquery:search-for", search_for);
QofIdType search_for;
xmlNodePtr terms;
xmlNodePtr sorts;
gint max_results;
terms = qof_query_terms_to_xml(q);
if (terms) xmlAddChild (topnode, terms);
search_for = qof_query_get_search_for (q);
PUT_STR ("qofquery:search-for", search_for);
sorts = qof_query_sorts_to_xml (q);
if (sorts) xmlAddChild (topnode, sorts);
terms = qof_query_terms_to_xml(q);
if (terms) xmlAddChild (topnode, terms);
max_results = qof_query_get_max_results (q);
PUT_INT32 ("qofquery:max-results", max_results);
sorts = qof_query_sorts_to_xml (q);
if (sorts) xmlAddChild (topnode, sorts);
max_results = qof_query_get_max_results (q);
PUT_INT32 ("qofquery:max-results", max_results);
}
/* ======================================================= */
@ -515,19 +515,19 @@ do_qof_query_to_xml (QofQuery *q, xmlNodePtr topnode)
xmlNodePtr
qof_query_to_xml (QofQuery *q)
{
xmlNodePtr topnode;
xmlNodePtr node;
xmlNsPtr ns;
xmlNodePtr topnode;
xmlNodePtr node;
xmlNsPtr ns;
topnode = xmlNewNode(NULL, "qof:qofquery");
xmlSetProp(topnode, "version", "1.0.1");
topnode = xmlNewNode(NULL, "qof:qofquery");
xmlSetProp(topnode, "version", "1.0.1");
// XXX path to DTD is wrong
// ns = xmlNewNs (topnode, "file:" "/usr/share/lib" "/qofquery.dtd", "qof");
// XXX path to DTD is wrong
// ns = xmlNewNs (topnode, "file:" "/usr/share/lib" "/qofquery.dtd", "qof");
do_qof_query_to_xml (q, topnode);
do_qof_query_to_xml (q, topnode);
return topnode;
return topnode;
}
/* =============================================================== */
@ -539,60 +539,61 @@ qof_query_to_xml (QofQuery *q)
int main (int argc, char * argv[])
{
QofQuery *q;
QofSqlQuery *sq;
xmlDocPtr doc;
xmlNodePtr topnode;
xmlChar *xbuf;
int bufsz;
xmlOutputBufferPtr xbuf;
qof_query_init();
qof_object_initialize ();
QofQuery *q;
QofSqlQuery *sq;
xmlDocPtr doc;
xmlNodePtr topnode;
xmlChar *xbuf;
int bufsz;
xmlOutputBufferPtr xbuf;
static QofParam params[] = {
{ "adate", QOF_TYPE_DATE, NULL, NULL},
{ "aint", QOF_TYPE_INT32, NULL, NULL},
{ "aint64", QOF_TYPE_INT64, NULL, NULL},
{ "astr", QOF_TYPE_STRING, NULL, NULL},
{ NULL },
};
qof_query_init();
qof_object_initialize ();
qof_class_register ("GncABC", NULL, params);
sq = qof_sql_query_new();
static QofParam params[] =
{
{ "adate", QOF_TYPE_DATE, NULL, NULL},
{ "aint", QOF_TYPE_INT32, NULL, NULL},
{ "aint64", QOF_TYPE_INT64, NULL, NULL},
{ "astr", QOF_TYPE_STRING, NULL, NULL},
{ NULL },
};
qof_sql_query_parse (sq,
"SELECT * from GncABC WHERE aint = 123 "
"or not astr=\'asdf\' "
"and aint64 = 9876123456789;");
// qof_sql_query_parse (sq, "SELECT * from GncABC;");
q = qof_sql_query_get_query (sq);
qof_class_register ("GncABC", NULL, params);
sq = qof_sql_query_new();
qof_query_print (q);
qof_sql_query_parse (sq,
"SELECT * from GncABC WHERE aint = 123 "
"or not astr=\'asdf\' "
"and aint64 = 9876123456789;");
// qof_sql_query_parse (sq, "SELECT * from GncABC;");
q = qof_sql_query_get_query (sq);
doc = doc = xmlNewDoc("1.0");
topnode = qof_query_to_xml (q);
xmlDocSetRootElement(doc,topnode);
qof_query_print (q);
xmlDocDumpFormatMemory (doc, &xbuf, &bufsz, 1);
doc = doc = xmlNewDoc("1.0");
topnode = qof_query_to_xml (q);
xmlDocSetRootElement(doc, topnode);
printf ("%s\n", xbuf);
xmlFree (xbuf);
xmlFreeDoc(doc);
xmlDocDumpFormatMemory (doc, &xbuf, &bufsz, 1);
printf ("%s\n", xbuf);
xmlFree (xbuf);
xmlFreeDoc(doc);
#if 0
printf ("duude\n");
// xmlOutputBufferPtr xbuf = xmlAllocOutputBuffer (enc);
xbuf = xmlOutputBufferCreateFile (stdout, NULL);
printf ("duude\n");
printf ("duude\n");
// xmlOutputBufferPtr xbuf = xmlAllocOutputBuffer (enc);
xbuf = xmlOutputBufferCreateFile (stdout, NULL);
printf ("duude\n");
xbuf = xmlOutputBufferCreateFd (1, NULL);
printf ("duude\n");
xmlNodeDumpOutput (xbuf, NULL, topnode, 99, 99, "iso-8859-1");
// xmlElemDump (stdout, NULL, topnode);
xbuf = xmlOutputBufferCreateFd (1, NULL);
printf ("duude\n");
xmlNodeDumpOutput (xbuf, NULL, topnode, 99, 99, "iso-8859-1");
// xmlElemDump (stdout, NULL, topnode);
#endif
return 0;
return 0;
}
#endif /* UNIT_TEST */

File diff suppressed because it is too large Load Diff

View File

@ -22,10 +22,10 @@
/** @addtogroup Query
BASIC QUERY API:
BASIC QUERY API:
With this API you can create arbitrary logical
queries to find sets of arbitrary object. To make simple
queries (1 term, such as a search for a parameter with one value),
queries (1 term, such as a search for a parameter with one value),
create the appropriate
QueryTerm structure and stick it in a Query object using
xaccInitQuery. The QueryTerm should be malloced but the Query object
@ -33,9 +33,9 @@ will handle freeing it. To make compound queries, make multiple
simple queries and combine them using qof_query_merge() and the logical
operations of your choice.
SQL QUERY API:
SQL QUERY API:
As an alternative to building queries one predicate at a time,
you can use the SQL query interface. This interface will accept
you can use the SQL query interface. This interface will accept
a string containing an SQL query, parse it, convert it into the
core representation, and execute it.
@ -49,7 +49,7 @@ tested.
The terms of the Query may represent any logical function and are
stored in canonical form, i.e. the function is expressed as a logical
sum of logical products. So if you have QueryTerms a, b, c, d, e and
you have the logical function a(b+c) + !(c(d+e)), it gets stored as
you have the logical function a(b+c) + !(c(d+e)), it gets stored as
ab + ac + !c + !c!e +!d!c + !d!e. This may not be optimal for evaluation
of some functions but it's easy to store, easy to manipulate, and it
doesn't require a complete algebra system to deal with.
@ -85,12 +85,13 @@ probably optimize.
typedef struct _QofQuery QofQuery;
/** Query Term Operators, for combining Query Terms */
typedef enum {
QOF_QUERY_AND=1,
QOF_QUERY_OR,
QOF_QUERY_NAND,
QOF_QUERY_NOR,
QOF_QUERY_XOR
typedef enum
{
QOF_QUERY_AND = 1,
QOF_QUERY_OR,
QOF_QUERY_NAND,
QOF_QUERY_NOR,
QOF_QUERY_XOR
} QofQueryOp;
/** First/only term is same as 'and' */
@ -104,16 +105,16 @@ typedef enum {
#define QOF_PARAM_GUID "guid"
/** "Known" Object Parameters -- some objects might support these */
#define QOF_PARAM_KVP "kvp"
#define QOF_PARAM_ACTIVE "active"
#define QOF_PARAM_VERSION "version"
#define QOF_PARAM_KVP "kvp"
#define QOF_PARAM_ACTIVE "active"
#define QOF_PARAM_VERSION "version"
/* --------------------------------------------------------- */
/** \name Query Subsystem Initialization and Shudown */
// @{
/** Subsystem initialization and shutdown. Call init() once
/** Subsystem initialization and shutdown. Call init() once
* to initalize the query subsytem; call shutdown() to free
* up any resources associated with the query subsystem.
* up any resources associated with the query subsystem.
* Typically called during application startup, shutdown.
*/
@ -127,13 +128,13 @@ void qof_query_shutdown (void);
GSList * qof_query_build_param_list (char const *param, ...);
/** Create a new query.
/** Create a new query.
* Before running the query, a 'search-for' type must be set
* otherwise nothing will be returned. The results of the query
* otherwise nothing will be returned. The results of the query
* is a list of the indicated search-for type.
*
* Allocates and initializes a Query structure which must be
* freed by the user with qof_query_destroy(). A newly-allocated
* Allocates and initializes a Query structure which must be
* freed by the user with qof_query_destroy(). A newly-allocated
* QofQuery object matches nothing (qof_query_run() will return NULL).
*/
QofQuery * qof_query_create (void);
@ -142,19 +143,19 @@ QofQuery * qof_query_create_for (QofIdTypeConst obj_type);
/** Frees the resources associate with a Query object. */
void qof_query_destroy (QofQuery *q);
/** Set the object type to be searched for. The results of
/** Set the object type to be searched for. The results of
* performing the query will be a list of this obj_type.
*/
void qof_query_search_for (QofQuery *query, QofIdTypeConst obj_type);
/** Set the book to be searched. Books contain/identify collections
/** Set the book to be searched. Books contain/identify collections
* of objects; the search will be performed over those books
* specified with this function. If no books are set, no results
* specified with this function. If no books are set, no results
* will be returned (since there is nothing to search over).
*
* You can search multiple books. To specify multiple books, call
* this function multiple times with different arguments.
* XXX needed qof_query_clear_books() to reset the list ...
* You can search multiple books. To specify multiple books, call
* this function multiple times with different arguments.
* XXX needed qof_query_clear_books() to reset the list ...
*/
void qof_query_set_book (QofQuery *q, QofBook *book);
@ -179,27 +180,27 @@ void qof_query_set_book (QofQuery *q, QofBook *book);
*
* Please note that QofQuery does not, at this time, support joins.
* That is, one cannot specify a predicate that is a parameter list.
* Put another way, one cannot search for objects where
* Put another way, one cannot search for objects where
* obja->thingy == objb->stuff
*/
void qof_query_add_term (QofQuery *query, GSList *param_list,
QofQueryPredData *pred_data, QofQueryOp op);
QofQueryPredData *pred_data, QofQueryOp op);
/** DOCUMENT ME !! */
void qof_query_add_guid_match (QofQuery *q, GSList *param_list,
const GUID *guid, QofQueryOp op);
const GUID *guid, QofQueryOp op);
/** DOCUMENT ME !! */
void qof_query_add_guid_list_match (QofQuery *q, GSList *param_list,
GList *guid_list, QofGuidMatch options,
QofQueryOp op);
GList *guid_list, QofGuidMatch options,
QofQueryOp op);
/** Handy-dandy convenience routines, avoids having to create
* a separate predicate for boolean matches. We might want to
* create handy-dandy sugar routines for the other predicate types
/** Handy-dandy convenience routines, avoids having to create
* a separate predicate for boolean matches. We might want to
* create handy-dandy sugar routines for the other predicate types
* as well. */
void qof_query_add_boolean_match (QofQuery *q,
GSList *param_list,
void qof_query_add_boolean_match (QofQuery *q,
GSList *param_list,
gboolean value,
QofQueryOp op);
@ -231,26 +232,26 @@ GList * qof_query_last_run (QofQuery *query);
GList * qof_query_run_subquery (QofQuery *subquery,
const QofQuery* primary_query);
/** Remove all query terms from query. query matches nothing
/** Remove all query terms from query. query matches nothing
* after qof_query_clear().
*/
void qof_query_clear (QofQuery *query);
/** Remove query terms of a particular type from q. The "type" of a term
* is determined by the type of data that gets passed to the predicate
* function.
* XXX ??? Huh? remove anything of that predicate type, or just
* function.
* XXX ??? Huh? remove anything of that predicate type, or just
* the particular predicate ?
*/
void qof_query_purge_terms (QofQuery *q, GSList *param_list);
/** Return boolean FALSE if there are no terms in the query
* Can be used as a predicate to see if the query has been
/** Return boolean FALSE if there are no terms in the query
* Can be used as a predicate to see if the query has been
* initialized (return value > 0) or is "blank" (return value == 0).
*/
int qof_query_has_terms (QofQuery *q);
/** Return the number of terms in the canonical form of the query.
/** Return the number of terms in the canonical form of the query.
*/
int qof_query_num_terms (QofQuery *q);
@ -262,7 +263,7 @@ GSList * qof_query_get_term_type (QofQuery *q, GSList *term_param);
QofQuery * qof_query_copy (QofQuery *q);
/** Make a copy of the indicated query, inverting the sense
* of the search. In other words, if the original query search
* of the search. In other words, if the original query search
* for all objects with a certain condition, the inverted query
* will search for all object with NOT that condition. The union
* of the results returned by the original and inverted queries
@ -274,7 +275,7 @@ QofQuery * qof_query_copy (QofQuery *q);
*/
QofQuery * qof_query_invert(QofQuery *q);
/** Combine two queries together using the Boolean set (logical)
/** Combine two queries together using the Boolean set (logical)
* operator 'op'. For example, if the operator 'op' is set to
* QUERY_AND, then the set of results returned by the query will
* will be the Boolean set intersection of the results returned
@ -294,18 +295,18 @@ QofQuery * qof_query_invert(QofQuery *q);
*/
QofQuery * qof_query_merge(QofQuery *q1, QofQuery *q2, QofQueryOp op);
/** Like qof_query_merge, but this will merge a copy of q2 into q1.
/** Like qof_query_merge, but this will merge a copy of q2 into q1.
* q2 remains unchanged.
*/
void qof_query_merge_in_place(QofQuery *q1, QofQuery *q2, QofQueryOp op);
/**
/**
* When a query is run, the results are sorted before being returned.
* This routine can be used to set the paramters on which the sort will
* be performed. Two objects in the result list will be compared using
* the 'primary_sort_params', and sorted based on that order. If the
* comparison shows that they are equal, then the
* 'secondary_sort_params' will be used. If still equal, then the
* 'secondary_sort_params' will be used. If still equal, then the
* tertiary params will be compared. Any or all of these parameter
* lists may be NULL. Any of these parameter lists may be set to
* QUERY_DEFAULT_SORT.
@ -320,12 +321,12 @@ void qof_query_merge_in_place(QofQuery *q1, QofQuery *q2, QofQueryOp op);
* new lists are set).
*/
void qof_query_set_sort_order (QofQuery *q,
GSList *primary_sort_params,
GSList *secondary_sort_params,
GSList *tertiary_sort_params);
GSList *primary_sort_params,
GSList *secondary_sort_params,
GSList *tertiary_sort_params);
void qof_query_set_sort_options (QofQuery *q, gint prim_op, gint sec_op,
gint tert_op);
gint tert_op);
/**
* When a query is run, the results are sorted before being returned.
@ -339,30 +340,30 @@ void qof_query_set_sort_options (QofQuery *q, gint prim_op, gint sec_op,
* objects with the most recent dates will be returned.
*/
void qof_query_set_sort_increasing (QofQuery *q, gboolean prim_inc,
gboolean sec_inc, gboolean tert_inc);
gboolean sec_inc, gboolean tert_inc);
/**
* Set the maximum number of results that should be returned.
* Set the maximum number of results that should be returned.
* If 'max-results' is set to -1, then all of the results are
* returned. If there are more results than 'max-results',
* then the result list is trimmed. Note that there is an
* important interplay between 'max-results' and the sort order:
* only the last bit of results are returned. For example,
* if the sort order is set to be increasing date order, then
* if the sort order is set to be increasing date order, then
* only the objects with the most recent dates will be returned.
*/
*/
void qof_query_set_max_results (QofQuery *q, int n);
/** Compare two queries for equality.
/** Compare two queries for equality.
* Query terms are compared each to each.
* This is a simplistic
* implementation -- logical equivalences between different
* and/or trees are ignored.
* and/or trees are ignored.
*/
gboolean qof_query_equal (const QofQuery *q1, const QofQuery *q2);
/** Log the Query
/** Log the Query
*
* \deprecated Do not call directly, use the standard log
* module code: ::qof_log_set_level(QOF_MOD_QUERY, QOF_LOG_DEBUG);
@ -371,7 +372,8 @@ gboolean qof_query_equal (const QofQuery *q1, const QofQuery *q2);
void qof_query_print (QofQuery *query);
/** Return the type of data we're querying for */
/*@ dependent @*/ QofIdType qof_query_get_search_for (const QofQuery *q);
/*@ dependent @*/
QofIdType qof_query_get_search_for (const QofQuery *q);
/** Return the list of books we're using */
GList * qof_query_get_books (QofQuery *q);

View File

@ -35,15 +35,15 @@
void qof_query_core_init(void);
void qof_query_core_shutdown (void);
/*
/*
* An arbitrary Query Predicate. Given the object and the
* particular parameter get-function (obtained from the registry by
* the Query internals), compare the object's parameter to the
* predicate data.
*/
typedef gint (*QofQueryPredicateFunc) (gpointer object,
QofParam *getter,
QofQueryPredData *pdata);
QofParam *getter,
QofQueryPredData *pdata);
/* Lookup functions */
QofQueryPredicateFunc qof_query_core_get_predicate (gchar const *type);
@ -62,76 +62,88 @@ gboolean qof_query_core_predicate_equal (const QofQueryPredData *p1, const QofQu
* Query.
*/
typedef struct {
QofQueryPredData pd;
QofStringMatch options;
gboolean is_regex;
gchar * matchstring;
regex_t compiled;
typedef struct
{
QofQueryPredData pd;
QofStringMatch options;
gboolean is_regex;
gchar * matchstring;
regex_t compiled;
} query_string_def, *query_string_t;
typedef struct {
QofQueryPredData pd;
QofDateMatch options;
Timespec date;
typedef struct
{
QofQueryPredData pd;
QofDateMatch options;
Timespec date;
} query_date_def, *query_date_t;
typedef struct {
QofQueryPredData pd;
QofNumericMatch options;
gnc_numeric amount;
typedef struct
{
QofQueryPredData pd;
QofNumericMatch options;
gnc_numeric amount;
} query_numeric_def, *query_numeric_t;
typedef struct {
QofQueryPredData pd;
QofGuidMatch options;
GList * guids;
typedef struct
{
QofQueryPredData pd;
QofGuidMatch options;
GList * guids;
} query_guid_def, *query_guid_t;
typedef struct {
QofQueryPredData pd;
gint32 val;
typedef struct
{
QofQueryPredData pd;
gint32 val;
} query_int32_def, *query_int32_t;
typedef struct {
QofQueryPredData pd;
gint64 val;
typedef struct
{
QofQueryPredData pd;
gint64 val;
} query_int64_def, *query_int64_t;
typedef struct {
QofQueryPredData pd;
double val;
typedef struct
{
QofQueryPredData pd;
double val;
} query_double_def, *query_double_t;
typedef struct {
QofQueryPredData pd;
gboolean val;
typedef struct
{
QofQueryPredData pd;
gboolean val;
} query_boolean_def, *query_boolean_t;
typedef struct {
QofQueryPredData pd;
QofCharMatch options;
gchar * char_list;
typedef struct
{
QofQueryPredData pd;
QofCharMatch options;
gchar * char_list;
} query_char_def, *query_char_t;
typedef struct {
QofQueryPredData pd;
GSList * path;
KvpValue * value;
typedef struct
{
QofQueryPredData pd;
GSList * path;
KvpValue * value;
} query_kvp_def, *query_kvp_t;
typedef struct {
QofQueryPredData pd;
QofGuidMatch options;
QofCollection *coll;
GList *guids;
typedef struct
{
QofQueryPredData pd;
QofGuidMatch options;
QofCollection *coll;
GList *guids;
} query_coll_def, *query_coll_t;
typedef struct {
QofQueryPredData pd;
QofGuidMatch options;
const GUID *guid;
GList * guids;
typedef struct
{
QofQueryPredData pd;
QofGuidMatch options;
const GUID *guid;
GList * guids;
} query_choice_def, *query_choice_t;
#endif /* QOF_QUERYCOREP_H */

File diff suppressed because it is too large Load Diff

View File

@ -47,22 +47,24 @@ typedef struct _QofQueryPredData QofQueryPredData;
/** Standard Query comparitors, for how to compare objects in a predicate.
* Note that not all core types implement all comparitors
*/
typedef enum {
QOF_COMPARE_LT = 1,
QOF_COMPARE_LTE,
QOF_COMPARE_EQUAL,
QOF_COMPARE_GT,
QOF_COMPARE_GTE,
QOF_COMPARE_NEQ
typedef enum
{
QOF_COMPARE_LT = 1,
QOF_COMPARE_LTE,
QOF_COMPARE_EQUAL,
QOF_COMPARE_GT,
QOF_COMPARE_GTE,
QOF_COMPARE_NEQ
} QofQueryCompare;
/** List of known core query data-types...
* Each core query type defines it's set of optional "comparitor qualifiers".
*/
/* Comparisons for QOF_TYPE_STRING */
typedef enum {
QOF_STRING_MATCH_NORMAL = 1,
QOF_STRING_MATCH_CASEINSENSITIVE
typedef enum
{
QOF_STRING_MATCH_NORMAL = 1,
QOF_STRING_MATCH_CASEINSENSITIVE
} QofStringMatch;
/** Comparisons for QOF_TYPE_DATE
@ -72,9 +74,10 @@ typedef enum {
* down to the second.
*/
typedef enum {
QOF_DATE_MATCH_NORMAL = 1,
QOF_DATE_MATCH_DAY
typedef enum
{
QOF_DATE_MATCH_NORMAL = 1,
QOF_DATE_MATCH_DAY
} QofDateMatch;
/** Comparisons for QOF_TYPE_NUMERIC, QOF_TYPE_DEBCRED
@ -89,25 +92,27 @@ typedef enum {
* debit' predicate is equivalent to (amount <= 0) && (abs(amount) 'op' value)
*/
typedef enum {
QOF_NUMERIC_MATCH_DEBIT = 1,
QOF_NUMERIC_MATCH_CREDIT,
QOF_NUMERIC_MATCH_ANY
typedef enum
{
QOF_NUMERIC_MATCH_DEBIT = 1,
QOF_NUMERIC_MATCH_CREDIT,
QOF_NUMERIC_MATCH_ANY
} QofNumericMatch;
/* Comparisons for QOF_TYPE_GUID */
typedef enum {
/** These expect a single object and expect the
* QofAccessFunc returns GUID* */
QOF_GUID_MATCH_ANY = 1,
QOF_GUID_MATCH_NONE,
QOF_GUID_MATCH_NULL,
/** These expect a GList* of objects and calls the QofAccessFunc routine
* on each item in the list to obtain a GUID* for each object */
QOF_GUID_MATCH_ALL,
/** These expect a single object and expect the QofAccessFunc function
* to return a GList* of GUID* (the list is the property of the caller) */
QOF_GUID_MATCH_LIST_ANY,
typedef enum
{
/** These expect a single object and expect the
* QofAccessFunc returns GUID* */
QOF_GUID_MATCH_ANY = 1,
QOF_GUID_MATCH_NONE,
QOF_GUID_MATCH_NULL,
/** These expect a GList* of objects and calls the QofAccessFunc routine
* on each item in the list to obtain a GUID* for each object */
QOF_GUID_MATCH_ALL,
/** These expect a single object and expect the QofAccessFunc function
* to return a GList* of GUID* (the list is the property of the caller) */
QOF_GUID_MATCH_LIST_ANY,
} QofGuidMatch;
/** A CHAR type is for a RECNCell, Comparisons for QOF_TYPE_CHAR
@ -118,9 +123,10 @@ typedef enum {
* Match 'NONE' is equivalent to
* (value != char1) && (value != char2) && etc.
*/
typedef enum {
QOF_CHAR_MATCH_ANY = 1,
QOF_CHAR_MATCH_NONE
typedef enum
{
QOF_CHAR_MATCH_ANY = 1,
QOF_CHAR_MATCH_NONE
} QofCharMatch;
/** No extended comparisons for QOF_TYPE_INT32, QOF_TYPE_INT64,
@ -128,26 +134,27 @@ typedef enum {
*/
/** Head of Predicate Data structures. All PData must start like this. */
struct _QofQueryPredData {
QofType type_name; /* QOF_TYPE_* */
QofQueryCompare how;
struct _QofQueryPredData
{
QofType type_name; /* QOF_TYPE_* */
QofQueryCompare how;
};
/** @name Core Data Type Predicates
@{ */
QofQueryPredData *qof_query_string_predicate (QofQueryCompare how,
const gchar *str,
QofStringMatch options,
gboolean is_regex);
const gchar *str,
QofStringMatch options,
gboolean is_regex);
QofQueryPredData *qof_query_date_predicate (QofQueryCompare how,
QofDateMatch options,
Timespec date);
QofDateMatch options,
Timespec date);
QofQueryPredData *qof_query_numeric_predicate (QofQueryCompare how,
QofNumericMatch options,
gnc_numeric value);
QofNumericMatch options,
gnc_numeric value);
QofQueryPredData *qof_query_guid_predicate (QofGuidMatch options, GList *guids);
QofQueryPredData *qof_query_int32_predicate (QofQueryCompare how, gint32 val);
@ -155,9 +162,9 @@ QofQueryPredData *qof_query_int64_predicate (QofQueryCompare how, gint64 val);
QofQueryPredData *qof_query_double_predicate (QofQueryCompare how, double val);
QofQueryPredData *qof_query_boolean_predicate (QofQueryCompare how, gboolean val);
QofQueryPredData *qof_query_char_predicate (QofCharMatch options,
const gchar *chars);
const gchar *chars);
QofQueryPredData *qof_query_collect_predicate (QofGuidMatch options,
QofCollection *coll);
QofCollection *coll);
QofQueryPredData *qof_query_choice_predicate (QofGuidMatch options, GList *guids);
/** The qof_query_kvp_predicate() matches the object that has
@ -165,14 +172,14 @@ QofQueryPredData *qof_query_choice_predicate (QofGuidMatch options, GList *guid
* sense, the 'path' is handled as if it were a paramter.
*/
QofQueryPredData *qof_query_kvp_predicate (QofQueryCompare how,
GSList *path,
const KvpValue *value);
GSList *path,
const KvpValue *value);
/** Same predicate as above, except that 'path' is assumed to be
* a string containing slash-separated pathname. */
QofQueryPredData *qof_query_kvp_predicate_path (QofQueryCompare how,
const gchar *path,
const KvpValue *value);
const gchar *path,
const KvpValue *value);
/** Copy a predicate. */
QofQueryPredData *qof_query_core_predicate_copy (const QofQueryPredData *pdata);

View File

@ -28,138 +28,152 @@
static void
entity_set_reference_cb(QofInstance *ent, gpointer user_data)
{
void (*reference_setter) (QofInstance*, QofInstance*);
void (*choice_setter) (QofInstance*, QofInstance*);
void (*collect_setter)(QofInstance*, QofCollection*);
QofInstanceReference *ref;
GList *book_ref_list;
QofCollection *coll;
QofIdType type;
QofInstance *reference;
QofBook *partial_book;
partial_book = (QofBook*)user_data;
g_return_if_fail(partial_book && ent);
reference = NULL;
coll = NULL;
book_ref_list = qof_book_get_data(partial_book, ENTITYREFERENCE);
while(book_ref_list)
{
ref = (QofInstanceReference*)book_ref_list->data;
if(0 == guid_compare(ref->ref_guid, qof_instance_get_guid(ent)))
{
/* avoid setting the entity's own guid as a reference. */
book_ref_list = g_list_next(book_ref_list);
continue;
}
if(qof_object_is_choice(ent->e_type)) { type = ref->choice_type; }
type = ref->param->param_type;
coll = qof_book_get_collection(partial_book, type);
reference = qof_collection_lookup_entity(coll, ref->ref_guid);
reference_setter = (void(*)(QofInstance*, QofInstance*))ref->param->param_setfcn;
if((reference) && (reference_setter))
{
qof_begin_edit((QofInstance*)ent);
qof_begin_edit((QofInstance*)reference);
reference_setter(ent, reference);
qof_commit_edit((QofInstance*)ent);
qof_commit_edit((QofInstance*)reference);
}
/* collect and choice handling */
collect_setter = (void(*)(QofInstance*, QofCollection*))ref->param->param_setfcn;
choice_setter = (void(*)(QofInstance*, QofInstance*))ref->param->param_setfcn;
if ((0 == safe_strcmp(ref->param->param_type, QOF_TYPE_COLLECT)) &&
(0 == guid_compare(qof_instance_get_guid(ent), ref->ent_guid)) &&
(0 == safe_strcmp(ref->type, ent->e_type)))
{
QofCollection *temp_col;
char cm_sa[GUID_ENCODING_LENGTH + 1];
temp_col = ref->param->param_getfcn(ent, ref->param);
coll = qof_book_get_collection(partial_book,
qof_collection_get_type(temp_col));
guid_to_string_buff(ref->ref_guid, cm_sa);
reference = qof_collection_lookup_entity(coll, ref->ref_guid);
if(reference) {
qof_collection_add_entity(temp_col, reference);
qof_begin_edit((QofInstance*)ent);
qof_begin_edit((QofInstance*)reference);
if(collect_setter) { collect_setter(ent, temp_col); }
qof_commit_edit((QofInstance*)ent);
qof_commit_edit((QofInstance*)reference);
qof_collection_destroy(temp_col);
}
}
if(0 == safe_strcmp(ref->param->param_type, QOF_TYPE_CHOICE))
{
coll = qof_book_get_collection(partial_book, ref->type);
reference = qof_collection_lookup_entity(coll, ref->ref_guid);
qof_begin_edit((QofInstance*)ent);
qof_begin_edit((QofInstance*)reference);
if(choice_setter) { choice_setter(ent, reference); }
qof_commit_edit((QofInstance*)ent);
qof_commit_edit((QofInstance*)reference);
}
book_ref_list = g_list_next(book_ref_list);
}
void (*reference_setter) (QofInstance*, QofInstance*);
void (*choice_setter) (QofInstance*, QofInstance*);
void (*collect_setter)(QofInstance*, QofCollection*);
QofInstanceReference *ref;
GList *book_ref_list;
QofCollection *coll;
QofIdType type;
QofInstance *reference;
QofBook *partial_book;
partial_book = (QofBook*)user_data;
g_return_if_fail(partial_book && ent);
reference = NULL;
coll = NULL;
book_ref_list = qof_book_get_data(partial_book, ENTITYREFERENCE);
while (book_ref_list)
{
ref = (QofInstanceReference*)book_ref_list->data;
if (0 == guid_compare(ref->ref_guid, qof_instance_get_guid(ent)))
{
/* avoid setting the entity's own guid as a reference. */
book_ref_list = g_list_next(book_ref_list);
continue;
}
if (qof_object_is_choice(ent->e_type))
{
type = ref->choice_type;
}
type = ref->param->param_type;
coll = qof_book_get_collection(partial_book, type);
reference = qof_collection_lookup_entity(coll, ref->ref_guid);
reference_setter = (void(*)(QofInstance*, QofInstance*))ref->param->param_setfcn;
if ((reference) && (reference_setter))
{
qof_begin_edit((QofInstance*)ent);
qof_begin_edit((QofInstance*)reference);
reference_setter(ent, reference);
qof_commit_edit((QofInstance*)ent);
qof_commit_edit((QofInstance*)reference);
}
/* collect and choice handling */
collect_setter = (void(*)(QofInstance*, QofCollection*))ref->param->param_setfcn;
choice_setter = (void(*)(QofInstance*, QofInstance*))ref->param->param_setfcn;
if ((0 == safe_strcmp(ref->param->param_type, QOF_TYPE_COLLECT)) &&
(0 == guid_compare(qof_instance_get_guid(ent), ref->ent_guid)) &&
(0 == safe_strcmp(ref->type, ent->e_type)))
{
QofCollection *temp_col;
char cm_sa[GUID_ENCODING_LENGTH + 1];
temp_col = ref->param->param_getfcn(ent, ref->param);
coll = qof_book_get_collection(partial_book,
qof_collection_get_type(temp_col));
guid_to_string_buff(ref->ref_guid, cm_sa);
reference = qof_collection_lookup_entity(coll, ref->ref_guid);
if (reference)
{
qof_collection_add_entity(temp_col, reference);
qof_begin_edit((QofInstance*)ent);
qof_begin_edit((QofInstance*)reference);
if (collect_setter)
{
collect_setter(ent, temp_col);
}
qof_commit_edit((QofInstance*)ent);
qof_commit_edit((QofInstance*)reference);
qof_collection_destroy(temp_col);
}
}
if (0 == safe_strcmp(ref->param->param_type, QOF_TYPE_CHOICE))
{
coll = qof_book_get_collection(partial_book, ref->type);
reference = qof_collection_lookup_entity(coll, ref->ref_guid);
qof_begin_edit((QofInstance*)ent);
qof_begin_edit((QofInstance*)reference);
if (choice_setter)
{
choice_setter(ent, reference);
}
qof_commit_edit((QofInstance*)ent);
qof_commit_edit((QofInstance*)reference);
}
book_ref_list = g_list_next(book_ref_list);
}
}
static void
set_each_type(QofObject *obj, gpointer user_data)
{
QofBook *book;
QofBook *book;
book = (QofBook*)user_data;
qof_object_foreach(obj->e_type, book, entity_set_reference_cb, book);
book = (QofBook*)user_data;
qof_object_foreach(obj->e_type, book, entity_set_reference_cb, book);
}
static QofInstanceReference*
create_reference(QofInstance *ent, const QofParam *param)
{
QofInstanceReference *reference;
QofInstance *ref_ent;
const GUID *cm_guid;
char cm_sa[GUID_ENCODING_LENGTH + 1];
gchar *cm_string;
QofInstanceReference *reference;
QofInstance *ref_ent;
const GUID *cm_guid;
char cm_sa[GUID_ENCODING_LENGTH + 1];
gchar *cm_string;
g_return_val_if_fail(ent, NULL);
ref_ent = QOF_INSTANCE(param->param_getfcn(ent, param));
if(!ref_ent) { return NULL; }
reference = g_new0(QofInstanceReference, 1);
reference->type = ent->e_type;
reference->ref_guid = g_new(GUID, 1);
reference->ent_guid = qof_instance_get_guid(ent);
if(qof_object_is_choice(ent->e_type))
{
reference->choice_type = ref_ent->e_type;
}
reference->param = param;
cm_guid = qof_instance_get_guid(ref_ent);
guid_to_string_buff(cm_guid, cm_sa);
cm_string = g_strdup(cm_sa);
if(TRUE == string_to_guid(cm_string, reference->ref_guid)) {
g_free(cm_string);
return reference;
}
g_free(cm_string);
return NULL;
g_return_val_if_fail(ent, NULL);
ref_ent = QOF_INSTANCE(param->param_getfcn(ent, param));
if (!ref_ent)
{
return NULL;
}
reference = g_new0(QofInstanceReference, 1);
reference->type = ent->e_type;
reference->ref_guid = g_new(GUID, 1);
reference->ent_guid = qof_instance_get_guid(ent);
if (qof_object_is_choice(ent->e_type))
{
reference->choice_type = ref_ent->e_type;
}
reference->param = param;
cm_guid = qof_instance_get_guid(ref_ent);
guid_to_string_buff(cm_guid, cm_sa);
cm_string = g_strdup(cm_sa);
if (TRUE == string_to_guid(cm_string, reference->ref_guid))
{
g_free(cm_string);
return reference;
}
g_free(cm_string);
return NULL;
}
QofInstanceReference*
qof_instance_get_reference_from(QofInstance *ent, const QofParam *param)
{
g_return_val_if_fail(param, NULL);
param = qof_class_get_parameter(ent->e_type, param->param_name);
g_return_val_if_fail(0 != safe_strcmp(param->param_type, QOF_TYPE_COLLECT), NULL);
return create_reference(ent, param);
g_return_val_if_fail(param, NULL);
param = qof_class_get_parameter(ent->e_type, param->param_name);
g_return_val_if_fail(0 != safe_strcmp(param->param_type, QOF_TYPE_COLLECT), NULL);
return create_reference(ent, param);
}
void qof_book_set_references(QofBook *book)
{
gboolean partial;
gboolean partial;
partial =
(gboolean)GPOINTER_TO_INT(qof_book_get_data(book, PARTIAL_QOFBOOK));
g_return_if_fail(partial);
qof_object_foreach_type(set_each_type, book);
partial =
(gboolean)GPOINTER_TO_INT(qof_book_get_data(book, PARTIAL_QOFBOOK));
g_return_if_fail(partial);
qof_object_foreach_type(set_each_type, book);
}

View File

@ -20,7 +20,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _QOFREFERENCE_H
#define _QOFREFERENCE_H
@ -41,22 +41,22 @@ Different backends have different requirements for a complete book - some
(like gnucash) are highly customised to that application - however all complete
QofBooks must be self-contained, only a partial book uses QofInstanceReference.
To retain the relationships between entities, including between a partial and
To retain the relationships between entities, including between a partial and
a complete book, QofInstanceReference data is stored in the QofBook. This data
should be read by backends that support partial books so that the exported
data contains the GUID and QofIdType of the referenced entity. Even if that
should be read by backends that support partial books so that the exported
data contains the GUID and QofIdType of the referenced entity. Even if that
entity does not then exist within the partial book, it can be located when
the partial book is merged back into the original, complete, book. (Remember
the partial book is merged back into the original, complete, book. (Remember
that given the GUID and QofIdType of any QofInstance it is possible to uniquely
identify that entity in another book.)
Entities in partial books may need to refer to the entities that remain within
the partial book. Once all the entities you want are in the partial book,
call qof_book_set_references to restore as many references as possible. Each
object type is checked in turn, each entity of that type and then each
object type is checked in turn, each entity of that type and then each
parameter that can relate to another entity. Any references that cannot be
found are left unset - depending on the object these may be undefined or NULL.
(It is advisable to set all QOF parameters to either a default value or NULL
(It is advisable to set all QOF parameters to either a default value or NULL
in the create: routine for the object but QOF has no way of guaranteeing this.)
@{
@ -73,9 +73,9 @@ in the create: routine for the object but QOF has no way of guaranteeing this.)
Part of the handling for partial books requires a storage mechanism for
references to entities that are not within reach of the partial book.
This requires a GList in the book data to contain the reference
This requires a GList in the book data to contain the reference
QofIdType and GUID so that when the book is written out, the
reference can be included. See ::qof_book_get_data.
reference can be included. See ::qof_book_get_data.
When the file is imported back in, the list needs to be rebuilt.
The QSF backend rebuilds the references by linking to real entities.
@ -85,7 +85,7 @@ The list stores the QofInstanceReference to the referenced entity -
a struct that contains the GUID and the QofIdType of the referenced
entity as well as the parameter used to obtain the reference.
Partial books need to be differentiated in the backend, the
Partial books need to be differentiated in the backend, the
flag in the book data is used by qof_session_save to prevent a partial
book being saved using a backend that requires a full book. Forcing this
flag would cause data loss so always merge a partial book with the complete
@ -102,17 +102,18 @@ It is used by the entity copy functions and by the QSF backend.
Creates a GList stored in the Book hashtable to contain
repeated references for a single entity.
*/
typedef struct qof_instance_reference {
QofIdType choice_type;/**< Used when the reference is a QOF_TYPE_CHOICE type
typedef struct qof_instance_reference
{
QofIdType choice_type;/**< Used when the reference is a QOF_TYPE_CHOICE type
- stores the actual type of the reference from the list of available choices. */
QofIdType type; /**< The type of the original entity -
QofIdType type; /**< The type of the original entity -
use the param->param_type to obtain the type of the reference entity.
For a QOF_TYPE_COLLECT, obtain the collection and get the type from that. */
GUID *ref_guid; /**< The GUID of the REFERENCE entity */
const QofParam *param; /**< The parameter of the original entity to use
GUID *ref_guid; /**< The GUID of the REFERENCE entity */
const QofParam *param; /**< The parameter of the original entity to use
to get or set the reference. */
const GUID *ent_guid; /**< The GUID of the original entity. */
}QofInstanceReference;
const GUID *ent_guid; /**< The GUID of the original entity. */
} QofInstanceReference;
/** \brief Adds a new reference to the partial book data hash.
@ -187,7 +188,7 @@ to the reference list which is added to the partial book data hash.
The reference itself is used to preserve the relationship
between entities within and outside the partial book.
See also ::qof_class_get_referenceList to obtain the list of
See also ::qof_class_get_referenceList to obtain the list of
parameters that provide references to the known entity whilst
excluding parameters that return known QOF data types.

View File

@ -34,36 +34,36 @@
struct _QofSession
{
/* This is just a "fake" entry point to allow me to pass a Session as
* an Entity. NOTE: THIS IS NOT AN ENTITY! THE ONLY PART OF ENTITY
* THAT IS VALID IS E_TYPE!
*/
QofInstance entity;
/* This is just a "fake" entry point to allow me to pass a Session as
* an Entity. NOTE: THIS IS NOT AN ENTITY! THE ONLY PART OF ENTITY
* THAT IS VALID IS E_TYPE!
*/
QofInstance entity;
/* A book holds pointers to the various types of datasets.
* A session may have multiple books. */
GList *books;
/* A book holds pointers to the various types of datasets.
* A session may have multiple books. */
GList *books;
/* The requested book id, in the form or a URI, such as
* file:/some/where, or sql:server.host.com:555
*/
char *book_id;
/* The requested book id, in the form or a URI, such as
* file:/some/where, or sql:server.host.com:555
*/
char *book_id;
/* If any book subroutine failed, this records the failure reason
* (file not found, etc).
* This is a 'stack' that is one deep. (Should be deeper ??)
* FIXME: Each backend has its own error stack. The session
* and the backends should all be using (or making it look like)
* there is only one stack.
*/
QofBackendError last_err;
char *error_message;
/* If any book subroutine failed, this records the failure reason
* (file not found, etc).
* This is a 'stack' that is one deep. (Should be deeper ??)
* FIXME: Each backend has its own error stack. The session
* and the backends should all be using (or making it look like)
* there is only one stack.
*/
QofBackendError last_err;
char *error_message;
/* ---------------------------------------------------- */
/* Pointer to the backend that is actually used to move data
* between the persistant store and the local engine. */
QofBackend *backend;
gint lock;
/* ---------------------------------------------------- */
/* Pointer to the backend that is actually used to move data
* between the persistant store and the local engine. */
QofBackend *backend;
gint lock;
};

File diff suppressed because it is too large Load Diff

View File

@ -22,38 +22,38 @@
/** @addtogroup Backend
*
* The QOF Session
* The QOF Session
* encapsulates a connection to a storage backend. That is, it
* manages the connection to a persistant data store; whereas
* the backend is the thing that performs the actual datastore
* the backend is the thing that performs the actual datastore
* access.
*
* This class provides several important services:
*
* 1) It resolves and loads the appropriate backend, based on
* 1) It resolves and loads the appropriate backend, based on
* the URL.
*
* 2) It reports backend errors (e.g. network errors, storage
* corruption errors) through a single, backend-independent
*
* 2) It reports backend errors (e.g. network errors, storage
* corruption errors) through a single, backend-independent
* API.
*
* 3) It reports non-error events received from the backend.
*
* 4) It helps manage global dataset locks. For example, for the
* file backend, the lock prevents multiple users from editing
* the same file at the same time, thus avoiding lost data due
* to race conditions. Thus, an open session implies that the
* file backend, the lock prevents multiple users from editing
* the same file at the same time, thus avoiding lost data due
* to race conditions. Thus, an open session implies that the
* associated file is locked.
*
* 5) Misc utilities, such as a search path for the file to be
* edited, and/or other URL resolution utilities. This should
* 5) Misc utilities, such as a search path for the file to be
* edited, and/or other URL resolution utilities. This should
* simplify install & maintenance problems for naive users who
* may not have a good grasp on what a file system is, or where
* they want to keep their data files.
*
* 6) In the future, this class is probably a good place to manage
* 6) In the future, this class is probably a good place to manage
* a portion of the user authentication process, and hold user
* credentials/cookies/keys/tokens. This is because at the
* credentials/cookies/keys/tokens. This is because at the
* coarsest level, authorization can happen at the datastore
* level: i.e. does this user even have the authority to connect
* to and open this datastore?
@ -65,13 +65,13 @@
* in the local process) and the datastore (the place where book
* data lives permanently, e.g., file, database).
*
* In the current design, a session may hold multiple books. For
* now, exactly what this means is somewhat vague, and code in
* In the current design, a session may hold multiple books. For
* now, exactly what this means is somewhat vague, and code in
* various places makes some implicit assumptions: first, only
* one book is 'current' and open for editing. Next, its assumed
* one book is 'current' and open for editing. Next, its assumed
* that all of the books in a session are related in some way.
* i.e. that they are all earlier accounting periods of the
* currently open book. In particular, the backends probably
* currently open book. In particular, the backends probably
* make that assumption, in order to store the different accounting
* periods in a clump so that one can be found, given another.
*
@ -84,8 +84,8 @@
also check if it can contact it's storage media (disk,
network, server, etc.) and abort if it can't. Malformed
file URL's would be handled the same way.
@{
@{
*/
/** @file qofsession.h
@ -129,13 +129,13 @@ void qof_session_swap_data (QofSession *session_1, QofSession *session_2);
* choose to search other, application-specific, directories as well.
*
* The 'ignore_lock' argument, if set to TRUE, will cause this routine
* to ignore any global-datastore locks (e.g. file locks) that it finds.
* If set to FALSE, then file/database-global locks will be tested and
* to ignore any global-datastore locks (e.g. file locks) that it finds.
* If set to FALSE, then file/database-global locks will be tested and
* obeyed.
*
* If the datastore exists, can be reached (e.g over the net),
* connected to, opened and read, and a lock can be obtained then
* a lock will be obtained. Note that multi-user datastores
* If the datastore exists, can be reached (e.g over the net),
* connected to, opened and read, and a lock can be obtained then
* a lock will be obtained. Note that multi-user datastores
* (e.g. the SQL backend) typically will not need to get a global
* lock, and thus, the user will not be locked out. That's the
* whole point of 'multi-user'.
@ -147,27 +147,27 @@ void qof_session_swap_data (QofSession *session_1, QofSession *session_2);
* stack, and that is where it should be examined.
*/
void qof_session_begin (QofSession *session, const char * book_id,
gboolean ignore_lock, gboolean create_if_nonexistent);
gboolean ignore_lock, gboolean create_if_nonexistent);
/**
* The qof_session_load() method causes the QofBook to be made ready to
* to use with this URL/datastore. When the URL points at a file,
* The qof_session_load() method causes the QofBook to be made ready to
* to use with this URL/datastore. When the URL points at a file,
* then this routine would load the data from the file. With remote
* backends, e.g. network or SQL, this would load only enough data
* to make the book actually usable; it would not cause *all* of the
* data to be loaded.
*
* XXX the current design tries to accomodate multiple calls to 'load'
* for each session, each time wiping out the old books; this seems
* wrong to me, and should be restricted to allow only one load per
* for each session, each time wiping out the old books; this seems
* wrong to me, and should be restricted to allow only one load per
* session.
*/
typedef void (*QofPercentageFunc) (const char *message, double percent);
void qof_session_load (QofSession *session,
QofPercentageFunc percentage_func);
QofPercentageFunc percentage_func);
/** @name Session Errors
/** @name Session Errors
@{ */
/** The qof_session_get_error() routine can be used to obtain the reason
* for any failure. Calling this routine returns the current error.
@ -177,10 +177,10 @@ const char * qof_session_get_error_message(const QofSession *session);
/**
* The qof_session_pop_error() routine can be used to obtain the reason
* for any failure. Calling this routine resets the error value.
* for any failure. Calling this routine resets the error value.
*
* This routine allows an implementation of multiple error values,
* e.g. in a stack, where this routine pops the top value. The current
* This routine allows an implementation of multiple error values,
* e.g. in a stack, where this routine pops the top value. The current
* implementation has a stack that is one-deep.
*
* See qofbackend.h for a listing of returned errors.
@ -189,7 +189,7 @@ QofBackendError qof_session_pop_error (QofSession *session);
/** @} */
/** The qof_session_add_book() allows additional books to be added to
* a session.
* a session.
* XXX Under construction, clarify the following when done:
* XXX There must already be an open book in the session already!?
* XXX Only one open book at a time per session is allowed!?
@ -204,13 +204,13 @@ QofBook * qof_session_get_book (const QofSession *session);
* path for the session. That is, if a relative or partial filename
* was for the session, then it had to have been fully resolved to
* open the session. This routine returns the result of this resolution.
* The path is always guaranteed to reside in the local file system,
* The path is always guaranteed to reside in the local file system,
* even if the session itself was opened as a URL. (currently, the
* filepath is derived from the url by substituting commas for
* slashes).
*
* The qof_session_get_url() routine returns the url that was opened.
* URL's for local files take the form of
* URL's for local files take the form of
* file:/some/where/some/file.gml
*/
const char * qof_session_get_file_path (const QofSession *session);
@ -234,13 +234,13 @@ gboolean qof_session_save_may_clobber_data (const QofSession *session);
* has already been written out to the database.
*/
void qof_session_save (QofSession *session,
QofPercentageFunc percentage_func);
QofPercentageFunc percentage_func);
/**
* The qof_session_end() method will release the session lock. For the
* file backend, it will *not* save the data to a file. Thus,
* file backend, it will *not* save the data to a file. Thus,
* this method acts as an "abort" or "rollback" primitive. However,
* for other backends, such as the sql backend, the data would have
* been written out before this, and so this routines wouldn't
* been written out before this, and so this routines wouldn't
* roll-back anything; it would just shut the connection.
*/
void qof_session_end (QofSession *session);
@ -249,17 +249,17 @@ void qof_session_end (QofSession *session);
Only certain backends can cope with selective copying of
entities and only fully defined QOF entities can be copied
between sessions - see the \ref QSF (QSF) documentation
between sessions - see the \ref QSF (QSF) documentation
(::qsf_write_file) for more information.
The recommended backend for the new session is QSF or a future
SQL backend. Using any of these entity copy functions sets a
SQL backend. Using any of these entity copy functions sets a
flag in the backend that this is now a partial QofBook. See \ref Reference.
When you save a session containing a partial QofBook,
the session will check that the backend is able to handle the
partial book. If not, the backend will be replaced by one that
can handle partial books, preferably one using the same
::access_method. Currently, this means that a book
::access_method. Currently, this means that a book
using the GnuCash XML v2 file backend will be switched to QSF.
Copied entities are identical to the source entity, all parameters
@ -270,7 +270,7 @@ as mechanisms for data export.
It is acceptable to add entities to new_session in batches. Note that
any of these calls will fail if an entity already exists in new_session
with the same GUID as any entity to be copied.
with the same GUID as any entity to be copied.
To merge a whole QofBook or where there is any possibility
of collisions or requirement for user intervention,
@ -281,9 +281,9 @@ see \ref BookMerge
*/
/** \brief Copy a single QofInstance to another session
Checks first that no entity in the session book contains
the GUID of the source entity.
the GUID of the source entity.
@param new_session - the target session
@param original - the QofInstance* to copy
@ -331,7 +331,7 @@ gboolean qof_instance_copy_coll(QofSession *new_session, QofCollection *entity_c
/** \brief Recursively copy a collection of entities to a session.
\note This function creates a <b>partial QofBook</b>. See
\note This function creates a <b>partial QofBook</b>. See
::qof_instance_copy_to_session for more information.
The QofBook in the new_session must \b not contain any entities
@ -347,7 +347,7 @@ down to the third level. See ::QofInstanceReference.
to the new session, including all parameters. The starting point is all
entities in the top level collection. It can take some time.
@param coll A QofCollection of entities that may or may not have
@param coll A QofCollection of entities that may or may not have
references.
@param new_session The QofSession to receive the copied entities.
@ -367,8 +367,8 @@ Copy the single entity and all referenced entities to the second level.
Only entities that are directly referenced by the top level entity are
copied.
This is a deep copy - all parameters of all referenced entities are copied. If
the top level entity has no references, this is identical to
This is a deep copy - all parameters of all referenced entities are copied. If
the top level entity has no references, this is identical to
::qof_instance_copy_to_session.
@param ent A single entity that may or may not have references.
@ -382,7 +382,7 @@ one of the references fails to copy.
gboolean
qof_instance_copy_one_r(QofSession *new_session, QofInstance *ent);
/** @}
/** @}
*/
/** \brief Allow session data to be printed to stdout
@ -406,13 +406,13 @@ backends may return a ::QofBackendError.
@{ */
/** The qof_session_events_pending() method will return TRUE if the
* backend has pending events which must be processed to bring
* backend has pending events which must be processed to bring
* the engine up to date with the backend.
*/
gboolean qof_session_events_pending (const QofSession *session);
/** The qof_session_process_events() method will process any events
* indicated by the qof_session_events_pending() method. It returns
* indicated by the qof_session_events_pending() method. It returns
* TRUE if the engine was modified while engine events were suspended.
*/
gboolean qof_session_process_events (QofSession *session);

File diff suppressed because it is too large Load Diff

View File

@ -37,8 +37,8 @@
/** @addtogroup SQL SQL Interface to Query
The types of SQL queries that are allowed at this point are very
limited. In general, only the following types of queries are
The types of SQL queries that are allowed at this point are very
limited. In general, only the following types of queries are
supported:
SELECT * FROM SomeObj WHERE (param_a < 10.0) AND (param_b = "asdf")
SORT BY param_c DESC;
@ -47,9 +47,9 @@ supported:
For SELECT, the returned list is a list of all of the instances of 'SomeObj' that
match the query. The 'SORT' term is optional. The 'WHERE' term is
optional; but if you don't include 'WHERE', you will get a list of
optional; but if you don't include 'WHERE', you will get a list of
all of the object instances. The Boolean operations 'AND' and 'OR'
together with parenthesis can be used to construct arbitrarily
together with parenthesis can be used to construct arbitrarily
nested predicates.
For INSERT, the returned list is a list containing the newly created instance
@ -85,8 +85,8 @@ user input into UTC time using the ::QOF_UTC_DATE_FORMAT string.
e.g. set the UTC date format and call ::qof_print_time_buff
with a time_t obtained via ::timespecToTime_t.
If the param is a KVP frame, then we use a special markup to
indicate frame values. The markup should look like
If the param is a KVP frame, then we use a special markup to
indicate frame values. The markup should look like
/some/kvp/path:value. Thus, for example,
SELECT * FROM SomeObj WHERE (param_a < '/some/kvp:10.0')
will search for the object where param_a is a KVP frame, and this
@ -108,8 +108,8 @@ SELECT d,f,k FROM ObjB; qof_object_new_instance(); ObjC_set_a(value_c);
ObjC_set_b(value_k) etc. What's needed is for the SELECT to return
a complete object that only contains the parameters selected.
Also unsupported: UPDATE.
Also unsupported: UPDATE.
Certain SQL commands can have no QOF equivalent and will
generate a runtime parser error:
- ALTER
@ -141,7 +141,7 @@ void qof_sql_query_set_book (QofSqlQuery *q, QofBook *book);
* The book must be set in order to be able to perform a query.
*
* The returned list will have been sorted using the indicated sort
* The returned list will have been sorted using the indicated sort
* order, (by default ascending order) and trimmed to the
* max_results length.
* Do NOT free the resulting list. This list is managed internally
@ -161,7 +161,7 @@ void qof_sql_query_parse (QofSqlQuery *query, const gchar * str);
/** Return the QofQuery form of the previously parsed query. */
QofQuery * qof_sql_query_get_query (QofSqlQuery *);
/** Run the previously parsed query. The QofBook must be set
/** Run the previously parsed query. The QofBook must be set
* before this function can be called. Note, teh QofBook can
* be changed between each successive call to this routine.
* This routine can be called after either qof_sql_query_parse()
@ -169,29 +169,29 @@ QofQuery * qof_sql_query_get_query (QofSqlQuery *);
*/
GList * qof_sql_query_rerun (QofSqlQuery *query);
/**
/**
* Set the kvp frame to be used for formulating 'indirect' predicates.
*
* Although joins are not supported (see above), there is one special
* hack that one can use to pass data indirectly into the predicates.
* This is by using a KVP key name to reference the value to be used
* for a predicate. Thus, for example,
* for a predicate. Thus, for example,
* SELECT * FROM SomeObj WHERE (param_a = KVP:/some/key/path);
* will look up the value stored at '/some/key/path', and use that
* value to form the actual predicate. So, for example, if
* the value stored at '/some/key/path' was 2, then the actual
* query run will be
* value to form the actual predicate. So, for example, if
* the value stored at '/some/key/path' was 2, then the actual
* query run will be
* SELECT * FROM SomeObj WHERE (param_a = 2);
* The lookup occurs at the time that the query is formulated.
*
* The query does *not* take over ownership of the kvp frame,
* nor does it copy it. Thus, the kvp frame must exist when the
* query is formulated, and it is the responsibility of the
* query is formulated, and it is the responsibility of the
* caller to free it when no longer needed.
*
* Note that because this feature is a kind of a hack put in place
* due to the lack of support for joins, it will probably go away
* (be deprecated) if/when joins are implemented.
* (be deprecated) if/when joins are implemented.
*/
void qof_sql_query_set_kvp (QofSqlQuery *, KvpFrame *);

View File

@ -80,53 +80,61 @@ qof_utf8_strcasecmp (const gchar *da, const gchar *db)
return retval;
}
gint
gint
safe_strcmp (const gchar * da, const gchar * db)
{
if ((da) && (db)) {
if ((da) != (db)) {
gint retval = strcmp ((da), (db));
/* if strings differ, return */
if (retval) return retval;
}
} else
if ((!(da)) && (db)) {
return -1;
} else
if ((da) && (!(db))) {
return +1;
}
return 0;
if ((da) && (db))
{
if ((da) != (db))
{
gint retval = strcmp ((da), (db));
/* if strings differ, return */
if (retval) return retval;
}
}
else if ((!(da)) && (db))
{
return -1;
}
else if ((da) && (!(db)))
{
return +1;
}
return 0;
}
gint
gint
safe_strcasecmp (const gchar * da, const gchar * db)
{
if ((da) && (db)) {
if ((da) != (db)) {
gint retval = qof_utf8_strcasecmp ((da), (db));
/* if strings differ, return */
if (retval) return retval;
}
} else
if ((!(da)) && (db)) {
return -1;
} else
if ((da) && (!(db))) {
return +1;
if ((da) && (db))
{
if ((da) != (db))
{
gint retval = qof_utf8_strcasecmp ((da), (db));
/* if strings differ, return */
if (retval) return retval;
}
}
return 0;
else if ((!(da)) && (db))
{
return -1;
}
else if ((da) && (!(db)))
{
return +1;
}
return 0;
}
gint
gint
null_strcmp (const gchar * da, const gchar * db)
{
if (da && db) return strcmp (da, db);
if (!da && db && 0==db[0]) return 0;
if (!db && da && 0==da[0]) return 0;
if (!da && db) return -1;
if (da && !db) return +1;
return 0;
if (da && db) return strcmp (da, db);
if (!da && db && 0 == db[0]) return 0;
if (!db && da && 0 == da[0]) return 0;
if (!da && db) return -1;
if (da && !db) return +1;
return 0;
}
#define MAX_DIGITS 50
@ -135,41 +143,47 @@ null_strcmp (const gchar * da, const gchar * db)
gchar *
ultostr (gulong val, gint base)
{
gchar buf[MAX_DIGITS];
gulong broke[MAX_DIGITS];
gint i;
gulong places=0, reval;
if ((2>base) || (36<base)) return NULL;
gchar buf[MAX_DIGITS];
gulong broke[MAX_DIGITS];
gint i;
gulong places = 0, reval;
/* count digits */
places = 0;
for (i=0; i<MAX_DIGITS; i++) {
broke[i] = val;
places ++;
val /= base;
if (0 == val) break;
}
if ((2 > base) || (36 < base)) return NULL;
/* normalize */
reval = 0;
for (i=places-2; i>=0; i--) {
reval += broke[i+1];
reval *= base;
broke[i] -= reval;
}
/* print */
for (i=0; i<(gint)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 capital A */
/* count digits */
places = 0;
for (i = 0; i < MAX_DIGITS; i++)
{
broke[i] = val;
places ++;
val /= base;
if (0 == val) break;
}
}
buf[places] = 0x0;
return g_strdup (buf);
/* normalize */
reval = 0;
for (i = places - 2; i >= 0; i--)
{
reval += broke[i+1];
reval *= base;
broke[i] -= reval;
}
/* print */
for (i = 0; i < (gint)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 capital A */
}
}
buf[places] = 0x0;
return g_strdup (buf);
}
/* =================================================================== */
@ -179,63 +193,63 @@ ultostr (gulong val, gint base)
gboolean
gnc_strisnum(const gchar *s)
{
if (s == NULL) return FALSE;
if (*s == 0) return FALSE;
if (s == NULL) return FALSE;
if (*s == 0) return FALSE;
while (*s && isspace(*s))
s++;
while (*s && isspace(*s))
s++;
if (*s == 0) return FALSE;
if (!isdigit(*s)) return FALSE;
if (*s == 0) return FALSE;
if (!isdigit(*s)) return FALSE;
while (*s && isdigit(*s))
s++;
while (*s && isdigit(*s))
s++;
if (*s == 0) return TRUE;
if (*s == 0) return TRUE;
while (*s && isspace(*s))
s++;
while (*s && isspace(*s))
s++;
if (*s == 0) return TRUE;
if (*s == 0) return TRUE;
return FALSE;
return FALSE;
}
/* =================================================================== */
/* Return NULL if the field is whitespace (blank, tab, formfeed etc.)
/* Return NULL if the field is whitespace (blank, tab, formfeed etc.)
* Else return pointer to first non-whitespace character. */
/* =================================================================== */
const gchar *
qof_util_whitespace_filter (const gchar * val)
{
size_t len;
if (!val) return NULL;
size_t len;
if (!val) return NULL;
len = strspn (val, "\a\b\t\n\v\f\r ");
if (0 == val[len]) return NULL;
return val+len;
len = strspn (val, "\a\b\t\n\v\f\r ");
if (0 == val[len]) return NULL;
return val + len;
}
/* =================================================================== */
/* Return integer 1 if the string starts with 't' or 'T' or contains the
/* Return integer 1 if the string starts with 't' or 'T' or contains the
* word 'true' or 'TRUE'; if string is a number, return that number. */
/* =================================================================== */
gint
qof_util_bool_to_int (const gchar * val)
{
const gchar * p = qof_util_whitespace_filter (val);
if (!p) return 0;
if ('t' == p[0]) return 1;
if ('T' == p[0]) return 1;
if ('y' == p[0]) return 1;
if ('Y' == p[0]) return 1;
if (strstr (p, "true")) return 1;
if (strstr (p, "TRUE")) return 1;
if (strstr (p, "yes")) return 1;
if (strstr (p, "YES")) return 1;
return atoi (val);
const gchar * p = qof_util_whitespace_filter (val);
if (!p) return 0;
if ('t' == p[0]) return 1;
if ('T' == p[0]) return 1;
if ('y' == p[0]) return 1;
if ('Y' == p[0]) return 1;
if (strstr (p, "true")) return 1;
if (strstr (p, "TRUE")) return 1;
if (strstr (p, "yes")) return 1;
if (strstr (p, "YES")) return 1;
return atoi (val);
}
/* =================================================================== */
@ -245,22 +259,28 @@ qof_util_bool_to_int (const gchar * val)
static GCache * qof_string_cache = NULL;
#ifdef THESE_CAN_BE_USEFUL_FOR_DEGUGGING
static guint g_str_hash_KEY(gconstpointer v) {
static guint g_str_hash_KEY(gconstpointer v)
{
return g_str_hash(v);
}
static guint g_str_hash_VAL(gconstpointer v) {
static guint g_str_hash_VAL(gconstpointer v)
{
return g_str_hash(v);
}
static gpointer g_strdup_VAL(gpointer v) {
static gpointer g_strdup_VAL(gpointer v)
{
return g_strdup(v);
}
static gpointer g_strdup_KEY(gpointer v) {
static gpointer g_strdup_KEY(gpointer v)
{
return g_strdup(v);
}
static void g_free_VAL(gpointer v) {
static void g_free_VAL(gpointer v)
{
return g_free(v);
}
static void g_free_KEY(gpointer v) {
static void g_free_KEY(gpointer v)
{
return g_free(v);
}
static gboolean qof_util_str_equal(gconstpointer v, gconstpointer v2)
@ -271,15 +291,16 @@ static gboolean qof_util_str_equal(gconstpointer v, gconstpointer v2)
static GCache*
qof_util_get_string_cache(void)
{
if(!qof_string_cache) {
if (!qof_string_cache)
{
qof_string_cache = g_cache_new(
(GCacheNewFunc) g_strdup, /* value_new_func */
g_free, /* value_destroy_func */
(GCacheDupFunc) g_strdup, /* key_dup_func */
g_free, /* key_destroy_func */
g_str_hash, /* hash_key_func */
g_str_hash, /* hash_value_func */
g_str_equal); /* key_equal_func */
(GCacheNewFunc) g_strdup, /* value_new_func */
g_free, /* value_destroy_func */
(GCacheDupFunc) g_strdup, /* key_dup_func */
g_free, /* key_destroy_func */
g_str_hash, /* hash_key_func */
g_str_hash, /* hash_value_func */
g_str_equal); /* key_equal_func */
}
return qof_string_cache;
}
@ -296,7 +317,7 @@ void
qof_util_string_cache_remove(gconstpointer key)
{
if (key)
g_cache_remove(qof_util_get_string_cache(), key);
g_cache_remove(qof_util_get_string_cache(), key);
}
gpointer
@ -310,168 +331,199 @@ qof_util_string_cache_insert(gconstpointer key)
gchar*
qof_util_param_as_string(QofInstance *ent, QofParam *param)
{
gchar *param_string, param_date[MAX_DATE_LENGTH];
gchar param_sa[GUID_ENCODING_LENGTH + 1];
gchar *param_string, param_date[MAX_DATE_LENGTH];
gchar param_sa[GUID_ENCODING_LENGTH + 1];
gboolean known_type;
QofType paramType;
const GUID *param_guid;
time_t param_t;
gnc_numeric param_numeric, (*numeric_getter) (QofInstance*, QofParam*);
Timespec param_ts, (*date_getter) (QofInstance*, QofParam*);
double param_double, (*double_getter) (QofInstance*, QofParam*);
gboolean param_boolean, (*boolean_getter) (QofInstance*, QofParam*);
gint32 param_i32, (*int32_getter) (QofInstance*, QofParam*);
gint64 param_i64, (*int64_getter) (QofInstance*, QofParam*);
gchar param_char, (*char_getter) (QofInstance*, QofParam*);
QofType paramType;
const GUID *param_guid;
time_t param_t;
gnc_numeric param_numeric, (*numeric_getter) (QofInstance*, QofParam*);
Timespec param_ts, (*date_getter) (QofInstance*, QofParam*);
double param_double, (*double_getter) (QofInstance*, QofParam*);
gboolean param_boolean, (*boolean_getter) (QofInstance*, QofParam*);
gint32 param_i32, (*int32_getter) (QofInstance*, QofParam*);
gint64 param_i64, (*int64_getter) (QofInstance*, QofParam*);
gchar param_char, (*char_getter) (QofInstance*, QofParam*);
param_string = NULL;
param_string = NULL;
known_type = FALSE;
paramType = param->param_type;
if(safe_strcmp(paramType, QOF_TYPE_STRING) == 0) {
param_string = g_strdup(param->param_getfcn(ent, param));
if(param_string == NULL) { param_string = ""; }
known_type = TRUE;
return param_string;
}
if(safe_strcmp(paramType, QOF_TYPE_DATE) == 0) {
date_getter = (Timespec (*)(QofInstance*, QofParam*))param->param_getfcn;
param_ts = date_getter(ent, param);
param_t = timespecToTime_t(param_ts);
qof_strftime(param_date, MAX_DATE_LENGTH,
QOF_UTC_DATE_FORMAT, gmtime(&param_t));
param_string = g_strdup(param_date);
known_type = TRUE;
return param_string;
}
if((safe_strcmp(paramType, QOF_TYPE_NUMERIC) == 0) ||
(safe_strcmp(paramType, QOF_TYPE_DEBCRED) == 0)) {
numeric_getter = (gnc_numeric (*)(QofInstance*, QofParam*)) param->param_getfcn;
param_numeric = numeric_getter(ent, param);
param_string = g_strdup(gnc_numeric_to_string(param_numeric));
known_type = TRUE;
return param_string;
}
if(safe_strcmp(paramType, QOF_TYPE_GUID) == 0) {
param_guid = param->param_getfcn(ent, param);
guid_to_string_buff(param_guid, param_sa);
param_string = g_strdup(param_sa);
known_type = TRUE;
return param_string;
}
if(safe_strcmp(paramType, QOF_TYPE_INT32) == 0) {
int32_getter = (gint32 (*)(QofInstance*, QofParam*)) param->param_getfcn;
param_i32 = int32_getter(ent, param);
param_string = g_strdup_printf("%d", param_i32);
known_type = TRUE;
return param_string;
}
if(safe_strcmp(paramType, QOF_TYPE_INT64) == 0) {
int64_getter = (gint64 (*)(QofInstance*, QofParam*)) param->param_getfcn;
param_i64 = int64_getter(ent, param);
param_string = g_strdup_printf("%"G_GINT64_FORMAT, param_i64);
known_type = TRUE;
return param_string;
}
if(safe_strcmp(paramType, QOF_TYPE_DOUBLE) == 0) {
double_getter = (double (*)(QofInstance*, QofParam*)) param->param_getfcn;
param_double = double_getter(ent, param);
param_string = g_strdup_printf("%f", param_double);
known_type = TRUE;
return param_string;
}
if(safe_strcmp(paramType, QOF_TYPE_BOOLEAN) == 0){
boolean_getter = (gboolean (*)(QofInstance*, QofParam*)) param->param_getfcn;
param_boolean = boolean_getter(ent, param);
/* Boolean values need to be lowercase for QSF validation. */
if(param_boolean == TRUE) { param_string = g_strdup("true"); }
else { param_string = g_strdup("false"); }
known_type = TRUE;
return param_string;
}
/* "kvp" contains repeating values, cannot be a single string for the frame. */
if(safe_strcmp(paramType, QOF_TYPE_KVP) == 0) {
KvpFrame *frame = NULL;
frame = param->param_getfcn(ent, param);
known_type = TRUE;
if(!kvp_frame_is_empty(frame))
{
GHashTable *hash = kvp_frame_get_hash(frame);
param_string = g_strdup_printf("%s(%d)", QOF_TYPE_KVP,
g_hash_table_size(hash));
}
return param_string;
}
if(safe_strcmp(paramType, QOF_TYPE_CHAR) == 0) {
char_getter = (gchar (*)(QofInstance*, QofParam*)) param->param_getfcn;
param_char = char_getter(ent, param);
known_type = TRUE;
return g_strdup_printf("%c", param_char);
}
/* "collect" contains repeating values, cannot be a single string. */
if(safe_strcmp(paramType, QOF_TYPE_COLLECT) == 0)
paramType = param->param_type;
if (safe_strcmp(paramType, QOF_TYPE_STRING) == 0)
{
param_string = g_strdup(param->param_getfcn(ent, param));
if (param_string == NULL)
{
QofCollection *col = NULL;
col = param->param_getfcn(ent, param);
known_type = TRUE;
return g_strdup_printf("%s(%d)",
qof_collection_get_type(col), qof_collection_count(col));
param_string = "";
}
if(safe_strcmp(paramType, QOF_TYPE_CHOICE) == 0)
known_type = TRUE;
return param_string;
}
if (safe_strcmp(paramType, QOF_TYPE_DATE) == 0)
{
date_getter = (Timespec (*)(QofInstance*, QofParam*))param->param_getfcn;
param_ts = date_getter(ent, param);
param_t = timespecToTime_t(param_ts);
qof_strftime(param_date, MAX_DATE_LENGTH,
QOF_UTC_DATE_FORMAT, gmtime(&param_t));
param_string = g_strdup(param_date);
known_type = TRUE;
return param_string;
}
if ((safe_strcmp(paramType, QOF_TYPE_NUMERIC) == 0) ||
(safe_strcmp(paramType, QOF_TYPE_DEBCRED) == 0))
{
numeric_getter = (gnc_numeric (*)(QofInstance*, QofParam*)) param->param_getfcn;
param_numeric = numeric_getter(ent, param);
param_string = g_strdup(gnc_numeric_to_string(param_numeric));
known_type = TRUE;
return param_string;
}
if (safe_strcmp(paramType, QOF_TYPE_GUID) == 0)
{
param_guid = param->param_getfcn(ent, param);
guid_to_string_buff(param_guid, param_sa);
param_string = g_strdup(param_sa);
known_type = TRUE;
return param_string;
}
if (safe_strcmp(paramType, QOF_TYPE_INT32) == 0)
{
int32_getter = (gint32 (*)(QofInstance*, QofParam*)) param->param_getfcn;
param_i32 = int32_getter(ent, param);
param_string = g_strdup_printf("%d", param_i32);
known_type = TRUE;
return param_string;
}
if (safe_strcmp(paramType, QOF_TYPE_INT64) == 0)
{
int64_getter = (gint64 (*)(QofInstance*, QofParam*)) param->param_getfcn;
param_i64 = int64_getter(ent, param);
param_string = g_strdup_printf("%"G_GINT64_FORMAT, param_i64);
known_type = TRUE;
return param_string;
}
if (safe_strcmp(paramType, QOF_TYPE_DOUBLE) == 0)
{
double_getter = (double (*)(QofInstance*, QofParam*)) param->param_getfcn;
param_double = double_getter(ent, param);
param_string = g_strdup_printf("%f", param_double);
known_type = TRUE;
return param_string;
}
if (safe_strcmp(paramType, QOF_TYPE_BOOLEAN) == 0)
{
boolean_getter = (gboolean (*)(QofInstance*, QofParam*)) param->param_getfcn;
param_boolean = boolean_getter(ent, param);
/* Boolean values need to be lowercase for QSF validation. */
if (param_boolean == TRUE)
{
QofInstance *child = NULL;
child = param->param_getfcn(ent, param);
if(!child) { return param_string; }
known_type = TRUE;
return g_strdup(qof_object_printable(child->e_type, child));
param_string = g_strdup("true");
}
if(safe_strcmp(paramType, QOF_PARAM_BOOK) == 0)
else
{
param_string = g_strdup("false");
}
known_type = TRUE;
return param_string;
}
/* "kvp" contains repeating values, cannot be a single string for the frame. */
if (safe_strcmp(paramType, QOF_TYPE_KVP) == 0)
{
KvpFrame *frame = NULL;
frame = param->param_getfcn(ent, param);
known_type = TRUE;
if (!kvp_frame_is_empty(frame))
{
GHashTable *hash = kvp_frame_get_hash(frame);
param_string = g_strdup_printf("%s(%d)", QOF_TYPE_KVP,
g_hash_table_size(hash));
}
return param_string;
}
if (safe_strcmp(paramType, QOF_TYPE_CHAR) == 0)
{
char_getter = (gchar (*)(QofInstance*, QofParam*)) param->param_getfcn;
param_char = char_getter(ent, param);
known_type = TRUE;
return g_strdup_printf("%c", param_char);
}
/* "collect" contains repeating values, cannot be a single string. */
if (safe_strcmp(paramType, QOF_TYPE_COLLECT) == 0)
{
QofCollection *col = NULL;
col = param->param_getfcn(ent, param);
known_type = TRUE;
return g_strdup_printf("%s(%d)",
qof_collection_get_type(col), qof_collection_count(col));
}
if (safe_strcmp(paramType, QOF_TYPE_CHOICE) == 0)
{
QofInstance *child = NULL;
child = param->param_getfcn(ent, param);
if (!child)
{
QofBackend *be;
QofBook *book;
book = param->param_getfcn(ent, param);
PINFO (" book param %p", book);
be = qof_book_get_backend(book);
known_type = TRUE;
PINFO (" backend=%p", be);
if(!be) { return QOF_PARAM_BOOK; }
param_string = g_strdup(be->fullpath);
PINFO (" fullpath=%s", param_string);
if(param_string) { return param_string; }
param_guid = qof_book_get_guid(book);
guid_to_string_buff(param_guid, param_sa);
PINFO (" book GUID=%s", param_sa);
param_string = g_strdup(param_sa);
return param_string;
}
if(!known_type)
known_type = TRUE;
return g_strdup(qof_object_printable(child->e_type, child));
}
if (safe_strcmp(paramType, QOF_PARAM_BOOK) == 0)
{
QofBackend *be;
QofBook *book;
book = param->param_getfcn(ent, param);
PINFO (" book param %p", book);
be = qof_book_get_backend(book);
known_type = TRUE;
PINFO (" backend=%p", be);
if (!be)
{
QofInstance *child = NULL;
child = param->param_getfcn(ent, param);
if(!child) { return param_string; }
return g_strdup(qof_object_printable(child->e_type, child));
return QOF_PARAM_BOOK;
}
return g_strdup("");
param_string = g_strdup(be->fullpath);
PINFO (" fullpath=%s", param_string);
if (param_string)
{
return param_string;
}
param_guid = qof_book_get_guid(book);
guid_to_string_buff(param_guid, param_sa);
PINFO (" book GUID=%s", param_sa);
param_string = g_strdup(param_sa);
return param_string;
}
if (!known_type)
{
QofInstance *child = NULL;
child = param->param_getfcn(ent, param);
if (!child)
{
return param_string;
}
return g_strdup(qof_object_printable(child->e_type, child));
}
return g_strdup("");
}
void
qof_init (void)
{
g_type_init();
qof_log_init();
qof_util_get_string_cache ();
guid_init ();
qof_object_initialize ();
qof_query_init ();
qof_book_register ();
g_type_init();
qof_log_init();
qof_util_get_string_cache ();
guid_init ();
qof_object_initialize ();
qof_query_init ();
qof_book_register ();
}
void
qof_close(void)
{
qof_query_shutdown ();
qof_object_shutdown ();
guid_shutdown ();
qof_util_string_cache_destroy ();
qof_query_shutdown ();
qof_object_shutdown ();
guid_shutdown ();
qof_util_string_cache_destroy ();
qof_log_shutdown();
}

View File

@ -104,10 +104,10 @@
Similar but used when the enum is NOT a typedef
Make sure you use the DEFINE_ENUM_NON_TYPEDEF macro.
You can precede the FROM_STRING_FUNC_NON_TYPEDEF
and AS_STRING_FUNC_NON_TYPEDEF macros with the
You can precede the FROM_STRING_FUNC_NON_TYPEDEF
and AS_STRING_FUNC_NON_TYPEDEF macros with the
keyword static if appropriate.
ENUM_BODY is used in both types.
*/
@ -146,17 +146,17 @@
/** @name Convenience wrappers
@{
*/
/** \brief Initialise the Query Object Framework
/** \brief Initialise the Query Object Framework
Use in place of separate init functions (like guid_init()
and qof_query_init() etc.) to protect against future changes.
*/
void qof_init (void);
/** \brief Safely close down the Query Object Framework
/** \brief Safely close down the Query Object Framework
Use in place of separate close / shutdown functions
Use in place of separate close / shutdown functions
(like guid_shutdown(), qof_query_shutdown() etc.) to protect
against future changes.
*/
@ -179,29 +179,29 @@ gint qof_utf8_strcasecmp (const gchar *da, const gchar *db);
/** The safe_strcmp compares strings da and db the same way that strcmp()
does, except that either may be null. This routine assumes that
a non-null string is always greater than a null string.
@param da string 1.
@param db string 2.
@return If da == NULL && db != NULL, returns -1.
If da != NULL && db == NULL, returns +1.
If da != NULL && db != NULL, returns the result of
If da != NULL && db != NULL, returns the result of
strcmp(da, db).
If da == NULL && db == NULL, returns 0.
If da == NULL && db == NULL, returns 0.
*/
gint safe_strcmp (const gchar * da, const gchar * db);
/** case sensitive comparison of strings da and db - either
may be NULL. A non-NULL string is greater than a NULL string.
@param da string 1.
@param db string 2.
@return If da == NULL && db != NULL, returns -1.
If da != NULL && db == NULL, returns +1.
If da != NULL && db != NULL, returns the result of
If da != NULL && db != NULL, returns the result of
strcmp(da, db).
If da == NULL && db == NULL, returns 0.
If da == NULL && db == NULL, returns 0.
*/
gint safe_strcasecmp (const gchar * da, const gchar * db);
@ -224,13 +224,13 @@ gboolean gnc_strisnum(const gchar *s);
#define stpcpy g_stpcpy
#endif
/** Return NULL if the field is whitespace (blank, tab, formfeed etc.)
* Else return pointer to first non-whitespace character.
/** Return NULL if the field is whitespace (blank, tab, formfeed etc.)
* Else return pointer to first non-whitespace character.
*/
const gchar * qof_util_whitespace_filter (const gchar * val);
/** Return integer 1 if the string starts with 't' or 'T' or
* contains the word 'true' or 'TRUE'; if string is a number,
/** Return integer 1 if the string starts with 't' or 'T' or
* contains the word 'true' or 'TRUE'; if string is a number,
* return that number. (Leading whitespace is ignored). */
gint qof_util_bool_to_int (const gchar * val);
@ -311,31 +311,31 @@ gboolean qof_begin_edit(QofInstance *inst);
/**
* commit_edit helpers
*
* The caller should call PART1 as the first thing, then
* The caller should call PART1 as the first thing, then
* perform any local operations prior to calling the backend.
* Then call PART2.
* Then call PART2.
*/
/**
* part1 -- deal with the editlevel
*
*
* @param inst: an instance of QofInstance
*/
gboolean qof_commit_edit(QofInstance *inst);
/**
* part2 -- deal with the backend
*
*
* @param inst: an instance of QofInstance
* @param on_error: a function called if there is a backend error.
* void (*on_error)(inst, QofBackendError)
* @param on_done: a function called after the commit is completed
* @param on_done: a function called after the commit is completed
* successfully for an object which remained valid.
* void (*on_done)(inst)
* @param on_free: a function called if the commit succeeded and the instance
* is to be freed.
* is to be freed.
* void (*on_free)(inst)
*
*
* Note that only *one* callback will be called (or zero, if that
* callback is NULL). In particular, 'on_done' will not be called for
* an object which is to be freed.
@ -343,10 +343,10 @@ gboolean qof_commit_edit(QofInstance *inst);
* Returns TRUE, if the commit succeeded, FALSE otherwise.
*/
gboolean
qof_commit_edit_part2(QofInstance *inst,
void (*on_error)(QofInstance *, QofBackendError),
void (*on_done)(QofInstance *),
qof_commit_edit_part2(QofInstance *inst,
void (*on_error)(QofInstance *, QofBackendError),
void (*on_done)(QofInstance *),
void (*on_free)(QofInstance *));
#endif /* QOF_UTIL_H */
/** @} */