1 | /* Copyright (c) 2000, 2010, 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 as published by |
5 | the Free Software Foundation; version 2 of the License. |
6 | |
7 | This program is distributed in the hope that it will be useful, |
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | GNU General Public License for more details. |
11 | |
12 | You should have received a copy of the GNU General Public License |
13 | along with this program; if not, write to the Free Software |
14 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
15 | |
16 | /* |
17 | Code for handling strings with can grow dynamicly. |
18 | Copyright Monty Program KB. |
19 | By monty. |
20 | */ |
21 | |
22 | #include "mysys_priv.h" |
23 | #include <m_string.h> |
24 | |
25 | my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str, |
26 | size_t init_alloc, size_t alloc_increment) |
27 | { |
28 | size_t length; |
29 | DBUG_ENTER("init_dynamic_string" ); |
30 | |
31 | if (!alloc_increment) |
32 | alloc_increment=128; |
33 | length=1; |
34 | if (init_str && (length= strlen(init_str)+1) < init_alloc) |
35 | init_alloc=((length+alloc_increment-1)/alloc_increment)*alloc_increment; |
36 | if (!init_alloc) |
37 | init_alloc=alloc_increment; |
38 | |
39 | if (!(str->str=(char*) my_malloc(init_alloc,MYF(MY_WME)))) |
40 | DBUG_RETURN(TRUE); |
41 | str->length=length-1; |
42 | if (init_str) |
43 | memcpy(str->str,init_str,length); |
44 | str->max_length=init_alloc; |
45 | str->alloc_increment=alloc_increment; |
46 | DBUG_RETURN(FALSE); |
47 | } |
48 | |
49 | |
50 | my_bool dynstr_set(DYNAMIC_STRING *str, const char *init_str) |
51 | { |
52 | uint length=0; |
53 | DBUG_ENTER("dynstr_set" ); |
54 | |
55 | if (init_str && (length= (uint) strlen(init_str)+1) > str->max_length) |
56 | { |
57 | str->max_length=((length+str->alloc_increment-1)/str->alloc_increment)* |
58 | str->alloc_increment; |
59 | if (!str->max_length) |
60 | str->max_length=str->alloc_increment; |
61 | if (!(str->str=(char*) my_realloc(str->str,str->max_length,MYF(MY_WME)))) |
62 | DBUG_RETURN(TRUE); |
63 | } |
64 | if (init_str) |
65 | { |
66 | str->length=length-1; |
67 | memcpy(str->str,init_str,length); |
68 | } |
69 | else |
70 | str->length=0; |
71 | DBUG_RETURN(FALSE); |
72 | } |
73 | |
74 | |
75 | my_bool dynstr_realloc(DYNAMIC_STRING *str, size_t additional_size) |
76 | { |
77 | DBUG_ENTER("dynstr_realloc" ); |
78 | |
79 | if (!additional_size) DBUG_RETURN(FALSE); |
80 | if (str->length + additional_size > str->max_length) |
81 | { |
82 | str->max_length=((str->length + additional_size+str->alloc_increment-1)/ |
83 | str->alloc_increment)*str->alloc_increment; |
84 | if (!(str->str=(char*) my_realloc(str->str,str->max_length,MYF(MY_WME)))) |
85 | DBUG_RETURN(TRUE); |
86 | } |
87 | DBUG_RETURN(FALSE); |
88 | } |
89 | |
90 | |
91 | my_bool dynstr_append(DYNAMIC_STRING *str, const char *append) |
92 | { |
93 | return dynstr_append_mem(str,append,(uint) strlen(append)); |
94 | } |
95 | |
96 | |
97 | my_bool dynstr_append_mem(DYNAMIC_STRING *str, const char *append, |
98 | size_t length) |
99 | { |
100 | char *new_ptr; |
101 | DBUG_ENTER("dynstr_append_mem" ); |
102 | if (str->length+length >= str->max_length) |
103 | { |
104 | size_t new_length=(str->length+length+str->alloc_increment)/ |
105 | str->alloc_increment; |
106 | new_length*=str->alloc_increment; |
107 | if (!(new_ptr=(char*) my_realloc(str->str,new_length,MYF(MY_WME)))) |
108 | DBUG_RETURN(TRUE); |
109 | str->str=new_ptr; |
110 | str->max_length=new_length; |
111 | } |
112 | memcpy(str->str + str->length,append,length); |
113 | str->length+=length; |
114 | str->str[str->length]=0; /* Safety for C programs */ |
115 | DBUG_RETURN(FALSE); |
116 | } |
117 | |
118 | |
119 | my_bool dynstr_trunc(DYNAMIC_STRING *str, size_t n) |
120 | { |
121 | str->length-=n; |
122 | str->str[str->length]= '\0'; |
123 | return FALSE; |
124 | } |
125 | |
126 | /* |
127 | Concatenates any number of strings, escapes any OS quote in the result then |
128 | surround the whole affair in another set of quotes which is finally appended |
129 | to specified DYNAMIC_STRING. This function is especially useful when |
130 | building strings to be executed with the system() function. |
131 | |
132 | @param str Dynamic String which will have addtional strings appended. |
133 | @param append String to be appended. |
134 | @param ... Optional. Additional string(s) to be appended. |
135 | |
136 | @note The final argument in the list must be NullS even if no additional |
137 | options are passed. |
138 | |
139 | @return True = Success. |
140 | */ |
141 | |
142 | my_bool dynstr_append_os_quoted(DYNAMIC_STRING *str, const char *append, ...) |
143 | { |
144 | #ifdef __WIN__ |
145 | LEX_CSTRING quote= { C_STRING_WITH_LEN("\"" ) }; |
146 | LEX_CSTRING replace= { C_STRING_WITH_LEN("\\\"" ) }; |
147 | #else |
148 | LEX_CSTRING quote= { C_STRING_WITH_LEN("\'" ) }; |
149 | LEX_CSTRING replace= { C_STRING_WITH_LEN("'\"'\"'" ) }; |
150 | #endif /* __WIN__ */ |
151 | my_bool ret= TRUE; |
152 | va_list dirty_text; |
153 | |
154 | ret&= dynstr_append_mem(str, quote.str, quote.length); /* Leading quote */ |
155 | va_start(dirty_text, append); |
156 | while (append != NullS) |
157 | { |
158 | const char *cur_pos= append; |
159 | const char *next_pos= cur_pos; |
160 | |
161 | /* Search for quote in each string and replace with escaped quote */ |
162 | while(*(next_pos= strcend(cur_pos, quote.str[0])) != '\0') |
163 | { |
164 | ret&= dynstr_append_mem(str, cur_pos, (uint) (next_pos - cur_pos)); |
165 | ret&= dynstr_append_mem(str, replace.str, replace.length); |
166 | cur_pos= next_pos + 1; |
167 | } |
168 | ret&= dynstr_append_mem(str, cur_pos, (uint) (next_pos - cur_pos)); |
169 | append= va_arg(dirty_text, char *); |
170 | } |
171 | va_end(dirty_text); |
172 | ret&= dynstr_append_mem(str, quote.str, quote.length); /* Trailing quote */ |
173 | |
174 | return ret; |
175 | } |
176 | |
177 | my_bool dynstr_append_quoted(DYNAMIC_STRING *str, |
178 | const char *append, size_t len, |
179 | char quote) |
180 | { |
181 | size_t additional= (str->alloc_increment ? str->alloc_increment : 10); |
182 | size_t lim= additional; |
183 | size_t i; |
184 | if (dynstr_realloc(str, len + additional + 2)) |
185 | return TRUE; |
186 | str->str[str->length++]= quote; |
187 | for (i= 0; i < len; i++) |
188 | { |
189 | register char c= append[i]; |
190 | if (c == quote || c == '\\') |
191 | { |
192 | if (!lim) |
193 | { |
194 | if (dynstr_realloc(str, additional)) |
195 | return TRUE; |
196 | lim= additional; |
197 | } |
198 | lim--; |
199 | str->str[str->length++]= '\\'; |
200 | } |
201 | str->str[str->length++]= c; |
202 | } |
203 | str->str[str->length++]= quote; |
204 | return FALSE; |
205 | } |
206 | |
207 | |
208 | void dynstr_free(DYNAMIC_STRING *str) |
209 | { |
210 | if (str->str) /* Safety to allow double free */ |
211 | my_free(str->str); |
212 | str->str= NULL; |
213 | } |
214 | |
215 | |
216 | /* Give over the control of the dynamic string to caller */ |
217 | |
218 | void dynstr_reassociate(DYNAMIC_STRING *str, char **ptr, size_t *length, |
219 | size_t *alloc_length) |
220 | { |
221 | *ptr= str->str; |
222 | *length= str->length; |
223 | *alloc_length= str->max_length; |
224 | str->str=0; |
225 | } |
226 | |