diff options
Diffstat (limited to 'sql/strfunc.cc')
-rw-r--r-- | sql/strfunc.cc | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/sql/strfunc.cc b/sql/strfunc.cc index c03365cfc2b..aad91a2a16a 100644 --- a/sql/strfunc.cc +++ b/sql/strfunc.cc @@ -88,6 +88,188 @@ ulonglong find_set(TYPELIB *lib, const char *str, uint length, CHARSET_INFO *cs, } +static const char *on_off_default_names[]= +{ + "off","on","default", NullS +}; + +static const unsigned int on_off_default_names_len[]= +{ + sizeof("off") - 1, + sizeof("on") - 1, + sizeof("default") - 1 +}; + +static TYPELIB on_off_default_typelib= {array_elements(on_off_default_names)-1, + "", on_off_default_names, + (unsigned int *)on_off_default_names_len}; + + +/* + Given a string, find the first field_separator char, minding the charset +*/ + +static uint parse_name(TYPELIB *lib, const char **strpos, const char *end, + CHARSET_INFO *cs) +{ + const char *pos= *strpos; + const char *start= pos; + + /* Find the length */ + if (cs && cs->mbminlen > 1) + { + int mblen= 0; + for ( ; pos < end; pos+= mblen) + { + my_wc_t wc; + if ((mblen= cs->cset->mb_wc(cs, &wc, (const uchar *) pos, + (const uchar *) end)) < 1) + mblen= 1; // Not to hang on a wrong multibyte sequence + if (wc == (my_wc_t) '=' || wc == (my_wc_t) ',') + break; + } + } + else + for (; pos != end && *pos != '=' && *pos !=',' ; pos++); + + uint var_len= (uint) (pos - start); + /* Determine which flag it is*/ + uint find= cs ? find_type2(lib, start, var_len, cs) : + find_type(lib, start, var_len, (bool) 0); + *strpos= pos; + return find; +} + + +/* Read next character from the buffer in a charset-aware way */ + +static my_wc_t get_next_char(const char **pos, const char *end, CHARSET_INFO *cs) +{ + my_wc_t wc; + if (*pos == end) + return (my_wc_t)-1; + + if (cs && cs->mbminlen > 1) + { + int mblen; + if ((mblen= cs->cset->mb_wc(cs, &wc, (const uchar *) *pos, + (const uchar *) end)) < 1) + mblen= 1; // Not to hang on a wrong multibyte sequence + *pos += mblen; + return wc; + } + else + return *((*pos)++); +} + + +/* + Parse a string representation of set of flags + + SYNOPSIS + find_set_from_flags() + lib Flag names + default_name Number of "default" in the typelib + cur_set Current set of flags (start from this state) + default_set Default set of flags (use this for assign-default + keyword and flag=default assignments) + str String representation (see below) + length Length of the above + cs Charset used for the string + err_pos OUT If error, set to point to start of wrong set string + err_len OUT If error, set to the length of wrong set string + set_warning OUT TRUE <=> Some string in set couldn't be used + + DESCRIPTION + Parse a set of flag assignments, that is, parse a string in form: + + param_name1=value1,param_name2=value2,... + + where the names are specified in the TYPELIB, and each value can be + either 'on','off', or 'default'. Besides param=val assignments, we + support "default" keyword (keyword #default_name in the typelib) which + means assign everything the default. + + RETURN + FALSE Ok + TRUE Error +*/ + +ulonglong find_set_from_flags(TYPELIB *lib, uint default_name, + ulonglong cur_set, ulonglong default_set, + const char *str, uint length, CHARSET_INFO *cs, + char **err_pos, uint *err_len, bool *set_warning) +{ + CHARSET_INFO *strip= cs ? cs : &my_charset_latin1; + const char *end= str + strip->cset->lengthsp(strip, str, length); + ulonglong flags= cur_set; + *err_pos= 0; // No error yet + if (str != end) + { + const char *start= str; + for (;;) + { + my_wc_t chr; + const char *pos= start; + uint flag, value; + + if (!(flag= parse_name(lib, &pos, end, cs))) + { + *err_pos= (char*) start; + *err_len= pos - start; + *set_warning= 1; + break; + } + + if (flag == default_name) + { + flags= default_set; + } + else + { + if ((chr= get_next_char(&pos, end, cs)) != '=') + { + *err_pos= (char*)start; + *err_len= pos - start; + *set_warning= 1; + break; + } + + if (!(value= parse_name(&on_off_default_typelib, &pos, end, cs))) + { + *err_pos= (char*) start; + *err_len= pos - start; + *set_warning= 1; + break; + } + + ulonglong bit= ((longlong) 1 << (flag - 1)); + if (value == 1) // this is 'xxx=off' + flags &= ~bit; + else if (value == 2) // this is 'xxx=on' + flags |= bit; + else // this is 'xxx=default' + { + bit= default_set & bit; + flags= (flags & ~bit) | bit; + } + } + + if (pos >= end) + break; + if ((chr= get_next_char(&pos, end, cs)) != ',') + { + *err_pos= (char*)start; + *err_len= pos - start; + *set_warning= 1; + } + start=pos; + } + } + return flags; +} + + /* Function to find a string in a TYPELIB (Same format as mysys/typelib.c) |