]>
Commit | Line | Data |
---|---|---|
404d307c CP |
1 | #define MAX_PROVIDERS 10 |
2 | #define PROVIDER_NAME_LEN 100 | |
3 | ||
4 | #define DBAPI_SNPRINTF_MAX_ARGS 20 | |
5 | #define DBAPI_SNPRINTF_MAX_ARG_LENGTH 2048 | |
6 | ||
7 | #include <string.h> | |
8 | #include <stdlib.h> | |
9 | #include <stdarg.h> | |
10 | ||
11 | #include "../core/error.h" | |
12 | #include "../lib/strlfunc.h" | |
13 | #include "../lib/stringbuf.h" | |
14 | #include "dbapi2.h" | |
15 | ||
16 | struct DBAPIProviderData { | |
17 | char name[PROVIDER_NAME_LEN+1]; | |
18 | }; | |
19 | ||
20 | static DBAPIProvider *providerobjs[MAX_PROVIDERS]; | |
21 | static struct DBAPIProviderData providerdata[MAX_PROVIDERS]; | |
22 | ||
23 | void _init(void) { | |
24 | memset(providerobjs, 0, sizeof(providerobjs)); | |
25 | } | |
26 | ||
27 | void _fini(void) { | |
28 | /* everything should be unregistered already */ | |
29 | } | |
30 | ||
31 | int registerdbprovider(const char *name, DBAPIProvider *provider) { | |
32 | int i; | |
33 | ||
34 | for(i=0;i<MAX_PROVIDERS;i++) { | |
adf9e9ea | 35 | if(providerobjs[i]) |
404d307c CP |
36 | continue; |
37 | ||
38 | providerobjs[i] = provider; | |
39 | providerobjs[i]->__providerdata = &providerdata[i]; | |
40 | ||
41 | strlcpy(providerobjs[i]->__providerdata->name, name, PROVIDER_NAME_LEN); | |
42 | ||
39c33a3d CP |
43 | Error("dbapi2", ERR_INFO, "Database API registered: %s", name); |
44 | ||
404d307c CP |
45 | return i; |
46 | } | |
47 | ||
48 | Error("dbapi2", ERR_WARNING, "No remaining space for new database provider: %s", name); | |
49 | return -1; | |
50 | } | |
51 | ||
52 | void deregisterdbprovider(int handle) { | |
53 | if(handle < 0) | |
54 | return; | |
55 | ||
56 | providerobjs[handle] = NULL; | |
57 | } | |
58 | ||
59 | static void dbclose(DBAPIConn *db) { | |
60 | db->__close(db); | |
4a532778 | 61 | free((DBAPIConn *)db); |
404d307c CP |
62 | } |
63 | ||
4a532778 | 64 | static void dbsimplequery(const DBAPIConn *db, const char *format, ...) { |
adf9e9ea CP |
65 | va_list ap; |
66 | ||
67 | va_start(ap, format); | |
68 | db->__query(db, NULL, NULL, format, ap); | |
69 | va_end(ap); | |
70 | } | |
71 | ||
4a532778 | 72 | static void dbquery(const DBAPIConn *db, DBAPIQueryCallback cb, DBAPIUserData data, const char *format, ...) { |
adf9e9ea CP |
73 | va_list ap; |
74 | ||
75 | va_start(ap, format); | |
76 | db->__query(db, cb, data, format, ap); | |
77 | va_end(ap); | |
78 | } | |
79 | ||
39c33a3d CP |
80 | DBAPIConn *dbapi2open(const char *provider, const char *database) { |
81 | int i, found = -1; | |
404d307c CP |
82 | DBAPIConn *db; |
83 | DBAPIProvider *p; | |
84 | ||
39c33a3d CP |
85 | if(provider) { |
86 | for(i=0;i<MAX_PROVIDERS;i++) { | |
87 | if(providerobjs[i] && !strcmp(provider, providerobjs[i]->__providerdata->name)) { | |
88 | found = i; | |
89 | break; | |
90 | } | |
91 | } | |
92 | if(found == -1) { | |
93 | Error("dbapi2", ERR_WARNING, "Couldn't find forced database provider %s", provider); | |
94 | return NULL; | |
95 | } | |
96 | } else { | |
97 | for(i=0;i<MAX_PROVIDERS;i++) { | |
98 | if(providerobjs[i]) { | |
99 | found = i; | |
100 | break; | |
101 | } | |
404d307c | 102 | } |
404d307c | 103 | |
39c33a3d CP |
104 | if(found == -1) { |
105 | Error("dbapi2", ERR_WARNING, "No database providers found."); | |
106 | return NULL; | |
107 | } | |
404d307c CP |
108 | } |
109 | ||
adf9e9ea | 110 | p = providerobjs[found]; |
404d307c CP |
111 | |
112 | db = calloc(1, sizeof(DBAPIConn)); | |
113 | if(!db) | |
114 | return NULL; | |
115 | ||
116 | db->close = dbclose; | |
adf9e9ea | 117 | db->query = dbquery; |
404d307c CP |
118 | db->createtable = p->createtable; |
119 | db->loadtable = p->loadtable; | |
120 | db->escapestring = p->escapestring; | |
adf9e9ea | 121 | db->squery = dbsimplequery; |
4277aef7 | 122 | db->tablename = p->tablename; |
404d307c | 123 | |
adf9e9ea | 124 | db->__query = p->query; |
404d307c CP |
125 | db->__close = p->close; |
126 | db->__quotestring = p->quotestring; | |
127 | ||
128 | strlcpy(db->name, database, DBNAME_LEN); | |
129 | ||
130 | db->handle = p->new(db); | |
131 | if(!db->handle) { | |
132 | free(db); | |
133 | Error("dbapi2", ERR_WARNING, "Unable to initialise database %s, provider: %s", database, p->__providerdata->name); | |
134 | return NULL; | |
135 | } | |
136 | ||
39c33a3d CP |
137 | Error("dbapi2", ERR_INFO, "Database %s opened with provider %s.", database, p->__providerdata->name); |
138 | ||
404d307c CP |
139 | return db; |
140 | } | |
141 | ||
4a532778 | 142 | static void dbvsnprintf(const DBAPIConn *db, char *buf, size_t size, const char *format, const char *types, va_list ap) { |
404d307c CP |
143 | StringBuf b; |
144 | const char *p; | |
145 | static char convbuf[DBAPI_SNPRINTF_MAX_ARGS][DBAPI_SNPRINTF_MAX_ARG_LENGTH+10]; | |
146 | int arg, argcount; | |
147 | ||
148 | if(size == 0) | |
149 | return; | |
150 | ||
151 | { | |
152 | int i; | |
153 | ||
154 | int d; | |
155 | char *s; | |
156 | double g; | |
157 | unsigned int u; | |
158 | size_t l; | |
159 | int fallthrough; | |
160 | ||
161 | for(i=0;i<DBAPI_SNPRINTF_MAX_ARGS;i++) | |
162 | convbuf[i][0] = '\0'; | |
163 | ||
164 | argcount=0; | |
165 | for(;*types;types++) { | |
166 | char *cb = convbuf[argcount]; | |
167 | ||
168 | if(argcount++ >= DBAPI_SNPRINTF_MAX_ARGS) { | |
169 | /* calls exit(0) */ | |
170 | Error("dbapi2", ERR_STOP, "Maximum arguments reached in dbvsnprintf, database: %s", db->name); | |
171 | } | |
172 | ||
173 | fallthrough = 0; | |
174 | switch(*types) { | |
175 | case 's': | |
176 | s = va_arg(ap, char *); | |
177 | l = strlen(s); | |
178 | fallthrough = 1; | |
179 | ||
180 | /* falling through */ | |
181 | case 'S': | |
182 | if(!fallthrough) { | |
183 | s = va_arg(ap, char *); | |
184 | l = va_arg(ap, size_t); | |
185 | } | |
186 | ||
187 | /* now... this is a guess, but we should catch it most of the time */ | |
188 | if((l > (DBAPI_SNPRINTF_MAX_ARG_LENGTH / 2)) || !db->__quotestring(db, cb, sizeof(convbuf[0]), s, l)) { | |
189 | Error("dbapi2", ERR_WARNING, "Long string truncated (database: %s).", db->name); | |
190 | l = DBAPI_SNPRINTF_MAX_ARG_LENGTH; | |
191 | } | |
192 | ||
193 | break; | |
194 | case 'd': | |
195 | d = va_arg(ap, int); | |
196 | snprintf(cb, DBAPI_SNPRINTF_MAX_ARG_LENGTH, "%d", d); | |
197 | break; | |
198 | case 'u': | |
199 | u = va_arg(ap, unsigned int); | |
200 | snprintf(cb, DBAPI_SNPRINTF_MAX_ARG_LENGTH, "%u", u); | |
201 | break; | |
202 | case 'g': | |
203 | g = va_arg(ap, double); | |
204 | snprintf(cb, DBAPI_SNPRINTF_MAX_ARG_LENGTH, "%.1f", g); | |
205 | break; | |
206 | default: | |
207 | /* calls exit(0) */ | |
208 | Error("dbapi2", ERR_STOP, "Bad format specifier '%c' supplied in dbvsnprintf, format: '%s', database: %s", *types, format, db->name); | |
209 | } | |
210 | } | |
211 | } | |
212 | ||
213 | sbinit(&b, buf, size); | |
214 | ||
215 | for(arg=0,p=format;*p;p++) { | |
216 | if(*p != '?') { | |
217 | if(!sbaddchar(&b, *p)) | |
218 | break; | |
219 | continue; | |
220 | } | |
221 | p++; | |
222 | if(arg >= argcount) { | |
223 | /* calls exit(0) */ | |
224 | Error("dbapi2", ERR_STOP, "Gone over number of arguments in dbvsnprintf, database: %s", db->name); | |
225 | } | |
226 | ||
227 | if(!sbaddstr(&b, convbuf[arg])) { | |
228 | /* calls exit(0) */ | |
229 | Error("dbapi2", ERR_STOP, "Possible truncation in dbvsnprintf, database: %s", db->name); | |
230 | } | |
231 | ||
232 | arg++; | |
233 | } | |
234 | ||
235 | sbterminate(&b); | |
236 | } | |
237 | ||
4a532778 | 238 | void dbsnprintf(const DBAPIConn *db, char *buf, size_t size, const char *format, const char *types, ...) { |
404d307c CP |
239 | va_list ap; |
240 | ||
241 | va_start(ap, types); | |
242 | dbvsnprintf(db, buf, size, format, types, ap); | |
243 | va_end(ap); | |
244 | } |