///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2010-2011 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// Distributed under:
//
// the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// or (at your opinion) under:
//
// The MIT License
// (See accompanying file MIT.txt or a copy at
// http://www.opensource.org/licenses/mit-license.php)
//
///////////////////////////////////////////////////////////////////////////////
#define CPPDB_SOURCE
#include <cppdb/utils.h>
#include <cppdb/errors.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <sstream>
#include <locale>
namespace cppdb {
std::string format_time(std::tm const &v)
{
char buf[64]= {0};
strftime(buf,sizeof(buf),"%Y-%m-%d %H:%M:%S",&v);
return std::string(buf);
}
std::tm parse_time(std::string const &v)
{
if(strlen(v.c_str())!=v.size())
throw bad_value_cast();
return parse_time(v.c_str());
}
std::tm parse_time(char const *v)
{
std::tm t=std::tm();
int n;
double sec = 0;
n = sscanf(v,"%d-%d-%d %d:%d:%lf",
&t.tm_year,&t.tm_mon,&t.tm_mday,
&t.tm_hour,&t.tm_min,&sec);
if(n!=3 && n!=6)
{
throw bad_value_cast();
}
t.tm_year-=1900;
t.tm_mon-=1;
t.tm_isdst = -1;
t.tm_sec=static_cast<int>(sec);
if(mktime(&t)==-1)
throw bad_value_cast();
return t;
}
namespace {
bool is_blank_char(char c)
{
return c==' ' || c=='\t' || c=='\r' || c=='\n' || c=='\f';
}
std::string trim(std::string const &s)
{
if(s.empty())
return s;
size_t start=0,end=s.size()-1;
while(start < s.size() && is_blank_char(s[start])) {
start++;
}
while(end > start && is_blank_char(s[end])) {
end--;
}
return s.substr(start,end-start+1);
}
}
void parse_connection_string( std::string const &connection_string,
std::string &driver,
std::map<std::string,std::string> ¶ms)
{
params.clear();
size_t p = connection_string.find(':');
if( p == std::string::npos )
throw cppdb_error("cppdb::Invalid connection string - no driver given");
driver = connection_string.substr(0,p);
p++;
while(p<connection_string.size()) {
size_t n=connection_string.find('=',p);
if(n==std::string::npos)
throw cppdb_error("Invalid connection string - invalid property");
std::string key = trim(connection_string.substr(p,n-p));
p=n+1;
std::string value;
while(p<connection_string.size() && is_blank_char(connection_string[p]))
{
++p;
}
if(p>=connection_string.size()) {
/// Nothing - empty property
}
else if(connection_string[p]=='\'') {
p++;
while(true) {
if(p>=connection_string.size()) {
throw cppdb_error("Invalid connection string unterminated string");
}
if(connection_string[p]=='\'') {
if(p+1 < connection_string.size() && connection_string[p+1]=='\'') {
value+='\'';
p+=2;
}
else {
p++;
break;
}
}
else {
value+=connection_string[p];
p++;
}
}
}
else {
size_t n=connection_string.find(';',p);
if(n==std::string::npos) {
value=trim(connection_string.substr(p));
p=connection_string.size();
}
else {
value=trim(connection_string.substr(p,n-p));
p=n;
}
}
if(params.find(key)!=params.end()) {
throw cppdb_error("cppdb::invalid connection string duplicate key");
}
params[key]=value;
while(p<connection_string.size()) {
char c=connection_string[p];
if(is_blank_char(c))
++p;
else if(c==';') {
++p;
break;
}
}
}
} //
std::string connection_info::get(std::string const &prop,std::string const &default_value) const
{
properties_type::const_iterator p=properties.find(prop);
if(p==properties.end())
return default_value;
else
return p->second;
}
bool connection_info::has(std::string const &prop) const
{
return properties.find(prop) != properties.end();
}
int connection_info::get(std::string const &prop,int default_value) const
{
properties_type::const_iterator p=properties.find(prop);
if(p==properties.end())
return default_value;
std::istringstream ss;
ss.imbue(std::locale::classic());
ss.str(p->second);
int val;
ss >> val;
if(!ss || !ss.eof()) {
throw cppdb_error("cppdb::connection_info property " + prop + " expected to be integer value");
}
return val;
}
}