mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-18 22:26:30 +01:00
merge android_branch->
This commit is contained in:
commit
f954b09391
7 changed files with 278 additions and 131 deletions
|
@ -38,6 +38,7 @@ SRC = \
|
||||||
udpager.cpp \
|
udpager.cpp \
|
||||||
udpqueue.cpp \
|
udpqueue.cpp \
|
||||||
xwrelay.cpp \
|
xwrelay.cpp \
|
||||||
|
querybld.cpp \
|
||||||
|
|
||||||
# STATIC ?= -static
|
# STATIC ?= -static
|
||||||
GITINFO = gitversion.txt
|
GITINFO = gitversion.txt
|
||||||
|
|
|
@ -43,11 +43,8 @@
|
||||||
|
|
||||||
static DBMgr* s_instance = NULL;
|
static DBMgr* s_instance = NULL;
|
||||||
|
|
||||||
#define DELIM "\1"
|
|
||||||
#define MAX_NUM_PLAYERS 4
|
#define MAX_NUM_PLAYERS 4
|
||||||
|
|
||||||
static void formatParams( char* paramValues[], int nParams, const char* fmt,
|
|
||||||
char* buf, int bufLen, ... );
|
|
||||||
static int here_less_seed( const char* seeds, int perDeviceSum,
|
static int here_less_seed( const char* seeds, int perDeviceSum,
|
||||||
unsigned short seed );
|
unsigned short seed );
|
||||||
static void destr_function( void* conn );
|
static void destr_function( void* conn );
|
||||||
|
@ -105,20 +102,21 @@ DBMgr::AddNew( const char* cookie, const char* connName, CookieID cid,
|
||||||
if ( !cookie ) cookie = "";
|
if ( !cookie ) cookie = "";
|
||||||
if ( !connName ) connName = "";
|
if ( !connName ) connName = "";
|
||||||
|
|
||||||
const char* command = "INSERT INTO " GAMES_TABLE
|
QueryBuilder qb;
|
||||||
" (cid, room, connName, nTotal, lang, pub)"
|
qb.appendQueryf( "INSERT INTO " GAMES_TABLE
|
||||||
" VALUES( $1, $2, $3, $4, $5, $6 )";
|
" (cid, room, connName, nTotal, lang, pub)"
|
||||||
int nParams = 6;
|
" VALUES( $$, $$, $$, $$, $$, $$ )" )
|
||||||
char* paramValues[nParams];
|
.appendParam(cid)
|
||||||
char buf[512];
|
.appendParam(cookie)
|
||||||
formatParams( paramValues, nParams,
|
.appendParam(connName)
|
||||||
"%d"DELIM"%s"DELIM"%s"DELIM"%d"DELIM"%d"DELIM"%s",
|
.appendParam(nPlayersT)
|
||||||
buf, sizeof(buf), cid, cookie, connName, nPlayersT,
|
.appendParam(langCode)
|
||||||
langCode, isPublic?"TRUE":"FALSE" );
|
.appendParam(isPublic?"TRUE":"FALSE" )
|
||||||
|
.finish();
|
||||||
|
|
||||||
PGresult* result = PQexecParams( getThreadConn(), command,
|
PGresult* result = PQexecParams( getThreadConn(), qb.c_str(),
|
||||||
nParams, NULL,
|
qb.paramCount(), NULL,
|
||||||
paramValues,
|
qb.paramValues(),
|
||||||
NULL, NULL, 0 );
|
NULL, NULL, 0 );
|
||||||
if ( PGRES_COMMAND_OK != PQresultStatus(result) ) {
|
if ( PGRES_COMMAND_OK != PQresultStatus(result) ) {
|
||||||
logf( XW_LOGERROR, "PQexec=>%s;%s", PQresStatus(PQresultStatus(result)),
|
logf( XW_LOGERROR, "PQexec=>%s;%s", PQresStatus(PQresultStatus(result)),
|
||||||
|
@ -271,28 +269,27 @@ DBMgr::SeenSeed( const char* cookie, unsigned short seed,
|
||||||
char* connNameBuf, int bufLen, int* nPlayersHP,
|
char* connNameBuf, int bufLen, int* nPlayersHP,
|
||||||
CookieID* cid )
|
CookieID* cid )
|
||||||
{
|
{
|
||||||
int nParams = 5;
|
QueryBuilder qb;
|
||||||
char* paramValues[nParams];
|
qb.appendQueryf( "SELECT cid, connName, seeds, sum_array(nPerDevice) FROM "
|
||||||
char buf[512];
|
GAMES_TABLE
|
||||||
formatParams( paramValues, nParams,
|
" WHERE NOT dead"
|
||||||
"%s"DELIM"%d"DELIM"%d"DELIM"%d"DELIM"%s", buf, sizeof(buf),
|
" AND room ILIKE $$"
|
||||||
cookie, langCode, nPlayersT, seed,
|
" AND lang = $$"
|
||||||
wantsPublic?"TRUE":"FALSE" );
|
" AND nTotal = $$"
|
||||||
|
" AND $$ = ANY(seeds)"
|
||||||
|
" AND $$ = pub"
|
||||||
|
" ORDER BY ctime DESC"
|
||||||
|
" LIMIT 1")
|
||||||
|
.appendParam(cookie)
|
||||||
|
.appendParam(langCode)
|
||||||
|
.appendParam(nPlayersT)
|
||||||
|
.appendParam(seed)
|
||||||
|
.appendParam(wantsPublic?"TRUE":"FALSE" )
|
||||||
|
.finish();
|
||||||
|
|
||||||
const char* cmd = "SELECT cid, connName, seeds, sum_array(nPerDevice) FROM "
|
PGresult* result = PQexecParams( getThreadConn(), qb.c_str(),
|
||||||
GAMES_TABLE
|
qb.paramCount(), NULL,
|
||||||
" WHERE NOT dead"
|
qb.paramValues(),
|
||||||
" AND room ILIKE $1"
|
|
||||||
" AND lang = $2"
|
|
||||||
" AND nTotal = $3"
|
|
||||||
" AND $4 = ANY(seeds)"
|
|
||||||
" AND $5 = pub"
|
|
||||||
" ORDER BY ctime DESC"
|
|
||||||
" LIMIT 1";
|
|
||||||
|
|
||||||
PGresult* result = PQexecParams( getThreadConn(), cmd,
|
|
||||||
nParams, NULL,
|
|
||||||
paramValues,
|
|
||||||
NULL, NULL, 0 );
|
NULL, NULL, 0 );
|
||||||
bool found = 1 == PQntuples( result );
|
bool found = 1 == PQntuples( result );
|
||||||
if ( found ) {
|
if ( found ) {
|
||||||
|
@ -312,31 +309,28 @@ DBMgr::FindOpen( const char* cookie, int lang, int nPlayersT, int nPlayersH,
|
||||||
bool wantsPublic, char* connNameBuf, int bufLen,
|
bool wantsPublic, char* connNameBuf, int bufLen,
|
||||||
int* nPlayersHP )
|
int* nPlayersHP )
|
||||||
{
|
{
|
||||||
CookieID cid = 0;
|
QueryBuilder qb;
|
||||||
|
qb.appendQueryf("SELECT cid, connName, sum_array(nPerDevice) FROM "
|
||||||
|
GAMES_TABLE
|
||||||
|
" WHERE NOT dead"
|
||||||
|
" AND room ILIKE $$"
|
||||||
|
" AND lang = $$"
|
||||||
|
" AND nTotal = $$"
|
||||||
|
" AND $$ <= nTotal-sum_array(nPerDevice)"
|
||||||
|
" AND $$ = pub"
|
||||||
|
" LIMIT 1")
|
||||||
|
.appendParam(cookie)
|
||||||
|
.appendParam(lang)
|
||||||
|
.appendParam(nPlayersT)
|
||||||
|
.appendParam(nPlayersH)
|
||||||
|
.appendParam(wantsPublic?"TRUE":"FALSE" )
|
||||||
|
.finish();
|
||||||
|
|
||||||
int nParams = 5;
|
PGresult* result = PQexecParams( getThreadConn(), qb.c_str(),
|
||||||
char* paramValues[nParams];
|
qb.paramCount(), NULL,
|
||||||
char buf[512];
|
qb.paramValues(),
|
||||||
formatParams( paramValues, nParams,
|
|
||||||
"%s"DELIM"%d"DELIM"%d"DELIM"%d"DELIM"%s", buf, sizeof(buf),
|
|
||||||
cookie, lang, nPlayersT, nPlayersH, wantsPublic?"TRUE":"FALSE" );
|
|
||||||
|
|
||||||
/* NOTE: ILIKE, for case-insensitive comparison, is a postgres extension
|
|
||||||
to SQL. */
|
|
||||||
const char* cmd = "SELECT cid, connName, sum_array(nPerDevice) FROM "
|
|
||||||
GAMES_TABLE
|
|
||||||
" WHERE NOT dead"
|
|
||||||
" AND room ILIKE $1"
|
|
||||||
" AND lang = $2"
|
|
||||||
" AND nTotal = $3"
|
|
||||||
" AND $4 <= nTotal-sum_array(nPerDevice)"
|
|
||||||
" AND $5 = pub"
|
|
||||||
" LIMIT 1";
|
|
||||||
|
|
||||||
PGresult* result = PQexecParams( getThreadConn(), cmd,
|
|
||||||
nParams, NULL,
|
|
||||||
paramValues,
|
|
||||||
NULL, NULL, 0 );
|
NULL, NULL, 0 );
|
||||||
|
CookieID cid = 0;
|
||||||
if ( 1 == PQntuples( result ) ) {
|
if ( 1 == PQntuples( result ) ) {
|
||||||
cid = atoi( PQgetvalue( result, 0, 0 ) );
|
cid = atoi( PQgetvalue( result, 0, 0 ) );
|
||||||
snprintf( connNameBuf, bufLen, "%s", PQgetvalue( result, 0, 1 ) );
|
snprintf( connNameBuf, bufLen, "%s", PQgetvalue( result, 0, 1 ) );
|
||||||
|
@ -396,14 +390,21 @@ DBMgr::RegisterDevice( const DevID* host, int clientVersion,
|
||||||
devID = (DevIDRelay)random();
|
devID = (DevIDRelay)random();
|
||||||
} while ( DEVID_NONE == devID );
|
} while ( DEVID_NONE == devID );
|
||||||
|
|
||||||
StrWPF query;
|
QueryBuilder qb;
|
||||||
query.catf( "INSERT INTO " DEVICES_TABLE " (id, devTypes[1],"
|
qb.appendQueryf( "INSERT INTO " DEVICES_TABLE " (id, devTypes[1],"
|
||||||
" devids[1], clntVers, versdesc, model, osvers)"
|
" devids[1], clntVers, versdesc, model, osvers)"
|
||||||
" VALUES( %d, %d, '%s', %d, '%s', '%s', '%s' )",
|
" VALUES($$, $$, $$, $$, $$, $$, $$)" );
|
||||||
devID, host->m_devIDType, devidStr, clientVersion,
|
|
||||||
desc, model, osVers );
|
qb.appendParam( devID )
|
||||||
logf( XW_LOGINFO, "%s: %s", __func__, query.c_str() );
|
.appendParam( host->m_devIDType )
|
||||||
success = execSql( query );
|
.appendParam( devidStr )
|
||||||
|
.appendParam( clientVersion )
|
||||||
|
.appendParam( desc )
|
||||||
|
.appendParam( model )
|
||||||
|
.appendParam( osVers )
|
||||||
|
.finish();
|
||||||
|
|
||||||
|
success = execParams( qb );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return devID;
|
return devID;
|
||||||
|
@ -420,15 +421,17 @@ DBMgr::ReregisterDevice( DevIDRelay relayID, const DevID* host,
|
||||||
const char* const desc, int clientVersion,
|
const char* const desc, int clientVersion,
|
||||||
const char* const model, const char* const osVers )
|
const char* const model, const char* const osVers )
|
||||||
{
|
{
|
||||||
// First update the existing
|
QueryBuilder qb;
|
||||||
StrWPF query;
|
qb.appendQueryf( "UPDATE " DEVICES_TABLE " SET "
|
||||||
query.catf( "UPDATE " DEVICES_TABLE " SET "
|
"devTypes = array_prepend($$, devTypes), "
|
||||||
"devTypes = array_prepend( %d, devTypes), "
|
"devids = array_prepend($$, devids), " )
|
||||||
"devids = array_prepend('%s', devids), ",
|
|
||||||
host->m_devIDType, host->m_devIDString.c_str() );
|
|
||||||
|
|
||||||
formatUpdate( query, true, desc, clientVersion, model, osVers, relayID );
|
.appendParam( host->m_devIDType )
|
||||||
execSql( query );
|
.appendParam( host->m_devIDString.c_str() );
|
||||||
|
|
||||||
|
formatUpdate( qb, true, desc, clientVersion, model, osVers, relayID );
|
||||||
|
qb.finish();
|
||||||
|
execParams( qb );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return true if the relayID exists in the DB already
|
// Return true if the relayID exists in the DB already
|
||||||
|
@ -445,10 +448,11 @@ DBMgr::UpdateDevice( DevIDRelay relayID, const char* const desc,
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( exists ) {
|
if ( exists ) {
|
||||||
StrWPF query;
|
QueryBuilder qb;
|
||||||
query.catf( "UPDATE " DEVICES_TABLE " SET " );
|
qb.appendQueryf( "UPDATE " DEVICES_TABLE " SET " );
|
||||||
formatUpdate( query, false, desc, clientVersion, model, osVers, relayID );
|
formatUpdate( qb, false, desc, clientVersion, model, osVers, relayID );
|
||||||
execSql( query );
|
qb.finish();
|
||||||
|
execParams( qb );
|
||||||
}
|
}
|
||||||
return exists;
|
return exists;
|
||||||
}
|
}
|
||||||
|
@ -460,26 +464,33 @@ DBMgr::UpdateDevice( DevIDRelay relayID )
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DBMgr::formatUpdate( StrWPF& query, bool append, const char* const desc,
|
DBMgr::formatUpdate( QueryBuilder& qb,
|
||||||
|
bool append, const char* const desc,
|
||||||
int clientVersion, const char* const model,
|
int clientVersion, const char* const model,
|
||||||
const char* const osVers, DevIDRelay relayID )
|
const char* const osVers, DevIDRelay relayID )
|
||||||
{
|
{
|
||||||
if ( append ) {
|
if ( append ) {
|
||||||
query.catf( "mtimes=array_prepend('now', mtimes)" ); // FIXME: too many
|
qb.appendQueryf( "mtimes=array_prepend('now', mtimes)" ); // FIXME: too many
|
||||||
} else {
|
} else {
|
||||||
query.catf( "mtimes[1]='now'" );
|
qb.appendQueryf( "mtimes[1]='now'" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( NULL != desc && '\0' != desc[0] ) {
|
if ( NULL != desc && '\0' != desc[0] ) {
|
||||||
query.catf( ", clntVers=%d, versDesc='%s'", clientVersion, desc );
|
qb.appendQueryf( ", clntVers=$$" )
|
||||||
|
.appendParam( clientVersion )
|
||||||
|
.appendQueryf( ", versDesc=$$" )
|
||||||
|
.appendParam( desc );
|
||||||
}
|
}
|
||||||
if ( NULL != model && '\0' != model[0] ) {
|
if ( NULL != model && '\0' != model[0] ) {
|
||||||
query.catf( ", model='%s'", model );
|
qb.appendQueryf( ", model=$$" )
|
||||||
|
.appendParam( model );
|
||||||
}
|
}
|
||||||
if ( NULL != osVers && '\0' != osVers[0] ) {
|
if ( NULL != osVers && '\0' != osVers[0] ) {
|
||||||
query.catf( ", osvers='%s'", osVers );
|
qb.appendQueryf( ", osvers=$$" )
|
||||||
|
.appendParam( osVers );
|
||||||
}
|
}
|
||||||
query.catf( " WHERE id = %d", relayID );
|
qb.appendQueryf( " WHERE id = $$" )
|
||||||
|
.appendParam( relayID );
|
||||||
}
|
}
|
||||||
|
|
||||||
HostID
|
HostID
|
||||||
|
@ -831,6 +842,22 @@ DBMgr::execSql( const char* const query )
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
DBMgr::execParams( QueryBuilder& qb )
|
||||||
|
{
|
||||||
|
PGresult* result = PQexecParams( getThreadConn(), qb.c_str(),
|
||||||
|
qb.paramCount(), NULL,
|
||||||
|
qb.paramValues(),
|
||||||
|
NULL, NULL, 0 );
|
||||||
|
bool success = PGRES_COMMAND_OK == PQresultStatus( result );
|
||||||
|
if ( !success ) {
|
||||||
|
logf( XW_LOGERROR, "PQexecParams(%s)=>%s;%s", qb.c_str(),
|
||||||
|
PQresStatus(PQresultStatus(result)),
|
||||||
|
PQresultErrorMessage(result) );
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DBMgr::readArray( const char* const connName, const char* column, int arr[] ) /* len 4 */
|
DBMgr::readArray( const char* const connName, const char* column, int arr[] ) /* len 4 */
|
||||||
{
|
{
|
||||||
|
@ -1255,31 +1282,6 @@ void DBMgr::clearHasNoMessages( DevIDRelay devid )
|
||||||
assert( !hasNoMessages( devid ) );
|
assert( !hasNoMessages( devid ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
formatParams( char* paramValues[], int nParams, const char* fmt, char* buf,
|
|
||||||
int bufLen, ... )
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
va_start( ap, bufLen );
|
|
||||||
|
|
||||||
int len = vsnprintf( buf, bufLen, fmt, ap );
|
|
||||||
assert( buf[len] == '\0' );
|
|
||||||
|
|
||||||
int pnum;
|
|
||||||
char* ptr = buf;
|
|
||||||
for ( pnum = 0; pnum < nParams; ++pnum ) {
|
|
||||||
paramValues[pnum] = ptr;
|
|
||||||
for ( ; *ptr != '\0' && *ptr != DELIM[0]; ++ptr ) {
|
|
||||||
// do nothing
|
|
||||||
assert( ptr < &buf[bufLen] );
|
|
||||||
}
|
|
||||||
// we've found an end
|
|
||||||
*ptr = '\0';
|
|
||||||
++ptr;
|
|
||||||
}
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
here_less_seed( const char* seeds, int sumPerDevice, unsigned short seed )
|
here_less_seed( const char* seeds, int sumPerDevice, unsigned short seed )
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "xwrelay_priv.h"
|
#include "xwrelay_priv.h"
|
||||||
#include "devid.h"
|
#include "devid.h"
|
||||||
#include "strwpf.h"
|
#include "strwpf.h"
|
||||||
|
#include "querybld.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -149,6 +150,7 @@ class DBMgr {
|
||||||
DBMgr();
|
DBMgr();
|
||||||
bool execSql( const string& query );
|
bool execSql( const string& query );
|
||||||
bool execSql( const char* const query ); /* no-results query */
|
bool execSql( const char* const query ); /* no-results query */
|
||||||
|
bool execParams( QueryBuilder& qb );
|
||||||
void readArray( const char* const connName, const char* column, int arr[] );
|
void readArray( const char* const connName, const char* column, int arr[] );
|
||||||
DevIDRelay getDevID( const char* connName, int hid );
|
DevIDRelay getDevID( const char* connName, int hid );
|
||||||
DevIDRelay getDevID( const DevID* devID );
|
DevIDRelay getDevID( const DevID* devID );
|
||||||
|
@ -160,7 +162,7 @@ class DBMgr {
|
||||||
bool nullConnnameOK );
|
bool nullConnnameOK );
|
||||||
int CountStoredMessages( const char* const connName, int hid );
|
int CountStoredMessages( const char* const connName, int hid );
|
||||||
bool UpdateDevice( DevIDRelay relayID );
|
bool UpdateDevice( DevIDRelay relayID );
|
||||||
void formatUpdate( StrWPF& query, bool append, const char* const desc,
|
void formatUpdate( QueryBuilder& qb, bool append, const char* const desc,
|
||||||
int clientVersion, const char* const model,
|
int clientVersion, const char* const model,
|
||||||
const char* const osVers, DevIDRelay relayID );
|
const char* const osVers, DevIDRelay relayID );
|
||||||
|
|
||||||
|
|
78
xwords4/relay/querybld.cpp
Normal file
78
xwords4/relay/querybld.cpp
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
||||||
|
/*
|
||||||
|
* Copyright 2014 by Eric House (xwords@eehouse.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include "querybld.h"
|
||||||
|
#include "xwrelay_priv.h"
|
||||||
|
|
||||||
|
QueryBuilder&
|
||||||
|
QueryBuilder::appendQueryf( const char* fmt, ... )
|
||||||
|
{
|
||||||
|
bool done;
|
||||||
|
do {
|
||||||
|
va_list ap;
|
||||||
|
va_start( ap, fmt );
|
||||||
|
done = m_query.catf( fmt, ap );
|
||||||
|
va_end( ap );
|
||||||
|
} while ( !done );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder&
|
||||||
|
QueryBuilder::appendParam( const char* value )
|
||||||
|
{
|
||||||
|
m_paramIndices.push_back( m_paramBuf.size() );
|
||||||
|
m_paramBuf.catf( "%s%c", value, '\0' );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder&
|
||||||
|
QueryBuilder::appendParam( int value )
|
||||||
|
{
|
||||||
|
m_paramIndices.push_back( m_paramBuf.size() );
|
||||||
|
m_paramBuf.catf( "%d%c", value, '\0' );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When done adding params, some of which contain $$, turn these into an order
|
||||||
|
* progression of $1, $2 .. $9. Note assumption that we don't go above 9 since
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
QueryBuilder::finish()
|
||||||
|
{
|
||||||
|
assert( 0 == m_paramValues.size() );
|
||||||
|
|
||||||
|
size_t ii;
|
||||||
|
const char* base = m_paramBuf.c_str();
|
||||||
|
for ( ii = 0; ii < m_paramIndices.size(); ++ii ) {
|
||||||
|
const char* ptr = m_paramIndices[ii] + base;
|
||||||
|
m_paramValues.push_back( ptr );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( size_t count = 0; ; ++count ) {
|
||||||
|
const char* str = m_query.c_str();
|
||||||
|
const char* ptr = strstr( str, "$$" );
|
||||||
|
if ( !ptr ) {
|
||||||
|
assert( count == m_paramIndices.size() );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assert( count < 9 );
|
||||||
|
m_query[1 + ptr - str] = '1' + count;
|
||||||
|
}
|
||||||
|
}
|
47
xwords4/relay/querybld.h
Normal file
47
xwords4/relay/querybld.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
||||||
|
/*
|
||||||
|
* Copyright 2014 by Eric House (xwords@eehouse.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _QUERYBLD_H_
|
||||||
|
#define _QUERYBLD_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "strwpf.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class QueryBuilder {
|
||||||
|
|
||||||
|
public:
|
||||||
|
QueryBuilder& appendQueryf( const char* fmt, ... );
|
||||||
|
QueryBuilder& appendParam( const char* value );
|
||||||
|
QueryBuilder& appendParam( int value );
|
||||||
|
void finish();
|
||||||
|
int paramCount() const { return m_paramValues.size(); }
|
||||||
|
const char* const* paramValues() const { return &m_paramValues[0]; }
|
||||||
|
const char* const c_str() const { return m_query.c_str(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
StrWPF m_query;
|
||||||
|
StrWPF m_paramBuf;
|
||||||
|
vector<size_t> m_paramIndices;
|
||||||
|
vector<const char*> m_paramValues;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -27,26 +27,37 @@
|
||||||
/* From stack overflow: snprintf with an expanding buffer.
|
/* From stack overflow: snprintf with an expanding buffer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
bool
|
||||||
|
StrWPF::catf( const char* fmt, va_list ap )
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
const int origsiz = size();
|
||||||
|
resize( origsiz + m_addsiz );
|
||||||
|
|
||||||
|
int len = vsnprintf( (char*)c_str() + origsiz, m_addsiz, fmt, ap );
|
||||||
|
|
||||||
|
if ( len >= m_addsiz ) { // needs more space
|
||||||
|
m_addsiz = len + 1;
|
||||||
|
resize( origsiz );
|
||||||
|
} else if ( -1 == len ) {
|
||||||
|
assert(0); // should be impossible
|
||||||
|
} else {
|
||||||
|
resize( origsiz + len );
|
||||||
|
m_addsiz = 100;
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
StrWPF::catf( const char* fmt, ... )
|
StrWPF::catf( const char* fmt, ... )
|
||||||
{
|
{
|
||||||
const int origsiz = size();
|
bool done;
|
||||||
int addsiz = 100;
|
do {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
for ( ; ; ) {
|
|
||||||
resize( origsiz + addsiz );
|
|
||||||
|
|
||||||
va_start( ap, fmt );
|
va_start( ap, fmt );
|
||||||
int len = vsnprintf( (char *)c_str() + origsiz, addsiz, fmt, ap );
|
done = catf( fmt, ap );
|
||||||
va_end( ap );
|
va_end( ap );
|
||||||
|
} while ( !done );
|
||||||
if ( len >= addsiz ) { // needs more space
|
|
||||||
addsiz = len + 1;
|
|
||||||
} else if ( -1 == len ) {
|
|
||||||
assert(0); // should be impossible
|
|
||||||
} else {
|
|
||||||
resize( origsiz + len );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,16 @@
|
||||||
#define _STRWPF_H_
|
#define _STRWPF_H_
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
class StrWPF : public std::string {
|
class StrWPF : public std::string {
|
||||||
public:
|
public:
|
||||||
|
StrWPF() : m_addsiz(100){}
|
||||||
|
|
||||||
void catf( const char* fmt, ... );
|
void catf( const char* fmt, ... );
|
||||||
|
bool catf( const char* fmt, va_list ap );
|
||||||
|
private:
|
||||||
|
int m_addsiz;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue