1 // Copyright (c) 2000, 2017, 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, as
5 // 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
11 // additional permission to link the program and your derivative works
12 // with the separately licensed software that they have included with
13 // MySQL.
14 //
15 // Without limiting anything contained in the foregoing, this file,
16 // which is part of MySQL Server, is also subject to the
17 // Universal FOSS Exception, version 1.0, a copy of which can be found at
18 // http://oss.oracle.com/licenses/universal-foss-exception.
19 //
20 // This program is distributed in the hope that it will be useful, but
21 // WITHOUT ANY WARRANTY; without even the implied warranty of
22 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23 // See the GNU General Public License, version 2.0, for more details.
24 //
25 // You should have received a copy of the GNU General Public License
26 // along with this program; if not, write to the Free Software Foundation, Inc.,
27 // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 
29 #ifndef _m_string_h
30 #define _m_string_h
31 
32 /**
33   @file include/m_string.h
34 */
35 
36 #include <float.h>
37 #include <stdbool.h>  // IWYU pragma: keep
38 #include <stdint.h>
39 #include <stdlib.h>
40 #include <string.h>
41 
42 #include "lex_string.h"
43 #include "my_config.h"
44 #include "my_inttypes.h"
45 #include "my_macros.h"
46 
47 /**
48   Definition of the null string (a null pointer of type char *),
49   used in some of our string handling code. New code should use
50   nullptr instead.
51 */
52 #define NullS (char *)0
53 
54 /*
55   my_str_malloc(), my_str_realloc() and my_str_free() are assigned to
56   implementations in strings/alloc.c, but can be overridden in
57   the calling program.
58  */
59 extern void *(*my_str_malloc)(size_t);
60 extern void *(*my_str_realloc)(void *, size_t);
61 extern void (*my_str_free)(void *);
62 
63 /* Declared in int2str() */
64 extern char _dig_vec_upper[];
65 extern char _dig_vec_lower[];
66 
67 /* Prototypes for string functions */
68 
69 extern char *strmake(char *dst, const char *src, size_t length);
70 extern char *strcont(const char *src, const char *set);
71 extern char *strxmov(char *dst, const char *src, ...);
72 extern char *strxnmov(char *dst, size_t len, const char *src, ...);
73 
74 /*
75   bchange(dst, old_length, src, new_length, tot_length)
76   replaces old_length characters at dst to new_length characters from
77   src in a buffer with tot_length bytes.
78 */
bchange(uchar * dst,size_t old_length,const uchar * src,size_t new_length,size_t tot_length)79 static inline void bchange(uchar *dst, size_t old_length, const uchar *src,
80                            size_t new_length, size_t tot_length) {
81   memmove(dst + new_length, dst + old_length, tot_length - old_length);
82   memcpy(dst, src, new_length);
83 }
84 
85 /*
86   strend(s) returns a character pointer to the NUL which ends s.  That
87   is,  strend(s)-s  ==  strlen(s). This is useful for adding things at
88   the end of strings.  It is redundant, because  strchr(s,'\0')  could
89   be used instead, but this is clearer and faster.
90 */
strend(const char * s)91 static inline char *strend(const char *s) {
92   while (*s++)
93     ;
94   return (char *)(s - 1);
95 }
96 
97 /*
98   strcend(s, c) returns a pointer to the  first  place  in  s where  c
99   occurs,  or a pointer to the end-null of s if c does not occur in s.
100 */
strcend(const char * s,char c)101 static inline char *strcend(const char *s, char c) {
102   for (;;) {
103     if (*s == (char)c) return (char *)s;
104     if (!*s++) return (char *)s - 1;
105   }
106 }
107 
108 /*
109   strfill(dest, len, fill) makes a string of fill-characters. The result
110   string is of length == len. The des+len character is allways set to NULL.
111   strfill() returns pointer to dest+len;
112 */
strfill(char * s,size_t len,char fill)113 static inline char *strfill(char *s, size_t len, char fill) {
114   while (len--) *s++ = fill;
115   *(s) = '\0';
116   return (s);
117 }
118 
119 /*
120   my_stpmov(dst, src) moves all the  characters  of  src  (including  the
121   closing NUL) to dst, and returns a pointer to the new closing NUL in
122   dst.	 The similar UNIX routine strcpy returns the old value of dst,
123   which I have never found useful.  my_stpmov(my_stpmov(dst,a),b) moves a//b
124   into dst, which seems useful.
125 */
my_stpmov(char * dst,const char * src)126 static inline char *my_stpmov(char *dst, const char *src) {
127   while ((*dst++ = *src++))
128     ;
129   return dst - 1;
130 }
131 
132 /*
133   my_stpnmov(dst,src,length) moves length characters, or until end, of src to
134   dst and appends a closing NUL to dst if src is shorter than length.
135   The result is a pointer to the first NUL in dst, or is dst+n if dst was
136   truncated.
137 */
my_stpnmov(char * dst,const char * src,size_t n)138 static inline char *my_stpnmov(char *dst, const char *src, size_t n) {
139   while (n-- != 0) {
140     if (!(*dst++ = *src++)) return (char *)dst - 1;
141   }
142   return dst;
143 }
144 
145 /**
146    Copy a string from src to dst until (and including) terminating null byte.
147 
148    @param dst   Destination
149    @param src   Source
150 
151    @note src and dst cannot overlap.
152          Use my_stpmov() if src and dst overlaps.
153 
154    @note Unsafe, consider using my_stpnpy() instead.
155 
156    @return pointer to terminating null byte.
157 */
my_stpcpy(char * dst,const char * src)158 static inline char *my_stpcpy(char *dst, const char *src) {
159 #if defined(HAVE_BUILTIN_STPCPY)
160   return __builtin_stpcpy(dst, src);
161 #elif defined(HAVE_STPCPY)
162   return stpcpy(dst, src);
163 #else
164   /* Fallback to implementation supporting overlap. */
165   return my_stpmov(dst, src);
166 #endif
167 }
168 
169 /**
170    Copy fixed-size string from src to dst.
171 
172    @param dst   Destination
173    @param src   Source
174    @param n     Maximum number of characters to copy.
175 
176    @note src and dst cannot overlap
177          Use my_stpnmov() if src and dst overlaps.
178 
179    @return pointer to terminating null byte.
180 */
my_stpncpy(char * dst,const char * src,size_t n)181 static inline char *my_stpncpy(char *dst, const char *src, size_t n) {
182 #if defined(HAVE_STPNCPY)
183   return stpncpy(dst, src, n);
184 #else
185   /* Fallback to implementation supporting overlap. */
186   return my_stpnmov(dst, src, n);
187 #endif
188 }
189 
my_strtoll(const char * nptr,char ** endptr,int base)190 static inline longlong my_strtoll(const char *nptr, char **endptr, int base) {
191 #if defined _WIN32
192   return _strtoi64(nptr, endptr, base);
193 #else
194   return strtoll(nptr, endptr, base);
195 #endif
196 }
197 
my_strtoull(const char * nptr,char ** endptr,int base)198 static inline ulonglong my_strtoull(const char *nptr, char **endptr, int base) {
199 #if defined _WIN32
200   return _strtoui64(nptr, endptr, base);
201 #else
202   return strtoull(nptr, endptr, base);
203 #endif
204 }
205 
my_strtok_r(char * str,const char * delim,char ** saveptr)206 static inline char *my_strtok_r(char *str, const char *delim, char **saveptr) {
207 #if defined _WIN32
208   return strtok_s(str, delim, saveptr);
209 #else
210   return strtok_r(str, delim, saveptr);
211 #endif
212 }
213 
214 /* native_ rather than my_ since my_strcasecmp already exists */
native_strcasecmp(const char * s1,const char * s2)215 static inline int native_strcasecmp(const char *s1, const char *s2) {
216 #if defined _WIN32
217   return _stricmp(s1, s2);
218 #else
219   return strcasecmp(s1, s2);
220 #endif
221 }
222 
223 /* native_ rather than my_ for consistency with native_strcasecmp */
native_strncasecmp(const char * s1,const char * s2,size_t n)224 static inline int native_strncasecmp(const char *s1, const char *s2, size_t n) {
225 #if defined _WIN32
226   return _strnicmp(s1, s2, n);
227 #else
228   return strncasecmp(s1, s2, n);
229 #endif
230 }
231 
232 /*
233   is_prefix(s, t) returns 1 if s starts with t.
234   A empty t is always a prefix.
235 */
is_prefix(const char * s,const char * t)236 static inline int is_prefix(const char *s, const char *t) {
237   while (*t)
238     if (*s++ != *t++) return 0;
239   return 1; /* WRONG */
240 }
241 
242 /* Conversion routines */
243 typedef enum { MY_GCVT_ARG_FLOAT, MY_GCVT_ARG_DOUBLE } my_gcvt_arg_type;
244 
245 double my_strtod(const char *str, char **end, int *error);
246 double my_atof(const char *nptr);
247 size_t my_fcvt(double x, int precision, char *to, bool *error);
248 size_t my_gcvt(double x, my_gcvt_arg_type type, int width, char *to,
249                bool *error);
250 
251 #define NOT_FIXED_DEC 31
252 
253 /*
254   The longest string my_fcvt can return is 311 + "precision" bytes.
255   Here we assume that we never cal my_fcvt() with precision >= NOT_FIXED_DEC
256   (+ 1 byte for the terminating '\0').
257 */
258 #define FLOATING_POINT_BUFFER (311 + NOT_FIXED_DEC)
259 
260 /*
261   We want to use the 'e' format in some cases even if we have enough space
262   for the 'f' one just to mimic sprintf("%.15g") behavior for large integers,
263   and to improve it for numbers < 10^(-4).
264   That is, for |x| < 1 we require |x| >= 10^(-15), and for |x| > 1 we require
265   it to be integer and be <= 10^DBL_DIG for the 'f' format to be used.
266   We don't lose precision, but make cases like "1e200" or "0.00001" look nicer.
267 */
268 #define MAX_DECPT_FOR_F_FORMAT DBL_DIG
269 
270 /*
271   The maximum possible field width for my_gcvt() conversion.
272   (DBL_DIG + 2) significant digits + sign + "." + ("e-NNN" or
273   MAX_DECPT_FOR_F_FORMAT zeros for cases when |x|<1 and the 'f' format is used).
274 */
275 #define MY_GCVT_MAX_FIELD_WIDTH \
276   (DBL_DIG + 4 + MY_MAX(5, MAX_DECPT_FOR_F_FORMAT))
277 
278 extern char *int2str(long val, char *dst, int radix, int upcase);
279 C_MODE_START
280 extern char *int10_to_str(long val, char *dst, int radix);
281 C_MODE_END
282 extern char *str2int(const char *src, int radix, long lower, long upper,
283                      long *val);
284 longlong my_strtoll10(const char *nptr, char **endptr, int *error);
285 #if SIZEOF_LONG == SIZEOF_LONG_LONG
286 #define ll2str(A, B, C, D) int2str((A), (B), (C), (D))
287 #define longlong10_to_str(A, B, C) int10_to_str((A), (B), (C))
288 #undef strtoll
289 #define strtoll(A, B, C) strtol((A), (B), (C))
290 #define strtoull(A, B, C) strtoul((A), (B), (C))
291 #else
292 extern char *ll2str(longlong val, char *dst, int radix, int upcase);
293 extern char *longlong10_to_str(longlong val, char *dst, int radix);
294 #endif
295 #define longlong2str(A, B, C) ll2str((A), (B), (C), 1)
296 
297 /*
298   This function saves a longlong value in a buffer and returns the pointer to
299   the buffer.
300 */
llstr(longlong value,char * buff)301 static inline char *llstr(longlong value, char *buff) {
302   longlong10_to_str(value, buff, -10);
303   return buff;
304 }
305 
ullstr(longlong value,char * buff)306 static inline char *ullstr(longlong value, char *buff) {
307   longlong10_to_str(value, buff, 10);
308   return buff;
309 }
310 
311 #define STRING_WITH_LEN(X) (X), ((sizeof(X) - 1))
312 #define USTRING_WITH_LEN(X) ((uchar *)X), ((sizeof(X) - 1))
313 #define C_STRING_WITH_LEN(X) ((char *)(X)), ((sizeof(X) - 1))
314 
315 /**
316   Skip trailing space (ASCII spaces only).
317 
318   @return New end of the string.
319 */
skip_trailing_space(const uchar * ptr,size_t len)320 static inline const uchar *skip_trailing_space(const uchar *ptr, size_t len) {
321   const uchar *end = ptr + len;
322   while (end - ptr >= 8) {
323     uint64_t chunk;
324     memcpy(&chunk, end - 8, sizeof(chunk));
325     if (chunk != 0x2020202020202020ULL) break;
326     end -= 8;
327   }
328   while (end > ptr && end[-1] == 0x20) end--;
329   return (end);
330 }
331 
lex_string_set(LEX_STRING * lex_str,const char * c_str)332 static inline void lex_string_set(LEX_STRING *lex_str, const char *c_str) {
333   lex_str->str = (char *)c_str;
334   lex_str->length = strlen(c_str);
335 }
336 
lex_cstring_set(LEX_CSTRING * lex_str,const char * c_str)337 static inline void lex_cstring_set(LEX_CSTRING *lex_str, const char *c_str) {
338   lex_str->str = c_str;
339   lex_str->length = strlen(c_str);
340 }
341 
342 #endif
343