mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
move Query private data structures to private file
git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@6498 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
da15715647
commit
d4ff335f23
@ -74,6 +74,7 @@ noinst_HEADERS = \
|
|||||||
FreqSpecP.h \
|
FreqSpecP.h \
|
||||||
GNCIdP.h \
|
GNCIdP.h \
|
||||||
GroupP.h \
|
GroupP.h \
|
||||||
|
QueryP.h \
|
||||||
SchedXactionP.h \
|
SchedXactionP.h \
|
||||||
SX-ttinfo.h \
|
SX-ttinfo.h \
|
||||||
TransactionP.h \
|
TransactionP.h \
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include "BackendP.h"
|
#include "BackendP.h"
|
||||||
#include "GNCId.h"
|
#include "GNCId.h"
|
||||||
#include "GroupP.h"
|
#include "GroupP.h"
|
||||||
|
#include "QueryP.h"
|
||||||
#include "Query.h"
|
#include "Query.h"
|
||||||
#include "TransactionP.h"
|
#include "TransactionP.h"
|
||||||
|
|
||||||
@ -52,7 +53,8 @@ static short module = MOD_QUERY;
|
|||||||
* - a chop limit which gives the maximum number of sorted
|
* - a chop limit which gives the maximum number of sorted
|
||||||
* splits to return. */
|
* splits to return. */
|
||||||
|
|
||||||
struct _querystruct {
|
struct query_s
|
||||||
|
{
|
||||||
/* terms is a list of the OR-terms in a sum-of-products
|
/* terms is a list of the OR-terms in a sum-of-products
|
||||||
* logical expression. */
|
* logical expression. */
|
||||||
GList * terms;
|
GList * terms;
|
||||||
@ -66,14 +68,17 @@ struct _querystruct {
|
|||||||
gboolean tertiary_increasing;
|
gboolean tertiary_increasing;
|
||||||
int max_splits;
|
int max_splits;
|
||||||
|
|
||||||
|
/* list of books that will be participating in the query */
|
||||||
|
BookList *books;
|
||||||
|
|
||||||
/* cache the results so we don't have to run the whole search
|
/* cache the results so we don't have to run the whole search
|
||||||
* again until it's really necessary */
|
* again until it's really necessary */
|
||||||
int changed;
|
int changed;
|
||||||
query_run_t last_run_type;
|
query_run_t last_run_type;
|
||||||
AccountGroup * acct_group;
|
AccountGroup * acct_group;
|
||||||
|
|
||||||
GList * split_list;
|
SplitList * split_list;
|
||||||
GList * xtn_list;
|
TransList * xtn_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
@ -131,10 +136,12 @@ xaccQueryPrint(Query * q)
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
/* print the node contents */
|
/* print the node contents */
|
||||||
for(i=q->terms; i; i=i->next) {
|
for(i=q->terms; i; i=i->next)
|
||||||
|
{
|
||||||
aterms = i->data;
|
aterms = i->data;
|
||||||
printf("aterm=%p\n", aterms);
|
printf("aterm=%p\n", aterms);
|
||||||
for(j=aterms; j; j=j->next) {
|
for(j=aterms; j; j=j->next)
|
||||||
|
{
|
||||||
qt = (QueryTerm *)j->data;
|
qt = (QueryTerm *)j->data;
|
||||||
switch (qt->data.base.term_type)
|
switch (qt->data.base.term_type)
|
||||||
{
|
{
|
||||||
@ -158,14 +165,17 @@ xaccQueryPrint(Query * q)
|
|||||||
qt->data.str.case_sens);
|
qt->data.str.case_sens);
|
||||||
printf ("\tmatch string=%s \n", qt->data.str.matchstring);
|
printf ("\tmatch string=%s \n", qt->data.str.matchstring);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PR_BALANCE:
|
case PR_BALANCE:
|
||||||
printf ("balance sense=%d how=%d\n", qt->data.balance.sense,
|
printf ("balance sense=%d how=%d\n", qt->data.balance.sense,
|
||||||
qt->data.balance.how);
|
qt->data.balance.how);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PR_CLEARED:
|
case PR_CLEARED:
|
||||||
printf ("cleared sense=%d how=%d\n", qt->data.cleared.sense,
|
printf ("cleared sense=%d how=%d\n", qt->data.cleared.sense,
|
||||||
qt->data.cleared.how);
|
qt->data.cleared.how);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PR_DATE: {
|
case PR_DATE: {
|
||||||
char buff[40];
|
char buff[40];
|
||||||
printf ("date sense=%d use_start=%d use_end=%d\n",
|
printf ("date sense=%d use_start=%d use_end=%d\n",
|
||||||
@ -220,20 +230,24 @@ xaccQueryPrint(Query * q)
|
|||||||
qt->data.str.case_sens);
|
qt->data.str.case_sens);
|
||||||
printf ("\tmatch string=%s \n", qt->data.str.matchstring);
|
printf ("\tmatch string=%s \n", qt->data.str.matchstring);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PR_MISC:
|
case PR_MISC:
|
||||||
printf ("misc\n");
|
printf ("misc\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PR_NUM:
|
case PR_NUM:
|
||||||
printf ("num sense=%d case sensitive=%d\n", qt->data.str.sense,
|
printf ("num sense=%d case sensitive=%d\n", qt->data.str.sense,
|
||||||
qt->data.str.case_sens);
|
qt->data.str.case_sens);
|
||||||
printf ("\tmatch string=%s \n", qt->data.str.matchstring);
|
printf ("\tmatch string=%s \n", qt->data.str.matchstring);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PR_PRICE:
|
case PR_PRICE:
|
||||||
printf ("price sense=%d how=%d\n", qt->data.amount.sense,
|
printf ("price sense=%d how=%d\n", qt->data.amount.sense,
|
||||||
qt->data.amount.how);
|
qt->data.amount.how);
|
||||||
printf ("\tsign=%d amount=%f\n", qt->data.amount.amt_sgn,
|
printf ("\tsign=%d amount=%f\n", qt->data.amount.amt_sgn,
|
||||||
qt->data.amount.amount);
|
qt->data.amount.amount);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PR_SHRS:
|
case PR_SHRS:
|
||||||
printf ("shrs sense=%d how=%d\n", qt->data.amount.sense,
|
printf ("shrs sense=%d how=%d\n", qt->data.amount.sense,
|
||||||
qt->data.amount.how);
|
qt->data.amount.how);
|
||||||
@ -266,6 +280,7 @@ xaccQueryPrint(Query * q)
|
|||||||
|
|
||||||
/* initial_term has hand-over semantics! Thus, initial_term must point
|
/* initial_term has hand-over semantics! Thus, initial_term must point
|
||||||
* to newly allocated memory or be NULL. */
|
* to newly allocated memory or be NULL. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
xaccInitQuery(Query * q, QueryTerm * initial_term)
|
xaccInitQuery(Query * q, QueryTerm * initial_term)
|
||||||
{
|
{
|
||||||
@ -280,8 +295,9 @@ xaccInitQuery(Query * q, QueryTerm * initial_term)
|
|||||||
or->data = and;
|
or->data = and;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(q->terms)
|
if(q->terms) xaccQueryClear(q);
|
||||||
xaccQueryClear(q);
|
|
||||||
|
q->books = NULL;
|
||||||
|
|
||||||
q->terms = or;
|
q->terms = or;
|
||||||
q->split_list = NULL;
|
q->split_list = NULL;
|
||||||
@ -358,7 +374,8 @@ xaccQueryNumTerms(Query * q)
|
|||||||
if (!q)
|
if (!q)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for(o=q->terms; o; o=o->next) {
|
for(o=q->terms; o; o=o->next)
|
||||||
|
{
|
||||||
n += g_list_length(o->data);
|
n += g_list_length(o->data);
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
@ -417,6 +434,17 @@ free_query_term(QueryTerm *qt)
|
|||||||
qt->data.acct.account_guids = NULL;
|
qt->data.acct.account_guids = NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PD_BOOK:
|
||||||
|
g_list_free (qt->data.book.books);
|
||||||
|
qt->data.book.books = NULL;
|
||||||
|
|
||||||
|
for (node = qt->data.book.book_guids; node; node = node->next)
|
||||||
|
xaccGUIDFree (node->data);
|
||||||
|
|
||||||
|
g_list_free (qt->data.book.book_guids);
|
||||||
|
qt->data.book.book_guids = NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
case PD_KVP:
|
case PD_KVP:
|
||||||
g_slist_free (qt->data.kvp.path);
|
g_slist_free (qt->data.kvp.path);
|
||||||
qt->data.kvp.path = NULL;
|
qt->data.kvp.path = NULL;
|
||||||
@ -465,6 +493,20 @@ copy_query_term(QueryTerm * qt)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PD_BOOK:
|
||||||
|
nqt->data.book.books = g_list_copy (nqt->data.book.books);
|
||||||
|
nqt->data.book.book_guids =
|
||||||
|
g_list_copy (nqt->data.book.book_guids);
|
||||||
|
for (node = nqt->data.book.book_guids; node; node = node->next)
|
||||||
|
{
|
||||||
|
GUID *old = node->data;
|
||||||
|
GUID *new = xaccGUIDMalloc ();
|
||||||
|
|
||||||
|
*new = *old;
|
||||||
|
node->data = new;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case PD_KVP: {
|
case PD_KVP: {
|
||||||
GSList *node;
|
GSList *node;
|
||||||
|
|
||||||
@ -495,7 +537,9 @@ copy_and_terms(GList *and_terms)
|
|||||||
GList *cur_and;
|
GList *cur_and;
|
||||||
|
|
||||||
for(cur_and = and_terms; cur_and; cur_and = cur_and->next)
|
for(cur_and = and_terms; cur_and; cur_and = cur_and->next)
|
||||||
|
{
|
||||||
and = g_list_prepend(and, copy_query_term (cur_and->data));
|
and = g_list_prepend(and, copy_query_term (cur_and->data));
|
||||||
|
}
|
||||||
|
|
||||||
return g_list_reverse(and);
|
return g_list_reverse(and);
|
||||||
}
|
}
|
||||||
@ -507,7 +551,9 @@ copy_or_terms(GList * or_terms)
|
|||||||
GList * cur_or;
|
GList * cur_or;
|
||||||
|
|
||||||
for(cur_or = or_terms; cur_or; cur_or = cur_or->next)
|
for(cur_or = or_terms; cur_or; cur_or = cur_or->next)
|
||||||
|
{
|
||||||
or = g_list_prepend(or, copy_and_terms(cur_or->data));
|
or = g_list_prepend(or, copy_and_terms(cur_or->data));
|
||||||
|
}
|
||||||
|
|
||||||
return g_list_reverse(or);
|
return g_list_reverse(or);
|
||||||
}
|
}
|
||||||
@ -524,13 +570,14 @@ xaccFreeQueryMembers(Query *q)
|
|||||||
{
|
{
|
||||||
GList * cur_or;
|
GList * cur_or;
|
||||||
|
|
||||||
if (q == NULL)
|
if (q == NULL) return;
|
||||||
return;
|
|
||||||
|
|
||||||
for(cur_or = q->terms; cur_or; cur_or = cur_or->next) {
|
for(cur_or = q->terms; cur_or; cur_or = cur_or->next)
|
||||||
|
{
|
||||||
GList * cur_and;
|
GList * cur_and;
|
||||||
|
|
||||||
for(cur_and = cur_or->data; cur_and; cur_and = cur_and->next) {
|
for(cur_and = cur_or->data; cur_and; cur_and = cur_and->next)
|
||||||
|
{
|
||||||
free_query_term(cur_and->data);
|
free_query_term(cur_and->data);
|
||||||
cur_and->data = NULL;
|
cur_and->data = NULL;
|
||||||
}
|
}
|
||||||
@ -549,8 +596,7 @@ xaccFreeQueryMembers(Query *q)
|
|||||||
void
|
void
|
||||||
xaccFreeQuery(Query * q)
|
xaccFreeQuery(Query * q)
|
||||||
{
|
{
|
||||||
if (q == NULL)
|
if (q == NULL) return;
|
||||||
return;
|
|
||||||
|
|
||||||
xaccFreeQueryMembers (q);
|
xaccFreeQueryMembers (q);
|
||||||
|
|
||||||
@ -562,8 +608,7 @@ xaccQueryCopy(Query *q)
|
|||||||
{
|
{
|
||||||
Query *copy;
|
Query *copy;
|
||||||
|
|
||||||
if (q == NULL)
|
if (q == NULL) return NULL;
|
||||||
return NULL;
|
|
||||||
|
|
||||||
copy = xaccMallocQuery ();
|
copy = xaccMallocQuery ();
|
||||||
xaccFreeQueryMembers (copy);
|
xaccFreeQueryMembers (copy);
|
||||||
@ -605,7 +650,8 @@ xaccQueryInvert(Query * q)
|
|||||||
|
|
||||||
num_or_terms = g_list_length(q->terms);
|
num_or_terms = g_list_length(q->terms);
|
||||||
|
|
||||||
switch(num_or_terms) {
|
switch(num_or_terms)
|
||||||
|
{
|
||||||
case 0:
|
case 0:
|
||||||
retval = xaccMallocQuery();
|
retval = xaccMallocQuery();
|
||||||
retval->max_splits = q->max_splits;
|
retval->max_splits = q->max_splits;
|
||||||
@ -869,7 +915,8 @@ split_cmp_func(sort_type_t how, gconstpointer ga, gconstpointer gb)
|
|||||||
if ( !(ta) && !(tb) ) return 0;
|
if ( !(ta) && !(tb) ) return 0;
|
||||||
|
|
||||||
|
|
||||||
switch(how) {
|
switch(how)
|
||||||
|
{
|
||||||
case BY_STANDARD:
|
case BY_STANDARD:
|
||||||
return xaccSplitDateOrder(sa, sb);
|
return xaccSplitDateOrder(sa, sb);
|
||||||
break;
|
break;
|
||||||
@ -1147,8 +1194,30 @@ xaccQueryCompileTerms (Query *q)
|
|||||||
{
|
{
|
||||||
GList * or_ptr, * and_ptr;
|
GList * or_ptr, * and_ptr;
|
||||||
|
|
||||||
for(or_ptr = q->terms; or_ptr ; or_ptr = or_ptr->next) {
|
/* find all of the books involved */
|
||||||
for(and_ptr = or_ptr->data; and_ptr; and_ptr = and_ptr->next) {
|
if (q->books) g_list_free (q->books);
|
||||||
|
q->books = NULL;
|
||||||
|
|
||||||
|
for(or_ptr = q->terms; or_ptr ; or_ptr = or_ptr->next)
|
||||||
|
{
|
||||||
|
for(and_ptr = or_ptr->data; and_ptr; and_ptr = and_ptr->next)
|
||||||
|
{
|
||||||
|
QueryTerm *qt = and_ptr->data;
|
||||||
|
switch (qt->data.type)
|
||||||
|
{
|
||||||
|
case PD_BOOK:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(or_ptr = q->terms; or_ptr ; or_ptr = or_ptr->next)
|
||||||
|
{
|
||||||
|
for(and_ptr = or_ptr->data; and_ptr; and_ptr = and_ptr->next)
|
||||||
|
{
|
||||||
QueryTerm *qt = and_ptr->data;
|
QueryTerm *qt = and_ptr->data;
|
||||||
switch (qt->data.type)
|
switch (qt->data.type)
|
||||||
{
|
{
|
||||||
|
@ -27,7 +27,6 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <regex.h>
|
|
||||||
|
|
||||||
#include "date.h"
|
#include "date.h"
|
||||||
#include "gnc-engine.h"
|
#include "gnc-engine.h"
|
||||||
@ -35,6 +34,8 @@
|
|||||||
#include "guid.h"
|
#include "guid.h"
|
||||||
#include "kvp_frame.h"
|
#include "kvp_frame.h"
|
||||||
|
|
||||||
|
typedef struct query_s Query;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QUERY_AND=1,
|
QUERY_AND=1,
|
||||||
QUERY_OR,
|
QUERY_OR,
|
||||||
@ -157,123 +158,6 @@ typedef enum {
|
|||||||
QUERY_MATCH_ANY=2 /* match any account */
|
QUERY_MATCH_ANY=2 /* match any account */
|
||||||
} query_run_t;
|
} query_run_t;
|
||||||
|
|
||||||
typedef struct _querystruct Query;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
pd_type_t type;
|
|
||||||
pr_type_t term_type;
|
|
||||||
int sense;
|
|
||||||
} BasePredicateData;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
pd_type_t type;
|
|
||||||
pr_type_t term_type;
|
|
||||||
int sense;
|
|
||||||
acct_match_t how;
|
|
||||||
AccountList *accounts;
|
|
||||||
AccountGUIDList *account_guids;
|
|
||||||
} AccountPredicateData;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
pd_type_t type;
|
|
||||||
pr_type_t term_type;
|
|
||||||
int sense;
|
|
||||||
amt_match_t how;
|
|
||||||
amt_match_sgn_t amt_sgn;
|
|
||||||
double amount;
|
|
||||||
} AmountPredicateData;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
pd_type_t type;
|
|
||||||
pr_type_t term_type;
|
|
||||||
int sense;
|
|
||||||
balance_match_t how;
|
|
||||||
} BalancePredicateData;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
pd_type_t type;
|
|
||||||
pr_type_t term_type;
|
|
||||||
int sense;
|
|
||||||
book_match_t how;
|
|
||||||
BookList *books;
|
|
||||||
BookGUIDList *book_guids;
|
|
||||||
} BookPredicateData;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
pd_type_t type;
|
|
||||||
pr_type_t term_type;
|
|
||||||
int sense;
|
|
||||||
cleared_match_t how;
|
|
||||||
} ClearedPredicateData;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
pd_type_t type;
|
|
||||||
pr_type_t term_type;
|
|
||||||
int sense;
|
|
||||||
GUID guid;
|
|
||||||
GNCIdType id_type;
|
|
||||||
} GUIDPredicateData;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
pd_type_t type;
|
|
||||||
pr_type_t term_type;
|
|
||||||
int sense;
|
|
||||||
int use_start;
|
|
||||||
Timespec start;
|
|
||||||
int use_end;
|
|
||||||
Timespec end;
|
|
||||||
} DatePredicateData;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
pd_type_t type;
|
|
||||||
pr_type_t term_type;
|
|
||||||
int sense;
|
|
||||||
kvp_match_t how;
|
|
||||||
kvp_match_where_t where;
|
|
||||||
GSList *path;
|
|
||||||
kvp_value *value;
|
|
||||||
} KVPPredicateData;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
pd_type_t type;
|
|
||||||
pr_type_t term_type;
|
|
||||||
int sense;
|
|
||||||
int how;
|
|
||||||
int data;
|
|
||||||
} MiscPredicateData;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
pd_type_t type;
|
|
||||||
pr_type_t term_type;
|
|
||||||
int sense;
|
|
||||||
int case_sens;
|
|
||||||
int use_regexp;
|
|
||||||
char *matchstring;
|
|
||||||
regex_t compiled;
|
|
||||||
} StringPredicateData;
|
|
||||||
|
|
||||||
typedef union {
|
|
||||||
pd_type_t type;
|
|
||||||
BasePredicateData base;
|
|
||||||
AccountPredicateData acct;
|
|
||||||
AmountPredicateData amount;
|
|
||||||
BalancePredicateData balance;
|
|
||||||
BookPredicateData book;
|
|
||||||
ClearedPredicateData cleared;
|
|
||||||
DatePredicateData date;
|
|
||||||
GUIDPredicateData guid;
|
|
||||||
KVPPredicateData kvp;
|
|
||||||
StringPredicateData str;
|
|
||||||
MiscPredicateData misc;
|
|
||||||
} PredicateData;
|
|
||||||
|
|
||||||
typedef int (* Predicate)(Split * to_test, PredicateData * test_data);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
PredicateData data;
|
|
||||||
Predicate p;
|
|
||||||
} QueryTerm;
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* basic Query API
|
* basic Query API
|
||||||
@ -403,10 +287,6 @@ void xaccQueryAddGUIDMatch(Query * q, const GUID *guid,
|
|||||||
void xaccQueryAddKVPMatch(Query *q, GSList *path, const kvp_value *value,
|
void xaccQueryAddKVPMatch(Query *q, GSList *path, const kvp_value *value,
|
||||||
kvp_match_t how, kvp_match_where_t where,
|
kvp_match_t how, kvp_match_where_t where,
|
||||||
QueryOp op);
|
QueryOp op);
|
||||||
void xaccQueryAddMiscMatch(Query * q, Predicate p, int how, int data,
|
|
||||||
QueryOp op);
|
|
||||||
|
|
||||||
void xaccQueryAddPredicate (Query * q, PredicateData *pred, QueryOp op);
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
@ -438,7 +318,4 @@ time_t xaccQueryGetEarliestDateFound(Query * q);
|
|||||||
time_t xaccQueryGetLatestDateFound(Query * q);
|
time_t xaccQueryGetLatestDateFound(Query * q);
|
||||||
|
|
||||||
|
|
||||||
/* This is useful for network systems */
|
|
||||||
Predicate xaccQueryGetPredicate (pr_type_t term_type);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include "Backend.h"
|
#include "Backend.h"
|
||||||
#include "Group.h"
|
#include "Group.h"
|
||||||
#include "Query.h"
|
#include "Query.h"
|
||||||
|
#include "QueryP.h"
|
||||||
#include "date.h"
|
#include "date.h"
|
||||||
#include "engine-helpers.h"
|
#include "engine-helpers.h"
|
||||||
#include "glib-helpers.h"
|
#include "glib-helpers.h"
|
||||||
|
Loading…
Reference in New Issue
Block a user