00001 /* Copyright (C) 2000 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 /* This file is originally from the mysql distribution. Coded by monty */ 00018 00019 #ifdef USE_PRAGMA_IMPLEMENTATION 00020 #pragma implementation // gcc: Class implementation 00021 #endif 00022 00023 #include <my_global.h> 00024 #include <my_sys.h> 00025 #include <m_string.h> 00026 #include <m_ctype.h> 00027 #ifdef HAVE_FCONVERT 00028 #include <floatingpoint.h> 00029 #endif 00030 00031 /* 00032 The following extern declarations are ok as these are interface functions 00033 required by the string function 00034 */ 00035 00036 extern gptr sql_alloc(unsigned size); 00037 extern void sql_element_free(void *ptr); 00038 00039 #include "sql_string.h" 00040 00041 /***************************************************************************** 00042 ** String functions 00043 *****************************************************************************/ 00044 00045 bool String::real_alloc(uint32 arg_length) 00046 { 00047 arg_length=ALIGN_SIZE(arg_length+1); 00048 str_length=0; 00049 if (Alloced_length < arg_length) 00050 { 00051 free(); 00052 if (!(Ptr=(char*) my_malloc(arg_length,MYF(MY_WME)))) 00053 return TRUE; 00054 Alloced_length=arg_length; 00055 alloced=1; 00056 } 00057 Ptr[0]=0; 00058 return FALSE; 00059 } 00060 00061 00062 /* 00063 ** Check that string is big enough. Set string[alloc_length] to 0 00064 ** (for C functions) 00065 */ 00066 00067 bool String::realloc(uint32 alloc_length) 00068 { 00069 uint32 len=ALIGN_SIZE(alloc_length+1); 00070 if (Alloced_length < len) 00071 { 00072 char *new_ptr; 00073 if (alloced) 00074 { 00075 if ((new_ptr= (char*) my_realloc(Ptr,len,MYF(MY_WME)))) 00076 { 00077 Ptr=new_ptr; 00078 Alloced_length=len; 00079 } 00080 else 00081 return TRUE; // Signal error 00082 } 00083 else if ((new_ptr= (char*) my_malloc(len,MYF(MY_WME)))) 00084 { 00085 if (str_length) // Avoid bugs in memcpy on AIX 00086 memcpy(new_ptr,Ptr,str_length); 00087 new_ptr[str_length]=0; 00088 Ptr=new_ptr; 00089 Alloced_length=len; 00090 alloced=1; 00091 } 00092 else 00093 return TRUE; // Signal error 00094 } 00095 Ptr[alloc_length]=0; // This make other funcs shorter 00096 return FALSE; 00097 } 00098 00099 bool String::set(longlong num, CHARSET_INFO *cs) 00100 { 00101 uint l=20*cs->mbmaxlen+1; 00102 00103 if (alloc(l)) 00104 return TRUE; 00105 str_length=(uint32) (cs->cset->longlong10_to_str)(cs,Ptr,l,-10,num); 00106 str_charset=cs; 00107 return FALSE; 00108 } 00109 00110 bool String::set(ulonglong num, CHARSET_INFO *cs) 00111 { 00112 uint l=20*cs->mbmaxlen+1; 00113 00114 if (alloc(l)) 00115 return TRUE; 00116 str_length=(uint32) (cs->cset->longlong10_to_str)(cs,Ptr,l,10,num); 00117 str_charset=cs; 00118 return FALSE; 00119 } 00120 00121 bool String::set(double num,uint decimals, CHARSET_INFO *cs) 00122 { 00123 char buff[331]; 00124 uint dummy_errors; 00125 00126 str_charset=cs; 00127 if (decimals >= NOT_FIXED_DEC) 00128 { 00129 uint32 len= my_sprintf(buff,(buff, "%.14g",num));// Enough for a DATETIME 00130 return copy(buff, len, &my_charset_latin1, cs, &dummy_errors); 00131 } 00132 #ifdef HAVE_FCONVERT 00133 int decpt,sign; 00134 char *pos,*to; 00135 00136 VOID(fconvert(num,(int) decimals,&decpt,&sign,buff+1)); 00137 if (!my_isdigit(&my_charset_latin1, buff[1])) 00138 { // Nan or Inf 00139 pos=buff+1; 00140 if (sign) 00141 { 00142 buff[0]='-'; 00143 pos=buff; 00144 } 00145 uint dummy_errors; 00146 return copy(pos,(uint32) strlen(pos), &my_charset_latin1, cs, &dummy_errors); 00147 } 00148 if (alloc((uint32) ((uint32) decpt+3+decimals))) 00149 return TRUE; 00150 to=Ptr; 00151 if (sign) 00152 *to++='-'; 00153 00154 pos=buff+1; 00155 if (decpt < 0) 00156 { /* value is < 0 */ 00157 *to++='0'; 00158 if (!decimals) 00159 goto end; 00160 *to++='.'; 00161 if ((uint32) -decpt > decimals) 00162 decpt= - (int) decimals; 00163 decimals=(uint32) ((int) decimals+decpt); 00164 while (decpt++ < 0) 00165 *to++='0'; 00166 } 00167 else if (decpt == 0) 00168 { 00169 *to++= '0'; 00170 if (!decimals) 00171 goto end; 00172 *to++='.'; 00173 } 00174 else 00175 { 00176 while (decpt-- > 0) 00177 *to++= *pos++; 00178 if (!decimals) 00179 goto end; 00180 *to++='.'; 00181 } 00182 while (decimals--) 00183 *to++= *pos++; 00184 00185 end: 00186 *to=0; 00187 str_length=(uint32) (to-Ptr); 00188 return FALSE; 00189 #else 00190 #ifdef HAVE_SNPRINTF 00191 buff[sizeof(buff)-1]=0; // Safety 00192 snprintf(buff,sizeof(buff)-1, "%.*f",(int) decimals,num); 00193 #else 00194 sprintf(buff,"%.*f",(int) decimals,num); 00195 #endif 00196 return copy(buff,(uint32) strlen(buff), &my_charset_latin1, cs, 00197 &dummy_errors); 00198 #endif 00199 } 00200 00201 00202 bool String::copy() 00203 { 00204 if (!alloced) 00205 { 00206 Alloced_length=0; // Force realloc 00207 return realloc(str_length); 00208 } 00209 return FALSE; 00210 } 00211 00212 bool String::copy(const String &str) 00213 { 00214 if (alloc(str.str_length)) 00215 return TRUE; 00216 str_length=str.str_length; 00217 bmove(Ptr,str.Ptr,str_length); // May be overlapping 00218 Ptr[str_length]=0; 00219 str_charset=str.str_charset; 00220 return FALSE; 00221 } 00222 00223 bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *cs) 00224 { 00225 if (alloc(arg_length)) 00226 return TRUE; 00227 if ((str_length=arg_length)) 00228 memcpy(Ptr,str,arg_length); 00229 Ptr[arg_length]=0; 00230 str_charset=cs; 00231 return FALSE; 00232 } 00233 00234 00235 /* 00236 Checks that the source string can be just copied to the destination string 00237 without conversion. 00238 00239 SYNPOSIS 00240 00241 needs_conversion() 00242 arg_length Length of string to copy. 00243 from_cs Character set to copy from 00244 to_cs Character set to copy to 00245 uint32 *offset Returns number of unaligned characters. 00246 00247 RETURN 00248 0 No conversion needed 00249 1 Either character set conversion or adding leading zeros 00250 (e.g. for UCS-2) must be done 00251 */ 00252 00253 bool String::needs_conversion(uint32 arg_length, 00254 CHARSET_INFO *from_cs, 00255 CHARSET_INFO *to_cs, 00256 uint32 *offset) 00257 { 00258 *offset= 0; 00259 if ((to_cs == &my_charset_bin) || 00260 (to_cs == from_cs) || 00261 my_charset_same(from_cs, to_cs) || 00262 ((from_cs == &my_charset_bin) && 00263 (!(*offset=(arg_length % to_cs->mbminlen))))) 00264 return FALSE; 00265 return TRUE; 00266 } 00267 00268 00269 /* 00270 Copy a multi-byte character sets with adding leading zeros. 00271 00272 SYNOPSIS 00273 00274 copy_aligned() 00275 str String to copy 00276 arg_length Length of string. This should NOT be dividable with 00277 cs->mbminlen. 00278 offset arg_length % cs->mb_minlength 00279 cs Character set for 'str' 00280 00281 NOTES 00282 For real multi-byte, ascii incompatible charactser sets, 00283 like UCS-2, add leading zeros if we have an incomplete character. 00284 Thus, 00285 SELECT _ucs2 0xAA 00286 will automatically be converted into 00287 SELECT _ucs2 0x00AA 00288 00289 RETURN 00290 0 ok 00291 1 error 00292 */ 00293 00294 bool String::copy_aligned(const char *str,uint32 arg_length, uint32 offset, 00295 CHARSET_INFO *cs) 00296 { 00297 /* How many bytes are in incomplete character */ 00298 offset= cs->mbmaxlen - offset; /* How many zeros we should prepend */ 00299 DBUG_ASSERT(offset && offset != cs->mbmaxlen); 00300 00301 uint32 aligned_length= arg_length + offset; 00302 if (alloc(aligned_length)) 00303 return TRUE; 00304 00305 /* 00306 Note, this is only safe for little-endian UCS-2. 00307 If we add big-endian UCS-2 sometimes, this code 00308 will be more complicated. But it's OK for now. 00309 */ 00310 bzero((char*) Ptr, offset); 00311 memcpy(Ptr + offset, str, arg_length); 00312 Ptr[aligned_length]=0; 00313 /* str_length is always >= 0 as arg_length is != 0 */ 00314 str_length= aligned_length; 00315 str_charset= cs; 00316 return FALSE; 00317 } 00318 00319 00320 bool String::set_or_copy_aligned(const char *str,uint32 arg_length, 00321 CHARSET_INFO *cs) 00322 { 00323 /* How many bytes are in incomplete character */ 00324 uint32 offset= (arg_length % cs->mbminlen); 00325 00326 if (!offset) /* All characters are complete, just copy */ 00327 { 00328 set(str, arg_length, cs); 00329 return FALSE; 00330 } 00331 return copy_aligned(str, arg_length, offset, cs); 00332 } 00333 00334 /* Copy with charset convertion */ 00335 00336 bool String::copy(const char *str, uint32 arg_length, 00337 CHARSET_INFO *from_cs, CHARSET_INFO *to_cs, uint *errors) 00338 { 00339 uint32 offset; 00340 if (!needs_conversion(arg_length, from_cs, to_cs, &offset)) 00341 { 00342 *errors= 0; 00343 return copy(str, arg_length, to_cs); 00344 } 00345 if ((from_cs == &my_charset_bin) && offset) 00346 { 00347 *errors= 0; 00348 return copy_aligned(str, arg_length, offset, to_cs); 00349 } 00350 uint32 new_length= to_cs->mbmaxlen*arg_length; 00351 if (alloc(new_length)) 00352 return TRUE; 00353 str_length=copy_and_convert((char*) Ptr, new_length, to_cs, 00354 str, arg_length, from_cs, errors); 00355 str_charset=to_cs; 00356 return FALSE; 00357 } 00358 00359 00360 /* 00361 Set a string to the value of a latin1-string, keeping the original charset 00362 00363 SYNOPSIS 00364 copy_or_set() 00365 str String of a simple charset (latin1) 00366 arg_length Length of string 00367 00368 IMPLEMENTATION 00369 If string object is of a simple character set, set it to point to the 00370 given string. 00371 If not, make a copy and convert it to the new character set. 00372 00373 RETURN 00374 0 ok 00375 1 Could not allocate result buffer 00376 00377 */ 00378 00379 bool String::set_ascii(const char *str, uint32 arg_length) 00380 { 00381 if (str_charset->mbminlen == 1) 00382 { 00383 set(str, arg_length, str_charset); 00384 return 0; 00385 } 00386 uint dummy_errors; 00387 return copy(str, arg_length, &my_charset_latin1, str_charset, &dummy_errors); 00388 } 00389 00390 00391 /* This is used by mysql.cc */ 00392 00393 bool String::fill(uint32 max_length,char fill_char) 00394 { 00395 if (str_length > max_length) 00396 Ptr[str_length=max_length]=0; 00397 else 00398 { 00399 if (realloc(max_length)) 00400 return TRUE; 00401 bfill(Ptr+str_length,max_length-str_length,fill_char); 00402 str_length=max_length; 00403 } 00404 return FALSE; 00405 } 00406 00407 void String::strip_sp() 00408 { 00409 while (str_length && my_isspace(str_charset,Ptr[str_length-1])) 00410 str_length--; 00411 } 00412 00413 bool String::append(const String &s) 00414 { 00415 if (s.length()) 00416 { 00417 if (realloc(str_length+s.length())) 00418 return TRUE; 00419 memcpy(Ptr+str_length,s.ptr(),s.length()); 00420 str_length+=s.length(); 00421 } 00422 return FALSE; 00423 } 00424 00425 00426 /* 00427 Append an ASCII string to the a string of the current character set 00428 */ 00429 00430 bool String::append(const char *s,uint32 arg_length) 00431 { 00432 if (!arg_length) 00433 return FALSE; 00434 00435 /* 00436 For an ASCII incompatible string, e.g. UCS-2, we need to convert 00437 */ 00438 if (str_charset->mbminlen > 1) 00439 { 00440 uint32 add_length=arg_length * str_charset->mbmaxlen; 00441 uint dummy_errors; 00442 if (realloc(str_length+ add_length)) 00443 return TRUE; 00444 str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset, 00445 s, arg_length, &my_charset_latin1, 00446 &dummy_errors); 00447 return FALSE; 00448 } 00449 00450 /* 00451 For an ASCII compatinble string we can just append. 00452 */ 00453 if (realloc(str_length+arg_length)) 00454 return TRUE; 00455 memcpy(Ptr+str_length,s,arg_length); 00456 str_length+=arg_length; 00457 return FALSE; 00458 } 00459 00460 00461 /* 00462 Append a 0-terminated ASCII string 00463 */ 00464 00465 bool String::append(const char *s) 00466 { 00467 return append(s, strlen(s)); 00468 } 00469 00470 00471 /* 00472 Append a string in the given charset to the string 00473 with character set recoding 00474 */ 00475 00476 bool String::append(const char *s,uint32 arg_length, CHARSET_INFO *cs) 00477 { 00478 uint32 dummy_offset; 00479 00480 if (needs_conversion(arg_length, cs, str_charset, &dummy_offset)) 00481 { 00482 uint32 add_length= arg_length / cs->mbminlen * str_charset->mbmaxlen; 00483 uint dummy_errors; 00484 if (realloc(str_length + add_length)) 00485 return TRUE; 00486 str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset, 00487 s, arg_length, cs, &dummy_errors); 00488 } 00489 else 00490 { 00491 if (realloc(str_length + arg_length)) 00492 return TRUE; 00493 memcpy(Ptr + str_length, s, arg_length); 00494 str_length+= arg_length; 00495 } 00496 return FALSE; 00497 } 00498 00499 00500 #ifdef TO_BE_REMOVED 00501 bool String::append(FILE* file, uint32 arg_length, myf my_flags) 00502 { 00503 if (realloc(str_length+arg_length)) 00504 return TRUE; 00505 if (my_fread(file, (byte*) Ptr + str_length, arg_length, my_flags)) 00506 { 00507 shrink(str_length); 00508 return TRUE; 00509 } 00510 str_length+=arg_length; 00511 return FALSE; 00512 } 00513 #endif 00514 00515 bool String::append(IO_CACHE* file, uint32 arg_length) 00516 { 00517 if (realloc(str_length+arg_length)) 00518 return TRUE; 00519 if (my_b_read(file, (byte*) Ptr + str_length, arg_length)) 00520 { 00521 shrink(str_length); 00522 return TRUE; 00523 } 00524 str_length+=arg_length; 00525 return FALSE; 00526 } 00527 00528 bool String::append_with_prefill(const char *s,uint32 arg_length, 00529 uint32 full_length, char fill_char) 00530 { 00531 int t_length= arg_length > full_length ? arg_length : full_length; 00532 00533 if (realloc(str_length + t_length)) 00534 return TRUE; 00535 t_length= full_length - arg_length; 00536 if (t_length > 0) 00537 { 00538 bfill(Ptr+str_length, t_length, fill_char); 00539 str_length=str_length + t_length; 00540 } 00541 append(s, arg_length); 00542 return FALSE; 00543 } 00544 00545 uint32 String::numchars() 00546 { 00547 return str_charset->cset->numchars(str_charset, Ptr, Ptr+str_length); 00548 } 00549 00550 int String::charpos(int i,uint32 offset) 00551 { 00552 if (i <= 0) 00553 return i; 00554 return str_charset->cset->charpos(str_charset,Ptr+offset,Ptr+str_length,i); 00555 } 00556 00557 int String::strstr(const String &s,uint32 offset) 00558 { 00559 if (s.length()+offset <= str_length) 00560 { 00561 if (!s.length()) 00562 return ((int) offset); // Empty string is always found 00563 00564 register const char *str = Ptr+offset; 00565 register const char *search=s.ptr(); 00566 const char *end=Ptr+str_length-s.length()+1; 00567 const char *search_end=s.ptr()+s.length(); 00568 skip: 00569 while (str != end) 00570 { 00571 if (*str++ == *search) 00572 { 00573 register char *i,*j; 00574 i=(char*) str; j=(char*) search+1; 00575 while (j != search_end) 00576 if (*i++ != *j++) goto skip; 00577 return (int) (str-Ptr) -1; 00578 } 00579 } 00580 } 00581 return -1; 00582 } 00583 00584 /* 00585 ** Search string from end. Offset is offset to the end of string 00586 */ 00587 00588 int String::strrstr(const String &s,uint32 offset) 00589 { 00590 if (s.length() <= offset && offset <= str_length) 00591 { 00592 if (!s.length()) 00593 return offset; // Empty string is always found 00594 register const char *str = Ptr+offset-1; 00595 register const char *search=s.ptr()+s.length()-1; 00596 00597 const char *end=Ptr+s.length()-2; 00598 const char *search_end=s.ptr()-1; 00599 skip: 00600 while (str != end) 00601 { 00602 if (*str-- == *search) 00603 { 00604 register char *i,*j; 00605 i=(char*) str; j=(char*) search-1; 00606 while (j != search_end) 00607 if (*i-- != *j--) goto skip; 00608 return (int) (i-Ptr) +1; 00609 } 00610 } 00611 } 00612 return -1; 00613 } 00614 00615 /* 00616 ** replace substring with string 00617 ** If wrong parameter or not enough memory, do nothing 00618 */ 00619 00620 00621 bool String::replace(uint32 offset,uint32 arg_length,const String &to) 00622 { 00623 return replace(offset,arg_length,to.ptr(),to.length()); 00624 } 00625 00626 bool String::replace(uint32 offset,uint32 arg_length, 00627 const char *to,uint32 length) 00628 { 00629 long diff = (long) length-(long) arg_length; 00630 if (offset+arg_length <= str_length) 00631 { 00632 if (diff < 0) 00633 { 00634 if (length) 00635 memcpy(Ptr+offset,to,length); 00636 bmove(Ptr+offset+length,Ptr+offset+arg_length, 00637 str_length-offset-arg_length); 00638 } 00639 else 00640 { 00641 if (diff) 00642 { 00643 if (realloc(str_length+(uint32) diff)) 00644 return TRUE; 00645 bmove_upp(Ptr+str_length+diff,Ptr+str_length, 00646 str_length-offset-arg_length); 00647 } 00648 if (length) 00649 memcpy(Ptr+offset,to,length); 00650 } 00651 str_length+=(uint32) diff; 00652 } 00653 return FALSE; 00654 } 00655 00656 00657 // added by Holyfoot for "geometry" needs 00658 int String::reserve(uint32 space_needed, uint32 grow_by) 00659 { 00660 if (Alloced_length < str_length + space_needed) 00661 { 00662 if (realloc(Alloced_length + max(space_needed, grow_by) - 1)) 00663 return TRUE; 00664 } 00665 return FALSE; 00666 } 00667 00668 void String::qs_append(const char *str, uint32 len) 00669 { 00670 memcpy(Ptr + str_length, str, len + 1); 00671 str_length += len; 00672 } 00673 00674 void String::qs_append(double d) 00675 { 00676 char *buff = Ptr + str_length; 00677 str_length+= my_sprintf(buff, (buff, "%.14g", d)); 00678 } 00679 00680 void String::qs_append(double *d) 00681 { 00682 double ld; 00683 float8get(ld, (char*) d); 00684 qs_append(ld); 00685 } 00686 00687 void String::qs_append(int i) 00688 { 00689 char *buff= Ptr + str_length; 00690 char *end= int10_to_str(i, buff, -10); 00691 str_length+= (int) (end-buff); 00692 } 00693 00694 void String::qs_append(uint i) 00695 { 00696 char *buff= Ptr + str_length; 00697 char *end= int10_to_str(i, buff, 10); 00698 str_length+= (int) (end-buff); 00699 } 00700 00701 /* 00702 Compare strings according to collation, without end space. 00703 00704 SYNOPSIS 00705 sortcmp() 00706 s First string 00707 t Second string 00708 cs Collation 00709 00710 NOTE: 00711 Normally this is case sensitive comparison 00712 00713 RETURN 00714 < 0 s < t 00715 0 s == t 00716 > 0 s > t 00717 */ 00718 00719 00720 int sortcmp(const String *s,const String *t, CHARSET_INFO *cs) 00721 { 00722 return cs->coll->strnncollsp(cs, 00723 (unsigned char *) s->ptr(),s->length(), 00724 (unsigned char *) t->ptr(),t->length(), 0); 00725 } 00726 00727 00728 /* 00729 Compare strings byte by byte. End spaces are also compared. 00730 00731 SYNOPSIS 00732 stringcmp() 00733 s First string 00734 t Second string 00735 00736 NOTE: 00737 Strings are compared as a stream of unsigned chars 00738 00739 RETURN 00740 < 0 s < t 00741 0 s == t 00742 > 0 s > t 00743 */ 00744 00745 00746 int stringcmp(const String *s,const String *t) 00747 { 00748 uint32 s_len=s->length(),t_len=t->length(),len=min(s_len,t_len); 00749 int cmp= memcmp(s->ptr(), t->ptr(), len); 00750 return (cmp) ? cmp : (int) (s_len - t_len); 00751 } 00752 00753 00754 String *copy_if_not_alloced(String *to,String *from,uint32 from_length) 00755 { 00756 if (from->Alloced_length >= from_length) 00757 return from; 00758 if (from->alloced || !to || from == to) 00759 { 00760 (void) from->realloc(from_length); 00761 return from; 00762 } 00763 if (to->realloc(from_length)) 00764 return from; // Actually an error 00765 if ((to->str_length=min(from->str_length,from_length))) 00766 memcpy(to->Ptr,from->Ptr,to->str_length); 00767 to->str_charset=from->str_charset; 00768 return to; 00769 } 00770 00771 00772 /**************************************************************************** 00773 Help functions 00774 ****************************************************************************/ 00775 00776 /* 00777 copy a string from one character set to another 00778 00779 SYNOPSIS 00780 copy_and_convert() 00781 to Store result here 00782 to_cs Character set of result string 00783 from Copy from here 00784 from_length Length of from string 00785 from_cs From character set 00786 00787 NOTES 00788 'to' must be big enough as form_length * to_cs->mbmaxlen 00789 00790 RETURN 00791 length of bytes copied to 'to' 00792 */ 00793 00794 00795 uint32 00796 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, 00797 const char *from, uint32 from_length, CHARSET_INFO *from_cs, 00798 uint *errors) 00799 { 00800 int cnvres; 00801 my_wc_t wc; 00802 const uchar *from_end= (const uchar*) from+from_length; 00803 char *to_start= to; 00804 uchar *to_end= (uchar*) to+to_length; 00805 int (*mb_wc)(struct charset_info_st *, my_wc_t *, const uchar *, 00806 const uchar *) = from_cs->cset->mb_wc; 00807 int (*wc_mb)(struct charset_info_st *, my_wc_t, uchar *s, uchar *e)= 00808 to_cs->cset->wc_mb; 00809 uint error_count= 0; 00810 00811 while (1) 00812 { 00813 if ((cnvres= (*mb_wc)(from_cs, &wc, (uchar*) from, 00814 from_end)) > 0) 00815 from+= cnvres; 00816 else if (cnvres == MY_CS_ILSEQ) 00817 { 00818 error_count++; 00819 from++; 00820 wc= '?'; 00821 } 00822 else 00823 break; // Impossible char. 00824 00825 outp: 00826 if ((cnvres= (*wc_mb)(to_cs, wc, (uchar*) to, to_end)) > 0) 00827 to+= cnvres; 00828 else if (cnvres == MY_CS_ILUNI && wc != '?') 00829 { 00830 error_count++; 00831 wc= '?'; 00832 goto outp; 00833 } 00834 else 00835 break; 00836 } 00837 *errors= error_count; 00838 return (uint32) (to - to_start); 00839 } 00840 00841 00842 void String::print(String *str) 00843 { 00844 char *st= (char*)Ptr, *end= st+str_length; 00845 for (; st < end; st++) 00846 { 00847 uchar c= *st; 00848 switch (c) 00849 { 00850 case '\\': 00851 str->append("\\\\", 2); 00852 break; 00853 case '\0': 00854 str->append("\\0", 2); 00855 break; 00856 case '\'': 00857 str->append("\\'", 2); 00858 break; 00859 case '\n': 00860 str->append("\\n", 2); 00861 break; 00862 case '\r': 00863 str->append("\\r", 2); 00864 break; 00865 case 26: //Ctrl-Z 00866 str->append("\\z", 2); 00867 break; 00868 default: 00869 str->append(c); 00870 } 00871 } 00872 } 00873 00874 00875 /* 00876 Exchange state of this object and argument. 00877 00878 SYNOPSIS 00879 String::swap() 00880 00881 RETURN 00882 Target string will contain state of this object and vice versa. 00883 */ 00884 00885 void String::swap(String &s) 00886 { 00887 swap_variables(char *, Ptr, s.Ptr); 00888 swap_variables(uint32, str_length, s.str_length); 00889 swap_variables(uint32, Alloced_length, s.Alloced_length); 00890 swap_variables(bool, alloced, s.alloced); 00891 swap_variables(CHARSET_INFO*, str_charset, s.str_charset); 00892 }
1.4.7

