-
Notifications
You must be signed in to change notification settings - Fork 30
/
util.h
308 lines (267 loc) · 9.69 KB
/
util.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
#ifndef __UTIL_H__
#define __UTIL_H__
/* NOTE: this must be included in "top level" file (wherever SQL types are
* used */
#if defined(_WIN32) || defined (WIN32)
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
/* FIXME: why isn't this included in sql/~ext.h? */
/* win function parameter attributes */
#include <windows.h>
#include <tchar.h>
#endif /* _WIN32/WIN32 */
#include <inttypes.h>
#include <wchar.h>
#include <assert.h>
#include "sql.h"
#include "sqlext.h"
/* export attribute for internal functions used for testing */
#ifndef TEST_API /* Release builds define this to an empty macro */
#ifdef DRIVER_BUILD
#define TEST_API __declspec(dllexport)
#else /* _EXPORTS */
#define TEST_API __declspec(dllimport)
#endif /* _EXPORTS */
#define TESTING /* compiles in the testing code */
#endif /* TEST_API */
/*
* Assert two integral types have same storage and sign.
*/
#define ASSERT_INTEGER_TYPES_EQUAL(a, b) \
assert((sizeof(a) == sizeof(b)) && \
( (0 < (a)0 - 1 && 0 < (b)0 - 1) || \
(0 > (a)0 - 1 && 0 > (b)0 - 1) ))
/*
* Stringifying in two preproc. passes
*/
#define _STR(_x) # _x
#define STR(_x) _STR(_x)
/*
* Turn a C static string to wide char string.
*/
#define _MK_WPTR(_cstr_) (L ## _cstr_)
#define MK_WPTR(_cstr_) _MK_WPTR(_cstr_)
#define MK_CPTR(_cstr_) _cstr_
#ifdef UNICODE
#define MK_TPTR MK_WPTR
#else /* UNICODE */
#define MK_TPTR MK_CPTR
#endif /* UNICODE */
#if !defined(_WIN32) && !defined (WIN32)
#define _T MK_TPTR
#endif /* _WIN32/WIN32 */
typedef struct cstr {
SQLCHAR *str;
size_t cnt;
} cstr_st;
/*
* Converts a wchar_t string to a C string for ASCII characters.
* 'dst' should be at least as character-long as 'src', if 'src' is
* 0-terminated, OR one character longer otherwise (for the 0-term).
* 'dst' will always be 0-term'd.
* Returns negative if conversion fails, OR number of converted wchars,
* including/plus the 0-term.
*/
int TEST_API ascii_w2c(const SQLWCHAR *src, SQLCHAR *dst, size_t chars);
int TEST_API ascii_c2w(const SQLCHAR *src, SQLWCHAR *dst, size_t chars);
/*
* Compare two SQLWCHAR object, case INsensitive.
*/
int wmemncasecmp(const SQLWCHAR *a, const SQLWCHAR *b, size_t len);
/*
* Compare two zero-terminated SQLWCHAR* objects, until a 0 is encountered in
* either of them or until 'count' characters are evaluated. If 'count'
* parameter is negative, it is ignored.
*
* This is useful in comparing SQL strings which the API allows to be passed
* either as 0-terminated or not (SQL_NTS).
* The function does a single pass (no length evaluation of the strings).
* wmemcmp() might read over the boundary of one of the objects, if the
* provided 'count' paramter is not the minimum of the strings' length.
*/
int wszmemcmp(const SQLWCHAR *a, const SQLWCHAR *b, long count);
/*
* wcsstr() variant for non-NTS.
*/
const SQLWCHAR *wcsnstr(const SQLWCHAR *hay, size_t len, SQLWCHAR needle);
typedef struct wstr {
SQLWCHAR *str;
size_t cnt;
} wstr_st;
/*
* Turns a static C string into a wstr_st.
*/
#ifndef __cplusplus /* no MSVC support for compound literals with /TP */
# define MK_WSTR(_s) ((wstr_st){.str = MK_WPTR(_s), .cnt = sizeof(_s) - 1})
# define MK_CSTR(_s) ((cstr_st){.str = _s, .cnt = sizeof(_s) - 1})
#endif /* !__cplusplus */
#define WSTR_INIT(_s) {MK_WPTR(_s), sizeof(_s) - 1}
#define CSTR_INIT(_s) {(SQLCHAR *)_s, sizeof(_s) - 1}
/*
* Test equality of two wstr_st objects.
*/
#define EQ_WSTR(s1, s2) \
((s1)->cnt == (s2)->cnt && wmemcmp((s1)->str, (s2)->str, (s1)->cnt) == 0)
/*
* Same as EQ_WSTR, but case INsensitive.
*/
#define EQ_CASE_WSTR(s1, s2) \
((s1)->cnt == (s2)->cnt && \
wmemncasecmp((s1)->str, (s2)->str, (s1)->cnt) == 0)
typedef struct {
BOOL wide;
union {
wstr_st w;
cstr_st c;
};
} xstr_st;
/* For as long as wptr_st & cptr_st are only differing in string pointer type,
* it's safe to save the check if wide or not. */
#define XSTR_LEN(_xptr) (_xptr)->w.cnt
/*
* Trims leading and trailing WS of a wide string of 'chars' length.
* 0-terminator should not be counted (as it's a non-WS).
*/
void trim_ws(cstr_st *str);
void wltrim_ws(wstr_st *wstr);
void wrtrim_ws(wstr_st *wstr);
#define wtrim_ws(_w) do { wltrim_ws(_w); wrtrim_ws(_w); } while (0)
/* Trim the w-string at first encounter of the give w-char.
* Returns TRUE if character has been encounter / trimming occured. */
BOOL wtrim_at(wstr_st *wstr, SQLWCHAR wchar);
BOOL wstr2bool(wstr_st *val);
/* Converts a [cw]str_st to a SQL(U)BIGINT.
* If !strict, parsing stops at first non-digit char.
* Returns the number of parsed characters or negative of failure. */
int str2ubigint(void *val, BOOL wide, SQLUBIGINT *out, BOOL strict);
int str2bigint(void *val, BOOL wide, SQLBIGINT *out, BOOL strict);
int str2double(void *val, BOOL wide, SQLDOUBLE *dbl, BOOL strict);
/* converts the int types to a C or wide string, returning the string length */
size_t i64tot(int64_t i64, void *buff, BOOL wide);
size_t ui64tot(uint64_t ui64, void *buff, BOOL wide);
#ifdef _WIN32
/*
* "[D]oes not null-terminate an output string if the input string length is
* explicitly specified without a terminating null character. To
* null-terminate an output string for this function, the application should
* pass in -1 or explicitly count the terminating null character for the input
* string."
* "If successful, returns the number of bytes written" or required (if
* _ubytes == 0), OR "0 if it does not succeed".
*/
#define WCS2U8(_wstr, _wchars, _u8, _ubytes) \
WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, \
_wstr, _wchars, _u8, _ubytes, \
NULL, NULL)
#define WCS2U8_BUFF_INSUFFICIENT \
(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
#define WCS2U8_ERRNO() GetLastError()
/*
* Locking type and primitives.
*/
typedef SRWLOCK esodbc_mutex_lt;
#define ESODBC_MUX_SINIT SRWLOCK_INIT
#define ESODBC_MUX_INIT(_m) InitializeSRWLock(_m)
#define ESODBC_MUX_DEL(_m) /* not needed/possible */
#define ESODBC_MUX_LOCK(_m) AcquireSRWLockExclusive(_m)
#define ESODBC_MUX_TRYLOCK(_m) TryAcquireSRWLockExclusive(_m)
#define ESODBC_MUX_UNLOCK(_m) ReleaseSRWLockExclusive(_m)
#else /* _WIN32 */
#error "unsupported platform"
/* "[R]eturns the number of bytes written into the multibyte output
* string, excluding the terminating NULL (if any)". Copies until \0 is
* met in wstr or buffer runs out. If \0 is met, it's copied, but not
* counted in return. (silly fn) */
/* "[T]he multibyte character string at mbstr is null-terminated
* only if wcstombs encounters a wide-character null character
* during conversion." */
// wcstombs(charp, wstr, octet_length);
#endif /* _WIN32 */
#ifdef UNICODE
typedef wstr_st tstr_st;
#else /* UNICODE */
typedef cstr_st tstr_st;
#endif /* UNICODE */
/* generic char JSON escaping prefix */
#define JSON_ESC_GEN_PREF "\\u00"
/* octet length of one generic JSON escaped character */
#define JSON_ESC_SEQ_SZ (sizeof(JSON_ESC_GEN_PREF) - 1 + /*0xAB*/2)
/*
* JSON-escapes a string.
* If string len is 0, it assumes a NTS.
* If output buffer (jout) is NULL, it returns the buffer size needed for
* escaping.
* Returns number of used bytes in buffer (which might be less than buffer
* size, if some char needs an escaping longer than remaining space).
*/
size_t json_escape(const char *jin, size_t inlen, char *jout, size_t outlen);
/*
* JSON-escapes a string (str), outputting the result in the same buffer.
* The buffer needs to be long enough (outlen) for this operation (at
* least json_escaped_len() long).
* If string [in]len is 0, it assumes a NTS.
* Returns number of used bytes in buffer (which might be less than out buffer
* size (outlen), if some char needs an escaping longer than remaining space).
*/
size_t json_escape_overlapping(char *str, size_t inlen, size_t outlen);
/*
* Copy a WSTR back to application.
* The WSTR must not count the 0-tem.
* The function checks against the correct size of available bytes, copies the
* wstr according to avaialble space and indicates the available bytes to copy
* back into provided buffer (if not NULL).
*/
SQLRETURN write_wstr(SQLHANDLE hnd, SQLWCHAR *dest, wstr_st *src,
SQLSMALLINT /*B*/avail, SQLSMALLINT /*B*/*usedp);
/*
* Converts a wide string to a UTF-8 MB, allocating the necessary space.
* The \0 is allocated and written, even if not present in source string, but
* only counted in output string if counted in input one.
* If 'dst' is null, the destination is also going to be allocate (collated
* with the string). The caller only needs to free the allocated chunk
* (returned pointer or dst->str).
* Returns NULL on error.
*/
cstr_st TEST_API *wstr_to_utf8(wstr_st *src, cstr_st *dst);
/*
* Printing aids.
*/
/*
* w/printf() desriptors for char/wchar_t *
* "WPrintF Wide/Char Pointer _ DESCriptor"
*/
#ifdef _WIN32
/* wprintf wide_t pointer descriptor */
# define WPFWP_DESC L"%s"
# define WPFWP_LDESC L"%.*s"
/* printf wide_t pointer descriptor */
# define PFWP_DESC "%S"
# define PFWP_LDESC "%.*S"
/* wprintf char pointer descriptor */
# define WPFCP_DESC L"%S"
# define WPFCP_LDESC L"%.*S"
/* printf char pointer descriptor */
# define PFCP_DESC "%s"
# define PFCP_LDESC "%.*s"
#else /* _WIN32 */
/* wprintf wide_t pointer descriptor */
# define WPFWP_DESC L"%S"
# define WPFWP_LDESC L"%.*S"
/* printf wide_t pointer descriptor */
# define PFWP_DESC "%S"
# define PFWP_LDESC "%.*S"
/* wprintf char pointer descriptor */
# define WPFCP_DESC L"%s"
# define WPFCP_LDESC L"%.*s"
/* printf char pointer descriptor */
# define PFCP_DESC "%s"
# define PFCP_LDESC "%.*s"
#endif /* _WIN32 */
#endif /* __UTIL_H__ */
/* vim: set noet fenc=utf-8 ff=dos sts=0 sw=4 ts=4 : */