1 /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 Without limiting anything contained in the foregoing, this file,
15 which is part of C Driver for MySQL (Connector/C), is also subject to the
16 Universal FOSS Exception, version 1.0, a copy of which can be found at
17 http://oss.oracle.com/licenses/universal-foss-exception.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License, version 2.0, for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
27
28 /* Functions to handle typelib */
29
30 #include "mysys_priv.h"
31 #include <m_string.h>
32 #include <m_ctype.h>
33
34
35 #define is_field_separator(X) ((X) == ',' || (X) == '=')
36
find_type_or_exit(const char * x,TYPELIB * typelib,const char * option)37 int find_type_or_exit(const char *x, TYPELIB *typelib, const char *option)
38 {
39 int res;
40 const char **ptr;
41
42 if ((res= find_type((char *) x, typelib, FIND_TYPE_BASIC)) <= 0)
43 {
44 ptr= typelib->type_names;
45 if (!*x)
46 fprintf(stderr, "No option given to %s\n", option);
47 else
48 fprintf(stderr, "Unknown option to %s: %s\n", option, x);
49 fprintf(stderr, "Alternatives are: '%s'", *ptr);
50 while (*++ptr)
51 fprintf(stderr, ",'%s'", *ptr);
52 fprintf(stderr, "\n");
53 exit(1);
54 }
55 return res;
56 }
57
58
59 /**
60 Search after a string in a list of strings. Endspace in x is not compared.
61
62 @param x String to find
63 @param typelib TYPELIB (struct of pointer to values + count)
64 @param flags flags to tune behaviour: a combination of
65 FIND_TYPE_NO_PREFIX
66 FIND_TYPE_ALLOW_NUMBER
67 FIND_TYPE_COMMA_TERM.
68 FIND_TYPE_NO_OVERWRITE can be passed but is
69 superfluous (is always implicitely on).
70
71 @retval
72 -1 Too many matching values
73 @retval
74 0 No matching value
75 @retval
76 >0 Offset+1 in typelib for matched string
77 */
78
79
find_type(const char * x,const TYPELIB * typelib,uint flags)80 int find_type(const char *x, const TYPELIB *typelib, uint flags)
81 {
82 int find,pos;
83 int UNINIT_VAR(findpos); /* guarded by find */
84 const char *i;
85 const char *j;
86 DBUG_ENTER("find_type");
87 DBUG_PRINT("enter",("x: '%s' lib: 0x%lx", x, (long) typelib));
88
89 DBUG_ASSERT(!(flags & ~(FIND_TYPE_NO_PREFIX | FIND_TYPE_ALLOW_NUMBER |
90 FIND_TYPE_NO_OVERWRITE | FIND_TYPE_COMMA_TERM)));
91 if (!typelib->count)
92 {
93 DBUG_PRINT("exit",("no count"));
94 DBUG_RETURN(0);
95 }
96 find=0;
97 for (pos=0 ; (j=typelib->type_names[pos]) ; pos++)
98 {
99 for (i=x ;
100 *i && (!(flags & FIND_TYPE_COMMA_TERM) || !is_field_separator(*i)) &&
101 my_toupper(&my_charset_latin1,*i) ==
102 my_toupper(&my_charset_latin1,*j) ; i++, j++) ;
103 if (! *j)
104 {
105 while (*i == ' ')
106 i++; /* skip_end_space */
107 if (! *i || ((flags & FIND_TYPE_COMMA_TERM) && is_field_separator(*i)))
108 DBUG_RETURN(pos+1);
109 }
110 if ((!*i &&
111 (!(flags & FIND_TYPE_COMMA_TERM) || !is_field_separator(*i))) &&
112 (!*j || !(flags & FIND_TYPE_NO_PREFIX)))
113 {
114 find++;
115 findpos=pos;
116 }
117 }
118 if (find == 0 && (flags & FIND_TYPE_ALLOW_NUMBER) && x[0] == '#' &&
119 strend(x)[-1] == '#' &&
120 (findpos=atoi(x+1)-1) >= 0 && (uint) findpos < typelib->count)
121 find=1;
122 else if (find == 0 || ! x[0])
123 {
124 DBUG_PRINT("exit",("Couldn't find type"));
125 DBUG_RETURN(0);
126 }
127 else if (find != 1 || (flags & FIND_TYPE_NO_PREFIX))
128 {
129 DBUG_PRINT("exit",("Too many possybilities"));
130 DBUG_RETURN(-1);
131 }
132 DBUG_RETURN(findpos+1);
133 } /* find_type */
134
135
136 /**
137 Get name of type nr
138
139 @note
140 first type is 1, 0 = empty field
141 */
142
make_type(char * to,uint nr,TYPELIB * typelib)143 void make_type(char * to, uint nr,
144 TYPELIB *typelib)
145 {
146 DBUG_ENTER("make_type");
147 if (!nr)
148 to[0]=0;
149 else
150 (void) strmov(to,get_type(typelib,nr-1));
151 DBUG_VOID_RETURN;
152 } /* make_type */
153
154
155 /**
156 Get type
157
158 @note
159 first type is 0
160 */
161
get_type(TYPELIB * typelib,uint nr)162 const char *get_type(TYPELIB *typelib, uint nr)
163 {
164 if (nr < (uint) typelib->count && typelib->type_names)
165 return(typelib->type_names[nr]);
166 return "?";
167 }
168
169
170 /**
171 Create an integer value to represent the supplied comma-seperated
172 string where each string in the TYPELIB denotes a bit position.
173
174 @param x string to decompose
175 @param lib TYPELIB (struct of pointer to values + count)
176 @param err index (not char position) of string element which was not
177 found or 0 if there was no error
178
179 @retval
180 a integer representation of the supplied string
181 */
182
find_typeset(char * x,TYPELIB * lib,int * err)183 my_ulonglong find_typeset(char *x, TYPELIB *lib, int *err)
184 {
185 my_ulonglong result;
186 int find;
187 char *i;
188 DBUG_ENTER("find_set");
189 DBUG_PRINT("enter",("x: '%s' lib: 0x%lx", x, (long) lib));
190
191 if (!lib->count)
192 {
193 DBUG_PRINT("exit",("no count"));
194 DBUG_RETURN(0);
195 }
196 result= 0;
197 *err= 0;
198 while (*x)
199 {
200 (*err)++;
201 i= x;
202 while (*x && !is_field_separator(*x))
203 x++;
204 if (x[0] && x[1]) /* skip separator if found */
205 x++;
206 if ((find= find_type(i, lib, FIND_TYPE_COMMA_TERM) - 1) < 0)
207 DBUG_RETURN(0);
208 result|= (ULL(1) << find);
209 }
210 *err= 0;
211 DBUG_RETURN(result);
212 } /* find_set */
213
214
215 /**
216 Create a copy of a specified TYPELIB structure.
217
218 @param root pointer to a MEM_ROOT object for allocations
219 @param from pointer to a source TYPELIB structure
220
221 @retval
222 pointer to the new TYPELIB structure on successful copy
223 @retval
224 NULL otherwise
225 */
226
copy_typelib(MEM_ROOT * root,TYPELIB * from)227 TYPELIB *copy_typelib(MEM_ROOT *root, TYPELIB *from)
228 {
229 TYPELIB *to;
230 uint i;
231
232 if (!from)
233 return NULL;
234
235 if (!(to= (TYPELIB*) alloc_root(root, sizeof(TYPELIB))))
236 return NULL;
237
238 if (!(to->type_names= (const char **)
239 alloc_root(root, (sizeof(char *) + sizeof(int)) * (from->count + 1))))
240 return NULL;
241 to->type_lengths= (unsigned int *)(to->type_names + from->count + 1);
242 to->count= from->count;
243 if (from->name)
244 {
245 if (!(to->name= strdup_root(root, from->name)))
246 return NULL;
247 }
248 else
249 to->name= NULL;
250
251 for (i= 0; i < from->count; i++)
252 {
253 if (!(to->type_names[i]= strmake_root(root, from->type_names[i],
254 from->type_lengths[i])))
255 return NULL;
256 to->type_lengths[i]= from->type_lengths[i];
257 }
258 to->type_names[to->count]= NULL;
259 to->type_lengths[to->count]= 0;
260
261 return to;
262 }
263
264
265 static const char *on_off_default_names[]= { "off","on","default", 0};
266 static TYPELIB on_off_default_typelib= {array_elements(on_off_default_names)-1,
267 "", on_off_default_names, 0};
268
269 /**
270 Parse a TYPELIB name from the buffer
271
272 @param lib Set of names to scan for.
273 @param strpos INOUT Start of the buffer (updated to point to the next
274 character after the name)
275 @param end End of the buffer
276
277 @note
278 The buffer is assumed to contain one of the names specified in the TYPELIB,
279 followed by comma, '=', or end of the buffer.
280
281 @retval
282 0 No matching name
283 @retval
284 >0 Offset+1 in typelib for matched name
285 */
286
parse_name(const TYPELIB * lib,const char ** strpos,const char * end)287 static uint parse_name(const TYPELIB *lib, const char **strpos, const char *end)
288 {
289 const char *pos= *strpos;
290 uint find= find_type(pos, lib, FIND_TYPE_COMMA_TERM);
291 for (; pos != end && *pos != '=' && *pos !=',' ; pos++);
292 *strpos= pos;
293 return find;
294 }
295
296 /**
297 Parse and apply a set of flag assingments
298
299 @param lib Flag names
300 @param default_name Number of "default" in the typelib
301 @param cur_set Current set of flags (start from this state)
302 @param default_set Default set of flags (use this for assign-default
303 keyword and flag=default assignments)
304 @param str String to be parsed
305 @param length Length of the string
306 @param err_pos OUT If error, set to point to start of wrong set string
307 NULL on success
308 @param err_len OUT If error, set to the length of wrong set string
309
310 @details
311 Parse a set of flag assignments, that is, parse a string in form:
312
313 param_name1=value1,param_name2=value2,...
314
315 where the names are specified in the TYPELIB, and each value can be
316 either 'on','off', or 'default'. Setting the same name twice is not
317 allowed.
318
319 Besides param=val assignments, we support the "default" keyword (keyword
320 #default_name in the typelib). It can be used one time, if specified it
321 causes us to build the new set over the default_set rather than cur_set
322 value.
323
324 @note
325 it's not charset aware
326
327 @retval
328 Parsed set value if (*errpos == NULL), otherwise undefined
329 */
330
find_set_from_flags(const TYPELIB * lib,uint default_name,my_ulonglong cur_set,my_ulonglong default_set,const char * str,uint length,char ** err_pos,uint * err_len)331 my_ulonglong find_set_from_flags(const TYPELIB *lib, uint default_name,
332 my_ulonglong cur_set, my_ulonglong default_set,
333 const char *str, uint length,
334 char **err_pos, uint *err_len)
335 {
336 const char *end= str + length;
337 my_ulonglong flags_to_set= 0, flags_to_clear= 0, res;
338 my_bool set_defaults= 0;
339
340 *err_pos= 0; /* No error yet */
341 if (str != end)
342 {
343 const char *start= str;
344 for (;;)
345 {
346 const char *pos= start;
347 uint flag_no, value;
348
349 if (!(flag_no= parse_name(lib, &pos, end)))
350 goto err;
351
352 if (flag_no == default_name)
353 {
354 /* Using 'default' twice isn't allowed. */
355 if (set_defaults)
356 goto err;
357 set_defaults= TRUE;
358 }
359 else
360 {
361 my_ulonglong bit= (1ULL << (flag_no - 1));
362 /* parse the '=on|off|default' */
363 if ((flags_to_clear | flags_to_set) & bit ||
364 pos >= end || *pos++ != '=' ||
365 !(value= parse_name(&on_off_default_typelib, &pos, end)))
366 goto err;
367
368 if (value == 1) /* this is '=off' */
369 flags_to_clear|= bit;
370 else if (value == 2) /* this is '=on' */
371 flags_to_set|= bit;
372 else /* this is '=default' */
373 {
374 if (default_set & bit)
375 flags_to_set|= bit;
376 else
377 flags_to_clear|= bit;
378 }
379 }
380 if (pos >= end)
381 break;
382
383 if (*pos++ != ',')
384 goto err;
385
386 start=pos;
387 continue;
388 err:
389 *err_pos= (char*)start;
390 *err_len= end - start;
391 break;
392 }
393 }
394 res= set_defaults? default_set : cur_set;
395 res|= flags_to_set;
396 res&= ~flags_to_clear;
397 return res;
398 }
399
400