1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 //  Copyright (C) 2010-2011  Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
4 //
5 //  Distributed under:
6 //
7 //                   the Boost Software License, Version 1.0.
8 //              (See accompanying file LICENSE_1_0.txt or copy at
9 //                     http://www.boost.org/LICENSE_1_0.txt)
10 //
11 //  or (at your opinion) under:
12 //
13 //                               The MIT License
14 //                 (See accompanying file MIT.txt or a copy at
15 //              http://www.opensource.org/licenses/mit-license.php)
16 //
17 ///////////////////////////////////////////////////////////////////////////////
18 #define CPPDB_SOURCE
19 #include <cppdb/utils.h>
20 #include <cppdb/errors.h>
21 #include <time.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <sstream>
25 #include <locale>
26 
27 namespace cppdb {
format_time(std::tm const & v)28 	std::string format_time(std::tm const &v)
29 	{
30 		char buf[64]= {0};
31 		strftime(buf,sizeof(buf),"%Y-%m-%d %H:%M:%S",&v);
32 		return std::string(buf);
33 	}
34 
parse_time(std::string const & v)35 	std::tm parse_time(std::string const &v)
36 	{
37 		if(strlen(v.c_str())!=v.size())
38 			throw bad_value_cast();
39 		return parse_time(v.c_str());
40 	}
parse_time(char const * v)41 	std::tm parse_time(char const *v)
42 	{
43 		std::tm t=std::tm();
44 		int n;
45 		double sec = 0;
46 		n = sscanf(v,"%d-%d-%d %d:%d:%lf",
47 			&t.tm_year,&t.tm_mon,&t.tm_mday,
48 			&t.tm_hour,&t.tm_min,&sec);
49 		if(n!=3 && n!=6)
50 		{
51 			throw bad_value_cast();
52 		}
53 		t.tm_year-=1900;
54 		t.tm_mon-=1;
55 		t.tm_isdst = -1;
56 		t.tm_sec=static_cast<int>(sec);
57 		if(mktime(&t)==-1)
58 			throw bad_value_cast();
59 		return t;
60 	}
61 
62 	namespace {
is_blank_char(char c)63 		bool is_blank_char(char c)
64 		{
65 			return c==' ' || c=='\t' || c=='\r' || c=='\n' || c=='\f';
66 		}
trim(std::string const & s)67 		std::string trim(std::string const &s)
68 		{
69 			if(s.empty())
70 				return s;
71 			size_t start=0,end=s.size()-1;
72 			while(start < s.size() && is_blank_char(s[start])) {
73 				start++;
74 			}
75 			while(end > start && is_blank_char(s[end])) {
76 				end--;
77 			}
78 			return s.substr(start,end-start+1);
79 		}
80 	}
81 
parse_connection_string(std::string const & connection_string,std::string & driver,std::map<std::string,std::string> & params)82 	void parse_connection_string(	std::string const &connection_string,
83 					std::string &driver,
84 					std::map<std::string,std::string> &params)
85 	{
86 		params.clear();
87 		size_t p = connection_string.find(':');
88 		if( p == std::string::npos )
89 			throw cppdb_error("cppdb::Invalid connection string - no driver given");
90 		driver = connection_string.substr(0,p);
91 		p++;
92 		while(p<connection_string.size()) {
93 			size_t n=connection_string.find('=',p);
94 			if(n==std::string::npos)
95 				throw cppdb_error("Invalid connection string - invalid property");
96 			std::string key = trim(connection_string.substr(p,n-p));
97 			p=n+1;
98 			std::string value;
99 			while(p<connection_string.size() && is_blank_char(connection_string[p]))
100 			{
101 				++p;
102 			}
103 			if(p>=connection_string.size()) {
104 				/// Nothing - empty property
105 			}
106 			else if(connection_string[p]=='\'') {
107 				p++;
108 				while(true) {
109 					if(p>=connection_string.size()) {
110 						throw cppdb_error("Invalid connection string unterminated string");
111 					}
112 					if(connection_string[p]=='\'') {
113 						if(p+1 < connection_string.size() && connection_string[p+1]=='\'') {
114 							value+='\'';
115 							p+=2;
116 						}
117 						else {
118 							p++;
119 							break;
120 						}
121 					}
122 					else {
123 						value+=connection_string[p];
124 						p++;
125 					}
126 				}
127 			}
128 			else {
129 				size_t n=connection_string.find(';',p);
130 				if(n==std::string::npos) {
131 					value=trim(connection_string.substr(p));
132 					p=connection_string.size();
133 				}
134 				else {
135 					value=trim(connection_string.substr(p,n-p));
136 					p=n;
137 				}
138 			}
139 			if(params.find(key)!=params.end()) {
140 				throw cppdb_error("cppdb::invalid connection string duplicate key");
141 			}
142 			params[key]=value;
143 			while(p<connection_string.size()) {
144 				char c=connection_string[p];
145 				if(is_blank_char(c))
146 					++p;
147 				else if(c==';') {
148 					++p;
149 					break;
150 				}
151 			}
152 		}
153 	} //
get(std::string const & prop,std::string const & default_value) const154 	std::string connection_info::get(std::string const &prop,std::string const &default_value) const
155 	{
156 		properties_type::const_iterator p=properties.find(prop);
157 		if(p==properties.end())
158 			return default_value;
159 		else
160 			return p->second;
161 	}
162 
has(std::string const & prop) const163 	bool connection_info::has(std::string const &prop) const
164 	{
165 		return properties.find(prop) != properties.end();
166 	}
167 
get(std::string const & prop,int default_value) const168 	int connection_info::get(std::string const &prop,int default_value) const
169 	{
170 		properties_type::const_iterator p=properties.find(prop);
171 		if(p==properties.end())
172 			return default_value;
173 		std::istringstream ss;
174 		ss.imbue(std::locale::classic());
175 		ss.str(p->second);
176 		int val;
177 		ss >> val;
178 		if(!ss || !ss.eof()) {
179 			throw cppdb_error("cppdb::connection_info property " + prop + " expected to be integer value");
180 		}
181 		return val;
182 	}
183 
184 }
185