From b178b08ba77dc5207b84643b63f189a79463915a Mon Sep 17 00:00:00 2001 From: florian <florian@freepascal.org> Date: Wed, 10 Sep 2008 20:14:31 +0000 Subject: [PATCH] Merged revisions 11665-11738 via svnmerge from http://svn.freepascal.org/svn/fpc/branches/unicodestring ........ r11665 | florian | 2008-08-30 13:30:17 +0200 (Sat, 30 Aug 2008) | 1 line * continued to work on unicodestring type support ........ r11666 | florian | 2008-08-30 19:02:26 +0200 (Sat, 30 Aug 2008) | 2 lines * expectloc for wide/ansi/unicode strings is LOC_CONSTANT or LOC_REGISTER now ........ r11667 | florian | 2008-08-30 20:42:37 +0200 (Sat, 30 Aug 2008) | 1 line * more unicodestring stuff fixed, test results on win32 are already good ........ r11670 | florian | 2008-08-30 23:21:48 +0200 (Sat, 30 Aug 2008) | 2 lines * first fixes for unix bootstrapping ........ r11683 | ivost | 2008-09-01 12:46:39 +0200 (Mon, 01 Sep 2008) | 2 lines * fixed 64bit bug in iconvenc.pas ........ r11689 | florian | 2008-09-01 23:12:34 +0200 (Mon, 01 Sep 2008) | 1 line * fixed several errors when building on unix ........ r11694 | florian | 2008-09-03 20:32:43 +0200 (Wed, 03 Sep 2008) | 1 line * fixed unix compilation ........ r11695 | florian | 2008-09-03 21:01:04 +0200 (Wed, 03 Sep 2008) | 1 line * bootstrapping fix ........ r11696 | florian | 2008-09-03 21:07:18 +0200 (Wed, 03 Sep 2008) | 1 line * more bootstrapping fixed ........ r11698 | florian | 2008-09-03 22:47:54 +0200 (Wed, 03 Sep 2008) | 1 line + two missing compiler procs exported ........ r11701 | florian | 2008-09-04 16:42:34 +0200 (Thu, 04 Sep 2008) | 2 lines + lazarus project for the linux rtl ........ r11702 | florian | 2008-09-04 16:43:27 +0200 (Thu, 04 Sep 2008) | 2 lines + set unicode string procedures ........ r11707 | florian | 2008-09-04 23:23:02 +0200 (Thu, 04 Sep 2008) | 2 lines * fixed several type casting stuff ........ r11712 | florian | 2008-09-05 22:46:03 +0200 (Fri, 05 Sep 2008) | 1 line * fixed unicodestring compilation on windows after recent unix changes ........ r11713 | florian | 2008-09-05 23:35:12 +0200 (Fri, 05 Sep 2008) | 1 line + UnicodeString support for Variants ........ r11715 | florian | 2008-09-06 20:59:54 +0200 (Sat, 06 Sep 2008) | 1 line * patch by Martin Schreiber for UnicodeString streaming ........ r11716 | florian | 2008-09-06 22:22:55 +0200 (Sat, 06 Sep 2008) | 2 lines * fixed test ........ r11717 | florian | 2008-09-07 10:25:51 +0200 (Sun, 07 Sep 2008) | 1 line * fixed typo when converting tunicodestring to punicodechar ........ r11718 | florian | 2008-09-07 11:29:52 +0200 (Sun, 07 Sep 2008) | 3 lines * fixed writing of UnicodeString properties * moved some helper routines to unicode headers ........ r11734 | florian | 2008-09-09 22:38:55 +0200 (Tue, 09 Sep 2008) | 1 line * fixed bootstrapping ........ r11735 | florian | 2008-09-10 11:25:28 +0200 (Wed, 10 Sep 2008) | 2 lines * first fixes for persisten unicodestrings ........ r11736 | florian | 2008-09-10 14:31:00 +0200 (Wed, 10 Sep 2008) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-11663" from http://svn.freepascal.org/svn/fpc/trunk ........ r11737 | florian | 2008-09-10 21:06:57 +0200 (Wed, 10 Sep 2008) | 3 lines * fixed unicodestring <-> variant handling * fixed unicodestring property reading ........ git-svn-id: trunk@11739 - --- .gitattributes | 14 + compiler/ccharset.pas | 254 +++ compiler/cgobj.pas | 14 +- compiler/cp1251.pas | 2 +- compiler/cp437.pas | 2 +- compiler/cp850.pas | 2 +- compiler/cp866.pas | 2 +- compiler/cp8859_1.pas | 2 +- compiler/cp8859_5.pas | 2 +- compiler/defcmp.pas | 12 +- compiler/defutil.pas | 22 + compiler/htypechk.pas | 14 +- compiler/nadd.pas | 25 +- compiler/ncal.pas | 3 +- compiler/ncgcnv.pas | 18 +- compiler/ncgcon.pas | 15 +- compiler/ncginl.pas | 2 +- compiler/ncgld.pas | 2 +- compiler/ncgmem.pas | 5 +- compiler/ncgrtti.pas | 9 +- compiler/ncnv.pas | 17 +- compiler/ncon.pas | 23 +- compiler/ninl.pas | 8 +- compiler/nmem.pas | 5 +- compiler/nutils.pas | 14 +- compiler/options.pas | 5 +- compiler/pdecl.pas | 2 +- compiler/pinline.pas | 3 + compiler/ppu.pas | 2 +- compiler/psystem.pas | 6 +- compiler/ptconst.pas | 4 +- compiler/scanner.pas | 2 +- compiler/symconst.pas | 4 +- compiler/widestr.pas | 3 +- packages/iconvenc/src/iconvenc.pas | 167 +- rtl/inc/compproc.inc | 210 ++- rtl/inc/rtti.inc | 32 +- rtl/inc/system.inc | 10 +- rtl/inc/systemh.inc | 17 +- rtl/inc/text.inc | 28 +- rtl/inc/ustringh.inc | 119 ++ rtl/inc/ustrings.inc | 2325 ++++++++++++++++++++++++++++ rtl/inc/variant.inc | 72 +- rtl/inc/varianth.inc | 18 + rtl/inc/wstring22h.inc | 108 ++ rtl/inc/wstringh.inc | 57 +- rtl/inc/wstrings.inc | 1518 +++++++++++++++++- rtl/inc/wustring22.inc | 2021 ++++++++++++++++++++++++ rtl/inc/wustrings.inc | 1986 ------------------------ rtl/linux/buildrtl.lpi | 64 + rtl/linux/buildrtl.pp | 20 + rtl/linux/system.pp | 4 + rtl/objpas/classes/classes.inc | 29 +- rtl/objpas/classes/classesh.inc | 10 +- rtl/objpas/classes/reader.inc | 105 +- rtl/objpas/classes/writer.inc | 44 + rtl/objpas/sysutils/sysformt.inc | 4 + rtl/objpas/typinfo.pp | 94 +- rtl/unix/cwstring.pp | 12 +- rtl/win32/buildrtl.lpi | 1 + rtl/win32/system.pp | 65 +- tests/test/trtti1.pp | 2 +- tests/test/tstring10.pp | 27 + tests/test/tunistr1.pp | 19 + tests/test/tunistr2.pp | 21 + tests/test/tunistr4.pp | 92 ++ tests/test/tunistr5.pp | 45 + tests/test/tunistr6.pp | 397 +++++ tests/test/tunistr7.pp | 47 + 69 files changed, 8007 insertions(+), 2302 deletions(-) create mode 100644 compiler/ccharset.pas create mode 100644 rtl/inc/ustringh.inc create mode 100644 rtl/inc/ustrings.inc create mode 100644 rtl/inc/wstring22h.inc create mode 100644 rtl/inc/wustring22.inc create mode 100644 rtl/linux/buildrtl.lpi create mode 100644 rtl/linux/buildrtl.pp create mode 100644 tests/test/tstring10.pp create mode 100644 tests/test/tunistr1.pp create mode 100644 tests/test/tunistr2.pp create mode 100644 tests/test/tunistr4.pp create mode 100644 tests/test/tunistr5.pp create mode 100644 tests/test/tunistr6.pp create mode 100644 tests/test/tunistr7.pp diff --git a/.gitattributes b/.gitattributes index da45c11009..9bacf83d65 100644 --- a/.gitattributes +++ b/.gitattributes @@ -106,6 +106,7 @@ compiler/avr/rgcpu.pas svneol=native#text/plain compiler/browcol.pas svneol=native#text/plain compiler/bsdcompile -text compiler/catch.pas svneol=native#text/plain +compiler/ccharset.pas svneol=native#text/plain compiler/cclasses.pas svneol=native#text/plain compiler/cfidwarf.pas svneol=native#text/plain compiler/cfileutl.pas svneol=native#text/plain @@ -5383,14 +5384,18 @@ rtl/inc/threadvr.inc svneol=native#text/plain rtl/inc/typefile.inc svneol=native#text/plain rtl/inc/ucomplex.pp svneol=native#text/plain rtl/inc/ufloat128.pp svneol=native#text/plain +rtl/inc/ustringh.inc svneol=native#text/plain +rtl/inc/ustrings.inc svneol=native#text/plain rtl/inc/varerror.inc svneol=native#text/plain rtl/inc/variant.inc svneol=native#text/plain rtl/inc/varianth.inc svneol=native#text/plain rtl/inc/variants.pp svneol=native#text/plain rtl/inc/video.inc svneol=native#text/plain rtl/inc/videoh.inc svneol=native#text/plain +rtl/inc/wstring22h.inc svneol=native#text/plain rtl/inc/wstringh.inc svneol=native#text/plain rtl/inc/wstrings.inc -text +rtl/inc/wustring22.inc svneol=native#text/plain rtl/inc/wustrings.inc svneol=native#text/plain rtl/linux/Makefile svneol=native#text/plain rtl/linux/Makefile.fpc svneol=native#text/plain @@ -5406,6 +5411,8 @@ rtl/linux/arm/syscall.inc svneol=native#text/plain rtl/linux/arm/syscallh.inc svneol=native#text/plain rtl/linux/arm/sysnr.inc svneol=native#text/plain rtl/linux/arm/ucprt0.as svneol=native#text/plain +rtl/linux/buildrtl.lpi svneol=native#text/plain +rtl/linux/buildrtl.pp svneol=native#text/plain rtl/linux/bunxsysc.inc svneol=native#text/plain rtl/linux/errno.inc svneol=native#text/plain rtl/linux/errnostr.inc -text @@ -7820,6 +7827,7 @@ tests/test/tsetsize.pp svneol=native#text/plain tests/test/tstack.pp svneol=native#text/plain tests/test/tstprocv.pp svneol=native#text/plain tests/test/tstring1.pp svneol=native#text/plain +tests/test/tstring10.pp svneol=native#text/plain tests/test/tstring2.pp svneol=native#text/plain tests/test/tstring3.pp svneol=native#text/plain tests/test/tstring4.pp svneol=native#text/plain @@ -7833,6 +7841,12 @@ tests/test/tstrreal2.pp svneol=native#text/plain tests/test/tstrreal3.pp -text tests/test/tsubdecl.pp svneol=native#text/plain tests/test/tunaligned1.pp svneol=native#text/plain +tests/test/tunistr1.pp svneol=native#text/plain +tests/test/tunistr2.pp svneol=native#text/plain +tests/test/tunistr4.pp svneol=native#text/plain +tests/test/tunistr5.pp svneol=native#text/plain +tests/test/tunistr6.pp svneol=native#text/plain +tests/test/tunistr7.pp svneol=native#text/plain tests/test/tunit1.pp svneol=native#text/plain tests/test/tunit2.pp svneol=native#text/plain tests/test/tunit3.pp svneol=native#text/plain diff --git a/compiler/ccharset.pas b/compiler/ccharset.pas new file mode 100644 index 0000000000..258a0359d2 --- /dev/null +++ b/compiler/ccharset.pas @@ -0,0 +1,254 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 2000 by Florian Klaempfl + member of the Free Pascal development team. + + This unit implements several classes for charset conversions + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +{ this unit is included temporarily for 2.2 bootstrapping and can be + removed after the next release after 2.2.2 } +{$mode objfpc} +unit ccharset; + + interface + + type + tunicodechar = word; + tunicodestring = ^tunicodechar; + + tcsconvert = class + // !!!!!!1constructor create; + end; + + tunicodecharmappingflag = (umf_noinfo,umf_leadbyte,umf_undefined, + umf_unused); + + punicodecharmapping = ^tunicodecharmapping; + tunicodecharmapping = record + unicode : tunicodechar; + flag : tunicodecharmappingflag; + reserved : byte; + end; + + punicodemap = ^tunicodemap; + tunicodemap = record + cpname : string[20]; + map : punicodecharmapping; + lastchar : longint; + next : punicodemap; + internalmap : boolean; + end; + + tcp2unicode = class(tcsconvert) + end; + + function loadunicodemapping(const cpname,f : string) : punicodemap; + procedure registermapping(p : punicodemap); + function getmap(const s : string) : punicodemap; + function mappingavailable(const s : string) : boolean; + function getunicode(c : char;p : punicodemap) : tunicodechar; + function getascii(c : tunicodechar;p : punicodemap) : string; + + implementation + + var + mappings : punicodemap; + + function loadunicodemapping(const cpname,f : string) : punicodemap; + + var + data : punicodecharmapping; + datasize : longint; + t : text; + s,hs : string; + scanpos,charpos,unicodevalue : longint; + code : word; + flag : tunicodecharmappingflag; + p : punicodemap; + lastchar : longint; + + begin + lastchar:=-1; + loadunicodemapping:=nil; + datasize:=256; + getmem(data,sizeof(tunicodecharmapping)*datasize); + assign(t,f); + {$I-} + reset(t); + {$I+} + if ioresult<>0 then + begin + freemem(data,sizeof(tunicodecharmapping)*datasize); + exit; + end; + while not(eof(t)) do + begin + readln(t,s); + if (s[1]='0') and (s[2]='x') then + begin + flag:=umf_unused; + scanpos:=3; + hs:='$'; + while s[scanpos] in ['0'..'9','A'..'F','a'..'f'] do + begin + hs:=hs+s[scanpos]; + inc(scanpos); + end; + val(hs,charpos,code); + if code<>0 then + begin + freemem(data,sizeof(tunicodecharmapping)*datasize); + close(t); + exit; + end; + while not(s[scanpos] in ['0','#']) do + inc(scanpos); + if s[scanpos]='#' then + begin + { special char } + unicodevalue:=$ffff; + hs:=copy(s,scanpos,length(s)-scanpos+1); + if hs='#DBCS LEAD BYTE' then + flag:=umf_leadbyte; + end + else + begin + { C hex prefix } + inc(scanpos,2); + hs:='$'; + while s[scanpos] in ['0'..'9','A'..'F','a'..'f'] do + begin + hs:=hs+s[scanpos]; + inc(scanpos); + end; + val(hs,unicodevalue,code); + if code<>0 then + begin + freemem(data,sizeof(tunicodecharmapping)*datasize); + close(t); + exit; + end; + if charpos>datasize then + begin + { allocate 1024 bytes more because } + { if we need more than 256 entries it's } + { probably a mbcs with a lot of } + { entries } + datasize:=charpos+1024; + reallocmem(data,sizeof(tunicodecharmapping)*datasize); + end; + flag:=umf_noinfo; + end; + data[charpos].flag:=flag; + data[charpos].unicode:=unicodevalue; + if charpos>lastchar then + lastchar:=charpos; + end; + end; + close(t); + new(p); + p^.lastchar:=lastchar; + p^.cpname:=cpname; + p^.internalmap:=false; + p^.next:=nil; + p^.map:=data; + loadunicodemapping:=p; + end; + + procedure registermapping(p : punicodemap); + + begin + p^.next:=mappings; + mappings:=p; + end; + + function getmap(const s : string) : punicodemap; + + var + hp : punicodemap; + + const + mapcache : string = ''; + mapcachep : punicodemap = nil; + + begin + if (mapcache=s) and assigned(mapcachep) and (mapcachep^.cpname=s) then + begin + getmap:=mapcachep; + exit; + end; + hp:=mappings; + while assigned(hp) do + begin + if hp^.cpname=s then + begin + getmap:=hp; + mapcache:=s; + mapcachep:=hp; + exit; + end; + hp:=hp^.next; + end; + getmap:=nil; + end; + + function mappingavailable(const s : string) : boolean; + + begin + mappingavailable:=getmap(s)<>nil; + end; + + function getunicode(c : char;p : punicodemap) : tunicodechar; + + begin + if ord(c)<=p^.lastchar then + getunicode:=p^.map[ord(c)].unicode + else + getunicode:=0; + end; + + function getascii(c : tunicodechar;p : punicodemap) : string; + + var + i : longint; + + begin + { at least map to space } + getascii:=#32; + for i:=0 to p^.lastchar do + if p^.map[i].unicode=c then + begin + if i<256 then + getascii:=chr(i) + else + getascii:=chr(i div 256)+chr(i mod 256); + exit; + end; + end; + + var + hp : punicodemap; + +initialization + mappings:=nil; +finalization + while assigned(mappings) do + begin + hp:=mappings^.next; + if not(mappings^.internalmap) then + begin + freemem(mappings^.map); + dispose(mappings); + end; + mappings:=hp; + end; +end. diff --git a/compiler/cgobj.pas b/compiler/cgobj.pas index 7bea0c7996..e9be0183ce 100644 --- a/compiler/cgobj.pas +++ b/compiler/cgobj.pas @@ -3112,13 +3112,15 @@ implementation paramanager.getintparaloc(pocall_default,1,cgpara1); paramanager.getintparaloc(pocall_default,2,cgpara2); if is_interfacecom(t) then - incrfunc:='FPC_INTF_INCR_REF' + incrfunc:='FPC_INTF_INCR_REF' else if is_ansistring(t) then - incrfunc:='FPC_ANSISTR_INCR_REF' + incrfunc:='FPC_ANSISTR_INCR_REF' else if is_widestring(t) then - incrfunc:='FPC_WIDESTR_INCR_REF' + incrfunc:='FPC_WIDESTR_INCR_REF' + else if is_unicodestring(t) then + incrfunc:='FPC_UNICODESTR_INCR_REF' else if is_dynamic_array(t) then - incrfunc:='FPC_DYNARRAY_INCR_REF' + incrfunc:='FPC_DYNARRAY_INCR_REF' else incrfunc:=''; { call the special incr function or the generic addref } @@ -3174,6 +3176,8 @@ implementation decrfunc:='FPC_ANSISTR_DECR_REF' else if is_widestring(t) then decrfunc:='FPC_WIDESTR_DECR_REF' + else if is_unicodestring(t) then + decrfunc:='FPC_UNICODESTR_DECR_REF' else if is_dynamic_array(t) then begin decrfunc:='FPC_DYNARRAY_DECR_REF'; @@ -3234,6 +3238,7 @@ implementation paramanager.getintparaloc(pocall_default,2,cgpara2); if is_ansistring(t) or is_widestring(t) or + is_unicodestring(t) or is_interfacecom(t) or is_dynamic_array(t) then a_load_const_ref(list,OS_ADDR,0,ref) @@ -3266,6 +3271,7 @@ implementation paramanager.getintparaloc(pocall_default,2,cgpara2); if is_ansistring(t) or is_widestring(t) or + is_unicodestring(t) or is_interfacecom(t) then begin g_decrrefcount(list,t,ref); diff --git a/compiler/cp1251.pas b/compiler/cp1251.pas index a2534fb531..b5f99074ea 100644 --- a/compiler/cp1251.pas +++ b/compiler/cp1251.pas @@ -6,7 +6,7 @@ unit cp1251; implementation uses - charset; + {$ifdef VER2_2}ccharset{$else VER2_2}charset{$endif VER2_2}; const map : array[0..255] of tunicodecharmapping = ( diff --git a/compiler/cp437.pas b/compiler/cp437.pas index a8ca25d3d3..144c854fcd 100644 --- a/compiler/cp437.pas +++ b/compiler/cp437.pas @@ -6,7 +6,7 @@ unit cp437; implementation uses - charset; + {$ifdef VER2_2}ccharset{$else VER2_2}charset{$endif VER2_2}; const map : array[0..255] of tunicodecharmapping = ( diff --git a/compiler/cp850.pas b/compiler/cp850.pas index 0a47f68268..51b3a3d1c8 100644 --- a/compiler/cp850.pas +++ b/compiler/cp850.pas @@ -6,7 +6,7 @@ unit cp850; implementation uses - charset; + {$ifdef VER2_2}ccharset{$else VER2_2}charset{$endif VER2_2}; const map : array[0..255] of tunicodecharmapping = ( diff --git a/compiler/cp866.pas b/compiler/cp866.pas index 435528b133..1279ae51a1 100644 --- a/compiler/cp866.pas +++ b/compiler/cp866.pas @@ -6,7 +6,7 @@ unit cp866; implementation uses - charset; + {$ifdef VER2_2}ccharset{$else VER2_2}charset{$endif VER2_2}; const map : array[0..255] of tunicodecharmapping = ( diff --git a/compiler/cp8859_1.pas b/compiler/cp8859_1.pas index 5b01d1664b..ae36fe3c18 100644 --- a/compiler/cp8859_1.pas +++ b/compiler/cp8859_1.pas @@ -6,7 +6,7 @@ unit cp8859_1; implementation uses - charset; + {$ifdef VER2_2}ccharset{$else VER2_2}charset{$endif VER2_2}; const map : array[0..255] of tunicodecharmapping = ( diff --git a/compiler/cp8859_5.pas b/compiler/cp8859_5.pas index e859ff0963..cc8f0c27f7 100644 --- a/compiler/cp8859_5.pas +++ b/compiler/cp8859_5.pas @@ -6,7 +6,7 @@ unit cp8859_5; implementation uses - charset; + {$ifdef VER2_2}ccharset{$else VER2_2}charset{$endif VER2_2}; const map : array[0..255] of tunicodecharmapping = ( diff --git a/compiler/defcmp.pas b/compiler/defcmp.pas index 459aa68c5d..4518192aa9 100644 --- a/compiler/defcmp.pas +++ b/compiler/defcmp.pas @@ -413,7 +413,7 @@ implementation else if (cs_ansistrings in current_settings.localswitches) and (tstringdef(def_to).stringtype=st_ansistring) then eq:=te_equal - else if tstringdef(def_to).stringtype=st_widestring then + else if tstringdef(def_to).stringtype in [st_widestring,st_unicodestring] then eq:=te_convert_l3 else eq:=te_convert_l1; @@ -425,7 +425,7 @@ implementation begin if is_ansistring(def_to) then eq:=te_convert_l1 - else if is_widestring(def_to) then + else if is_widestring(def_to) or is_unicodestring(def_to) then eq:=te_convert_l3 else eq:=te_convert_l2; @@ -446,7 +446,7 @@ implementation else eq:=te_convert_l2; end - else if is_widestring(def_to) then + else if is_widestring(def_to) or is_unicodestring(def_to) then eq:=te_convert_l3 else eq:=te_convert_l2; @@ -458,7 +458,7 @@ implementation if is_widechararray(def_from) or is_open_widechararray(def_from) then begin doconv:=tc_chararray_2_string; - if is_widestring(def_to) then + if is_widestring(def_to) or is_unicodestring(def_to) then eq:=te_convert_l1 else { size of widechar array is double due the sizeof a widechar } @@ -490,7 +490,7 @@ implementation else if is_pwidechar(def_from) then begin doconv:=tc_pwchar_2_string; - if is_widestring(def_to) then + if is_widestring(def_to) or is_unicodestring(def_to) then eq:=te_convert_l1 else eq:=te_convert_l3; @@ -909,7 +909,7 @@ implementation else { pwidechar(widestring) } if is_pwidechar(def_to) and - is_widestring(def_from) then + is_wide_or_unicode_string(def_from) then begin doconv:=tc_ansistring_2_pchar; eq:=te_convert_l1; diff --git a/compiler/defutil.pas b/compiler/defutil.pas index 0469d910b0..98c9fc11dc 100644 --- a/compiler/defutil.pas +++ b/compiler/defutil.pas @@ -165,6 +165,12 @@ interface {# returns true if p is a wide string type } function is_widestring(p : tdef) : boolean; + {# true if p is an unicode string def } + function is_unicodestring(p : tdef) : boolean; + + {# returns true if p is a wide or unicode string type } + function is_wide_or_unicode_string(p : tdef) : boolean; + {# Returns true if p is a short string type } function is_shortstring(p : tdef) : boolean; @@ -577,6 +583,22 @@ implementation end; + { true if p is an wide string def } + function is_wide_or_unicode_string(p : tdef) : boolean; + begin + is_wide_or_unicode_string:=(p.typ=stringdef) and + (tstringdef(p).stringtype in [st_widestring,st_unicodestring]); + end; + + + { true if p is an unicode string def } + function is_unicodestring(p : tdef) : boolean; + begin + is_unicodestring:=(p.typ=stringdef) and + (tstringdef(p).stringtype=st_unicodestring); + end; + + { true if p is an short string def } function is_shortstring(p : tdef) : boolean; begin diff --git a/compiler/htypechk.pas b/compiler/htypechk.pas index b7e548742f..5eec724079 100644 --- a/compiler/htypechk.pas +++ b/compiler/htypechk.pas @@ -1541,7 +1541,7 @@ implementation ) or ( is_widechar(p.resultdef) and - is_widestring(def_to) + (is_widestring(def_to) or is_unicodestring(def_to)) ) then eq:=te_equal end; @@ -2238,7 +2238,7 @@ implementation (tve_single,tve_dblcurrency,tve_extended, tve_dblcurrency,tve_dblcurrency,tve_extended); variantstringdef_cl: array[tstringtype] of tvariantequaltype = - (tve_sstring,tve_astring,tve_astring,tve_wstring,tve_unicodestring); + (tve_sstring,tve_astring,tve_astring,tve_wstring,tve_ustring); begin case def.typ of orddef: @@ -2437,9 +2437,9 @@ implementation else if (currvcl=tve_boolformal) or (bestvcl=tve_boolformal) then if (currvcl=tve_boolformal) then - result:=ord(bestvcl in [tve_chari64,tve_sstring,tve_astring,tve_wstring]) + result:=ord(bestvcl in [tve_chari64,tve_sstring,tve_astring,tve_wstring,tve_ustring]) else - result:=-ord(currvcl in [tve_chari64,tve_sstring,tve_astring,tve_wstring]) + result:=-ord(currvcl in [tve_chari64,tve_sstring,tve_astring,tve_wstring,tve_ustring]) { byte is better than everything else (we assume both aren't byte, } { since there's only one parameter and that one can't be the same) } else if (currvcl=tve_byte) or @@ -2497,7 +2497,11 @@ implementation { widestring is better than everything left } else if (currvcl=tve_wstring) or (bestvcl=tve_wstring) then - result:=1-2*ord(bestvcl=tve_wstring); + result:=1-2*ord(bestvcl=tve_wstring) + { unicodestring is better than everything left } + else if (currvcl=tve_ustring) or + (bestvcl=tve_ustring) then + result:=1-2*ord(bestvcl=tve_ustring); { all possibilities should have been checked now } if (result=-5) then diff --git a/compiler/nadd.pas b/compiler/nadd.pas index 79efa1e6b2..a7a3ad30f3 100644 --- a/compiler/nadd.pas +++ b/compiler/nadd.pas @@ -546,11 +546,11 @@ implementation { stringconstn only } { widechars are converted above to widestrings too } - { this isn't veryy efficient, but I don't think } + { this isn't ver y efficient, but I don't think } { that it does matter that much (FK) } if (lt=stringconstn) and (rt=stringconstn) and - (tstringconstnode(left).cst_type=cst_widestring) and - (tstringconstnode(right).cst_type=cst_widestring) then + (tstringconstnode(left).cst_type in [cst_widestring,cst_unicodestring]) and + (tstringconstnode(right).cst_type in [cst_widestring,cst_unicodestring]) then begin initwidestring(ws1); initwidestring(ws2); @@ -835,6 +835,8 @@ implementation if is_constnode(right) and is_constnode(left) and (is_widestring(right.resultdef) or is_widestring(left.resultdef) or + is_unicodestring(right.resultdef) or + is_unicodestring(left.resultdef) or is_widechar(right.resultdef) or is_widechar(left.resultdef)) then begin @@ -1419,8 +1421,13 @@ implementation begin if (nodetype in [addn,equaln,unequaln,lten,gten,ltn,gtn]) then begin + { Is there a unicodestring? } + if is_unicodestring(rd) or is_unicodestring(ld) then + strtype:= st_unicodestring + else { Is there a widestring? } if is_widestring(rd) or is_widestring(ld) or + is_unicodestring(rd) or is_unicodestring(ld) or is_pwidechar(rd) or is_widechararray(rd) or is_widechar(rd) or is_open_widechararray(rd) or is_pwidechar(ld) or is_widechararray(ld) or is_widechar(ld) or is_open_widechararray(ld) then strtype:= st_widestring @@ -1456,6 +1463,13 @@ implementation if not(is_widestring(ld)) then inserttypeconv(left,cwidestringtype); end; + st_unicodestring : + begin + if not(is_unicodestring(rd)) then + inserttypeconv(right,cunicodestringtype); + if not(is_unicodestring(ld)) then + inserttypeconv(left,cunicodestringtype); + end; st_ansistring : begin if not(is_ansistring(rd)) then @@ -2520,6 +2534,11 @@ implementation { this is only for add, the comparisaion is handled later } expectloc:=LOC_REGISTER; end + else if is_unicodestring(ld) then + begin + { this is only for add, the comparisaion is handled later } + expectloc:=LOC_REGISTER; + end else if is_ansistring(ld) then begin { this is only for add, the comparisaion is handled later } diff --git a/compiler/ncal.pas b/compiler/ncal.pas index ff9dae62cc..419783cc80 100644 --- a/compiler/ncal.pas +++ b/compiler/ncal.pas @@ -2772,7 +2772,8 @@ implementation else { ansi/widestrings must be registered, so we can dispose them } if is_ansistring(resultdef) or - is_widestring(resultdef) then + is_widestring(resultdef) or + is_unicodestring(resultdef) then begin expectloc:=LOC_REFERENCE; end diff --git a/compiler/ncgcnv.pas b/compiler/ncgcnv.pas index 734667c020..6649e927ae 100644 --- a/compiler/ncgcnv.pas +++ b/compiler/ncgcnv.pas @@ -148,6 +148,8 @@ interface location.register:=cg.getaddressregister(current_asmdata.CurrAsmList); cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.location.reference,location.register); end; + cst_widestring, + cst_unicodestring, cst_ansistring : begin if tstringconstnode(left).len=0 then @@ -167,20 +169,8 @@ interface {!!!!!!!} internalerror(8888); end; - cst_widestring: - begin - if tstringconstnode(left).len=0 then - begin - reference_reset(hr); - hr.symbol:=current_asmdata.RefAsmSymbol('FPC_EMPTYCHAR'); - location.register:=cg.getaddressregister(current_asmdata.CurrAsmList); - cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,hr,location.register); - end - else - begin - location_copy(location,left.location); - end; - end; + else + internalerror(200808241); end; end; diff --git a/compiler/ncgcon.pas b/compiler/ncgcon.pas index 9e9254be0e..11bc914709 100644 --- a/compiler/ncgcon.pas +++ b/compiler/ncgcon.pas @@ -270,7 +270,7 @@ implementation pooltype: TConstPoolType; pool: THashSet; entry: PHashSetItem; - + const PoolMap: array[tconststringtype] of TConstPoolType = ( sp_conststr, @@ -282,7 +282,7 @@ implementation ); begin { for empty ansistrings we could return a constant 0 } - if (cst_type in [cst_ansistring,cst_widestring]) and (len=0) then + if (cst_type in [cst_ansistring,cst_widestring,cst_unicodestring]) and (len=0) then begin location_reset(location,LOC_CONSTANT,OS_ADDR); location.value:=0; @@ -295,7 +295,7 @@ implementation if current_asmdata.ConstPools[pooltype] = nil then current_asmdata.ConstPools[pooltype] := THashSet.Create(64, True, False); pool := current_asmdata.ConstPools[pooltype]; - + if cst_type in [cst_widestring, cst_unicodestring] then entry := pool.FindOrAdd(pcompilerwidestring(value_str)^.data, len*cwidechartype.size) else @@ -311,7 +311,7 @@ implementation entry^.Data := lastlabel; maybe_new_object_file(current_asmdata.asmlists[al_typedconsts]); if (len=0) or - not(cst_type in [cst_ansistring,cst_widestring]) then + not(cst_type in [cst_ansistring,cst_widestring,cst_unicodestring]) then new_section(current_asmdata.asmlists[al_typedconsts],sec_rodata_norel,lastlabel.name,const_align(sizeof(pint))) else new_section(current_asmdata.asmlists[al_typedconsts],sec_rodata,lastlabel.name,const_align(sizeof(pint))); @@ -321,7 +321,7 @@ implementation begin if len=0 then InternalError(2008032301) { empty string should be handled above } - else + else begin current_asmdata.getdatalabel(l1); current_asmdata.asmlists[al_typedconsts].concat(Tai_label.Create(l1)); @@ -342,6 +342,7 @@ implementation current_asmdata.asmlists[al_typedconsts].concat(Tai_string.Create_pchar(pc,len+1)); end; end; + cst_unicodestring, cst_widestring: begin if len=0 then @@ -353,7 +354,7 @@ implementation { we use always UTF-16 coding for constants } { at least for now } { Consts.concat(Tai_const.Create_8bit(2)); } - if tf_winlikewidestring in target_info.flags then + if (cst_type=cst_widestring) and (tf_winlikewidestring in target_info.flags) then current_asmdata.asmlists[al_typedconsts].concat(Tai_const.Create_32bit(len*cwidechartype.size)) else begin @@ -401,7 +402,7 @@ implementation end; end; end; - if cst_type in [cst_ansistring, cst_widestring] then + if cst_type in [cst_ansistring, cst_widestring, cst_unicodestring] then begin location_reset(location, LOC_REGISTER, OS_ADDR); reference_reset_symbol(href, lab_str, 0); diff --git a/compiler/ncginl.pas b/compiler/ncginl.pas index 322fe09875..7508c22cf5 100644 --- a/compiler/ncginl.pas +++ b/compiler/ncginl.pas @@ -358,7 +358,7 @@ implementation hregister:=cg.makeregsize(current_asmdata.CurrAsmList,left.location.register,OS_INT); cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,href,hregister); end; - if is_widestring(left.resultdef) then + if is_widestring(left.resultdef) or is_unicodestring(left.resultdef) then cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SHR,OS_INT,1,hregister); cg.a_label(current_asmdata.CurrAsmList,lengthlab); location_reset(location,LOC_REGISTER,def_cgsize(resultdef)); diff --git a/compiler/ncgld.pas b/compiler/ncgld.pas index 988ad244c5..3d8066f316 100644 --- a/compiler/ncgld.pas +++ b/compiler/ncgld.pas @@ -1073,7 +1073,7 @@ implementation freetemp:=false; end else - if is_widestring(lt) then + if is_widestring(lt) or is_unicodestring(lt) then begin vtype:=vtWideString; freetemp:=false; diff --git a/compiler/ncgmem.pas b/compiler/ncgmem.pas index 77790e8030..e29b53987c 100644 --- a/compiler/ncgmem.pas +++ b/compiler/ncgmem.pas @@ -642,7 +642,8 @@ implementation { an ansistring needs to be dereferenced } if is_ansistring(left.resultdef) or - is_widestring(left.resultdef) then + is_widestring(left.resultdef) or + is_unicodestring(left.resultdef) then begin if nf_callunique in flags then internalerror(200304236); @@ -763,6 +764,7 @@ implementation begin case tstringdef(left.resultdef).stringtype of { it's the same for ansi- and wide strings } + st_unicodestring, st_widestring, st_ansistring: begin @@ -926,6 +928,7 @@ implementation begin case tstringdef(left.resultdef).stringtype of { it's the same for ansi- and wide strings } + st_unicodestring, st_widestring, st_ansistring: begin diff --git a/compiler/ncgrtti.pas b/compiler/ncgrtti.pas index f900ab57d4..fcac8726b1 100644 --- a/compiler/ncgrtti.pas +++ b/compiler/ncgrtti.pas @@ -372,6 +372,11 @@ implementation current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(tkWString)); write_rtti_name(def); end; + st_unicodestring: + begin + current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(tkUString)); + write_rtti_name(def); + end; st_longstring: begin current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(tkLString)); @@ -976,7 +981,7 @@ implementation current_asmdata.asmlists[al_rtti].concat(cai_align.Create(4)); asmlists[al_rtti].concat(Tai_const.create_32bit(syms[i].value)); if (tf_requires_proper_alignment in target_info.flags) then - current_asmdata.asmlists[al_rtti].concat(cai_align.Create(sizeof(TConstPtrUInt))); + current_asmdata.asmlists[al_rtti].concat(cai_align.Create(sizeof(TConstPtrUInt))); asmlists[al_rtti].concat(Tai_const.create_sym_offset(mainrtti,st+offsets[i])); end; end; @@ -1069,7 +1074,7 @@ implementation current_asmdata.asmlists[al_rtti].concat(cai_align.Create(4)); asmlists[al_rtti].concat(Tai_const.create_32bit(syms[i].value)); if (tf_requires_proper_alignment in target_info.flags) then - current_asmdata.asmlists[al_rtti].concat(cai_align.Create(sizeof(TConstPtrUInt))); + current_asmdata.asmlists[al_rtti].concat(cai_align.Create(sizeof(TConstPtrUInt))); asmlists[al_rtti].concat(Tai_const.create_sym_offset(mainrtti,st+offsets[i])); end; asmlists[al_rtti].concat(Tai_symbol_end.create(rttilab)); diff --git a/compiler/ncnv.pas b/compiler/ncnv.pas index 3a59f3e46c..fbf0814412 100644 --- a/compiler/ncnv.pas +++ b/compiler/ncnv.pas @@ -917,12 +917,12 @@ implementation { we can't do widechar to ansichar conversions at compile time, since } { this maps all non-ascii chars to '?' -> loses information } if (left.nodetype=ordconstn) and - ((tstringdef(resultdef).stringtype=st_widestring) or + ((tstringdef(resultdef).stringtype in [st_widestring,st_unicodestring]) or (torddef(left.resultdef).ordtype=uchar) or { >=128 is destroyed } (tordconstnode(left).value.uvalue<128)) then begin - if tstringdef(resultdef).stringtype=st_widestring then + if tstringdef(resultdef).stringtype in [st_widestring,st_unicodestring] then begin initwidestring(ws); if torddef(left.resultdef).ordtype=uwidechar then @@ -953,7 +953,7 @@ implementation if torddef(left.resultdef).ordtype<>uwidechar then procname := 'fpc_char_to_' else - procname := 'fpc_wchar_to_'; + procname := 'fpc_uchar_to_'; procname:=procname+tstringdef(resultdef).stringtypname; { and the parameter } @@ -1193,7 +1193,8 @@ implementation inserttypeconv(left,cwidestringtype) else if is_pchar(resultdef) and - is_widestring(left.resultdef) then + (is_widestring(left.resultdef) or + is_unicodestring(left.resultdef)) then begin inserttypeconv(left,cansistringtype); { the second pass of second_cstring_to_pchar expects a } @@ -2037,8 +2038,8 @@ implementation if (convtype=tc_string_2_string) and ( ((not is_widechararray(left.resultdef) and - not is_widestring(left.resultdef)) or - (tstringdef(resultdef).stringtype=st_widestring) or + not is_wide_or_unicode_string(left.resultdef)) or + (tstringdef(resultdef).stringtype in [st_widestring,st_unicodestring]) or { non-ascii chars would be replaced with '?' -> loses info } not hasnonasciichars(pcompilerwidestring(tstringconstnode(left).value_str))) ) then @@ -2530,10 +2531,10 @@ implementation begin if (torddef(resultdef).ordtype=uchar) and (torddef(left.resultdef).ordtype=uwidechar) then - fname := 'fpc_wchar_to_char' + fname := 'fpc_uchar_to_char' else if (torddef(resultdef).ordtype=uwidechar) and (torddef(left.resultdef).ordtype=uchar) then - fname := 'fpc_char_to_wchar' + fname := 'fpc_char_to_uchar' else internalerror(2007081201); diff --git a/compiler/ncon.pas b/compiler/ncon.pas index 3adab063cd..e08aa5b20b 100644 --- a/compiler/ncon.pas +++ b/compiler/ncon.pas @@ -866,7 +866,8 @@ implementation resultdef:=cshortstringtype; cst_ansistring : resultdef:=cansistringtype; - cst_unicodestring, + cst_unicodestring : + resultdef:=cunicodestringtype; cst_widestring : resultdef:=cwidestringtype; cst_longstring : @@ -877,11 +878,15 @@ implementation function tstringconstnode.pass_1 : tnode; begin result:=nil; - if (cst_type in [cst_ansistring,cst_widestring,cst_unicodestring]) and - (len=0) then - expectloc:=LOC_CONSTANT + if (cst_type in [cst_ansistring,cst_widestring,cst_unicodestring]) then + begin + if len=0 then + expectloc:=LOC_CONSTANT + else + expectloc:=LOC_REGISTER + end else - expectloc:=LOC_CREFERENCE; + expectloc:=LOC_CREFERENCE; end; @@ -920,8 +925,8 @@ implementation if def.typ<>stringdef then internalerror(200510011); { convert ascii 2 unicode } - if (tstringdef(def).stringtype=st_widestring) and - (cst_type<>cst_widestring) then + if (tstringdef(def).stringtype in [st_widestring,st_unicodestring]) and + not(cst_type in [cst_widestring,cst_unicodestring]) then begin initwidestring(pw); ascii2unicode(value_str,len,pw); @@ -930,8 +935,8 @@ implementation end else { convert unicode 2 ascii } - if (cst_type=cst_widestring) and - (tstringdef(def).stringtype<>st_widestring) then + if (cst_type in [cst_widestring,cst_unicodestring]) and + not(tstringdef(def).stringtype in [st_widestring,st_unicodestring]) then begin pw:=pcompilerwidestring(value_str); getmem(pc,getlengthwidestring(pw)+1); diff --git a/compiler/ninl.pas b/compiler/ninl.pas index 7d1ac96510..fcfbc21dde 100644 --- a/compiler/ninl.pas +++ b/compiler/ninl.pas @@ -1676,7 +1676,7 @@ implementation result:=cordconstnode.create(0,u8inttype,false); end else if not is_ansistring(left.resultdef) and - not is_widestring(left.resultdef) then + not is_wide_or_unicode_string(left.resultdef) then result:=cordconstnode.create(tstringdef(left.resultdef).len,u8inttype,true) end; end; @@ -2040,8 +2040,8 @@ implementation { length) } if (left.nodetype=typeconvn) and (ttypeconvnode(left).left.resultdef.typ=stringdef) and - not(is_widestring(left.resultdef) xor - is_widestring(ttypeconvnode(left).left.resultdef)) then + not(is_wide_or_unicode_string(left.resultdef) xor + is_wide_or_unicode_string(ttypeconvnode(left).left.resultdef)) then begin hp:=ttypeconvnode(left).left; ttypeconvnode(left).left:=nil; @@ -2334,7 +2334,7 @@ implementation result:=load_high_value_node(tparavarsym(tloadnode(left).symtableentry)) end else if is_ansistring(left.resultdef) or - is_widestring(left.resultdef) then + is_wide_or_unicode_string(left.resultdef) then CGMessage(type_e_mismatch) end; end; diff --git a/compiler/nmem.pas b/compiler/nmem.pas index 8adb48a128..9790c14a5d 100644 --- a/compiler/nmem.pas +++ b/compiler/nmem.pas @@ -667,7 +667,7 @@ implementation ansi/widestring needs to be valid } valid:=is_dynamic_array(left.resultdef) or is_ansistring(left.resultdef) or - is_widestring(left.resultdef) or + is_wide_or_unicode_string(left.resultdef) or { implicit pointer dereference -> pointer is read } (left.resultdef.typ = pointerdef); if valid then @@ -827,7 +827,8 @@ implementation if (nf_callunique in flags) and (is_ansistring(left.resultdef) or - (is_widestring(left.resultdef) and not(tf_winlikewidestring in target_info.flags))) then + is_unicodestring(left.resultdef) or + (is_widestring(left.resultdef) and not(tf_winlikewidestring in target_info.flags))) then begin left := ctypeconvnode.create_internal(ccallnode.createintern('fpc_'+tstringdef(left.resultdef).stringtypname+'_unique', ccallparanode.create( diff --git a/compiler/nutils.pas b/compiler/nutils.pas index 09b033a1a3..1fc9444d3b 100644 --- a/compiler/nutils.pas +++ b/compiler/nutils.pas @@ -531,7 +531,7 @@ implementation if not assigned(p.resultdef) then typecheckpass(p); if is_ansistring(p.resultdef) or - is_widestring(p.resultdef) or + is_wide_or_unicode_string(p.resultdef) or is_interfacecom(p.resultdef) or is_dynamic_array(p.resultdef) then begin @@ -584,6 +584,18 @@ implementation cnilnode.create )); end + else if is_unicodestring(p.resultdef) then + begin + result:=internalstatements(newstatement); + addstatement(newstatement,ccallnode.createintern('fpc_unicodestr_decr_ref', + ccallparanode.create( + ctypeconvnode.create_internal(p,voidpointertype), + nil))); + addstatement(newstatement,cassignmentnode.create( + ctypeconvnode.create_internal(p.getcopy,voidpointertype), + cnilnode.create + )); + end else if is_interfacecom(p.resultdef) then begin result:=internalstatements(newstatement); diff --git a/compiler/options.pas b/compiler/options.pas index 73771c8ba0..ae804c51cb 100644 --- a/compiler/options.pas +++ b/compiler/options.pas @@ -71,7 +71,7 @@ implementation uses widestr, - charset, + {$ifdef VER2_2}ccharset{$else VER2_2}charset{$endif VER2_2}, SysUtils, version, cutils,cmsgs, @@ -2580,6 +2580,9 @@ begin set_system_macro('FPC_PATCH',patch_nr); set_system_macro('FPC_FULLVERSION',Format('%d%.02d%.02d',[StrToInt(version_nr),StrToInt(release_nr),StrToInt(patch_nr)])); + if not(target_info.system in system_windows) then + def_system_macro('FPC_WIDESTRING_EQUAL_UNICODESTRING'); + for i:=low(tfeature) to high(tfeature) do if i in features then def_system_macro('FPC_HAS_FEATURE_'+featurestr[i]); diff --git a/compiler/pdecl.pas b/compiler/pdecl.pas index 7f6404b344..3dadd92479 100644 --- a/compiler/pdecl.pas +++ b/compiler/pdecl.pas @@ -96,7 +96,7 @@ implementation end; stringconstn: begin - if is_widestring(p.resultdef) then + if is_wide_or_unicode_string(p.resultdef) then begin initwidestring(pw); copywidestring(pcompilerwidestring(tstringconstnode(p).value_str),pw); diff --git a/compiler/pinline.pas b/compiler/pinline.pas index f91c02bc05..857184d752 100644 --- a/compiler/pinline.pas +++ b/compiler/pinline.pas @@ -720,6 +720,9 @@ implementation is_widechararray(paradef) or is_pwidechar(paradef) then copynode:=ccallnode.createintern('fpc_widestr_copy',paras) + else + if is_unicodestring(paradef) then + copynode:=ccallnode.createintern('fpc_unicodestr_copy',paras) else if is_char(paradef) then copynode:=ccallnode.createintern('fpc_char_copy',paras) diff --git a/compiler/ppu.pas b/compiler/ppu.pas index 0c9f6c320f..51b11ae05d 100644 --- a/compiler/ppu.pas +++ b/compiler/ppu.pas @@ -43,7 +43,7 @@ type {$endif Test_Double_checksum} const - CurrentPPUVersion = 91; + CurrentPPUVersion = 92; { buffer sizes } maxentrysize = 1024; diff --git a/compiler/psystem.pas b/compiler/psystem.pas index 8cb3d53427..b7f1f9b271 100644 --- a/compiler/psystem.pas +++ b/compiler/psystem.pas @@ -157,7 +157,10 @@ implementation { should we give a length to the default long and ansi string definition ?? } clongstringtype:=tstringdef.createlong(-1); cansistringtype:=tstringdef.createansi; - cwidestringtype:=tstringdef.createwide; + if target_info.system in system_windows then + cwidestringtype:=tstringdef.createwide + else + cwidestringtype:=tstringdef.createunicode; cunicodestringtype:=tstringdef.createunicode; { length=0 for shortstring is open string (needed for readln(string) } openshortstringtype:=tstringdef.createshort(0); @@ -265,6 +268,7 @@ implementation addtype('AnsiString',cansistringtype); addtype('WideString',cwidestringtype); addtype('UnicodeString',cunicodestringtype); + addtype('OpenString',openshortstringtype); addtype('Boolean',booltype); addtype('ByteBool',bool8type); diff --git a/compiler/ptconst.pas b/compiler/ptconst.pas index 4f9aa821f8..2106c5c0a2 100644 --- a/compiler/ptconst.pas +++ b/compiler/ptconst.pas @@ -431,7 +431,7 @@ implementation { convert to widestring stringconstn } inserttypeconv(p,cwidestringtype); if (p.nodetype=stringconstn) and - (tstringconstnode(p).cst_type=cst_widestring) then + (tstringconstnode(p).cst_type in [cst_widestring,cst_unicodestring]) then begin pw:=pcompilerwidestring(tstringconstnode(p).value_str); for i:=0 to tstringconstnode(p).len-1 do @@ -641,7 +641,7 @@ implementation begin n:=comp_expr(true); { load strval and strlength of the constant tree } - if (n.nodetype=stringconstn) or is_widestring(def) or is_constwidecharnode(n) then + if (n.nodetype=stringconstn) or is_wide_or_unicode_string(def) or is_constwidecharnode(n) then begin { convert to the expected string type so that for widestrings strval is a pcompilerwidestring } diff --git a/compiler/scanner.pas b/compiler/scanner.pas index 196e9efa8e..1285a448ed 100644 --- a/compiler/scanner.pas +++ b/compiler/scanner.pas @@ -962,7 +962,7 @@ In case not, the value returned can be arbitrary. else l:=tarraydef(hdef).highrange; stringdef: - if is_open_string(hdef) or is_ansistring(hdef) or is_widestring(hdef) then + if is_open_string(hdef) or is_ansistring(hdef) or is_wide_or_unicode_string(hdef) then Message(type_e_mismatch) else l:=tstringdef(hdef).len; diff --git a/compiler/symconst.pas b/compiler/symconst.pas index 5b1dca5cbb..12c1a911df 100644 --- a/compiler/symconst.pas +++ b/compiler/symconst.pas @@ -61,6 +61,8 @@ const tkDynArray = 21; tkInterfaceCorba = 22; tkProcVar = 23; + tkUString = 24; + tkUChar = 25; otSByte = 0; otUByte = 1; @@ -446,7 +448,7 @@ type tvariantequaltype = ( tve_incompatible, tve_chari64, - tve_unicodestring, + tve_ustring, tve_wstring, tve_astring, tve_sstring, diff --git a/compiler/widestr.pas b/compiler/widestr.pas index 1c0c0d634d..4747e655b6 100644 --- a/compiler/widestr.pas +++ b/compiler/widestr.pas @@ -28,8 +28,7 @@ unit widestr; interface uses - charset,globtype - ; + {$ifdef VER2_2}ccharset{$else VER2_2}charset{$endif VER2_2},globtype; type diff --git a/packages/iconvenc/src/iconvenc.pas b/packages/iconvenc/src/iconvenc.pas index c955398de5..11c144c85e 100755 --- a/packages/iconvenc/src/iconvenc.pas +++ b/packages/iconvenc/src/iconvenc.pas @@ -2,7 +2,7 @@ This file is part of the Free Pascal run time library. Copyright (c) 2000 by Marco van de Voort(marco@freepascal.org) member of the Free Pascal development team - + libiconv header translation + a helper routine http://wiki.freepascal.org/iconvenc @@ -15,7 +15,8 @@ } unit iconvenc; -interface + +interface {$mode objfpc}{$H+} {DEFINE LOADDYNAMIC} @@ -23,144 +24,150 @@ interface uses baseunix, {$ifdef LOADDYNAMIC} - dl, + dl, {$endif} initc; const - n=1; + n = 1; + type - Piconv_t = ^iconv_t; + piconv_t = ^iconv_t; iconv_t = pointer; - - Ticonv_open = function (__tocode:Pchar; __fromcode:Pchar):iconv_t;cdecl; - Ticonv = function (__cd:iconv_t; __inbuf:PPchar; __inbytesleft:Psize_t; __outbuf:PPchar; __outbytesleft:Psize_t):size_t;cdecl; - Ticonv_close = function (__cd:iconv_t):longint;cdecl; + + Ticonv_open = function(__tocode: pchar; __fromcode: pchar): iconv_t; cdecl; + Ticonv = function(__cd: iconv_t; __inbuf: ppchar; __inbytesleft: psize_t; __outbuf: ppchar; __outbytesleft: psize_t): size_t; cdecl; + Ticonv_close = function(__cd: iconv_t): cint; cdecl; {$IFNDEF LOADDYNAMIC} {$ifndef Linux} // and other OSes with iconv in libc. {$linklib iconv} {$endif} -function iconv_open (__tocode:Pchar; __fromcode:Pchar):iconv_t;cdecl; external; -function iconv (__cd:iconv_t; __inbuf:PPchar; __inbytesleft:Psize_t; __outbuf:PPchar; __outbytesleft:Psize_t):size_t;cdecl; external; -function iconv_close (__cd:iconv_t):longint;cdecl; external; +function iconv_open(__tocode: pchar; __fromcode: pchar): iconv_t; cdecl; external; +function iconv (__cd: iconv_t; __inbuf: ppchar; __inbytesleft: psize_t; __outbuf: ppchar; __outbytesleft: psize_t): size_t; cdecl; external; +function iconv_close (__cd: iconv_t): cint; cdecl; external; -var - IconvLibFound: Boolean = False; +var + IconvLibFound: boolean = False; {$ELSE} var - iconv_lib: Pointer; + iconv_lib: pointer; iconv_open: Ticonv_open; iconv: Ticonv; iconv_close: Ticonv_close; - IconvLibFound: Boolean = True; -function TryLoadLib(LibName:String;var error:string):Boolean; // can be used to load non standard libname + IconvLibFound: boolean = true; + +function TryLoadLib(LibName: string; var error: string): boolean; // can be used to load non standard libname {$endif} -function Iconvert(S:string;var res:string; FromEncoding, ToEncoding: string): cint; -function InitIconv (Var error:string): Boolean; +function Iconvert(s: string; var res: string; FromEncoding, ToEncoding: string): cint; +function InitIconv(var error: string): boolean; implementation {$IFDEF LOADDYNAMIC} -function TryLoadLib(LibName:String;var error:string):Boolean; -function resolvesymbol (var funcptr; symbol:string):boolean; +function TryLoadLib(LibName: string; var error: string): boolean; + function resolvesymbol (var funcptr; symbol: string): Boolean; + begin + pointer(funcptr) := pointer(dlsym(iconv_lib, pchar(symbol))); + result := assigned(pointer(funcptr)); + if not result then + error := error+#13#10+dlerror(); + end; + +var + res: boolean; begin - pointer(funcptr):=pointer(dlsym(iconv_lib, pchar(symbol))); - result:=assigned(pointer(funcptr)); - if not result then - error:=error+#13#10+dlerror(); -end; - -var res:boolean; - -begin - result:=false; - Error:=Error+#13#10'Trying '+LibName; - iconv_lib:=dlopen(pchar(libname), RTLD_NOW); + result := false; + Error := Error+#13#10'Trying '+LibName; + iconv_lib := dlopen(pchar(libname), RTLD_NOW); if Assigned(iconv_lib) then begin - result:=true; - result := result and resolvesymbol(pointer(iconv),'iconv'); - result := result and resolvesymbol(pointer(iconv_open),'iconv_open'); - result := result and resolvesymbol(pointer(iconv_close),'iconv_close'); + result := true; + result := result and resolvesymbol(pointer(iconv),'iconv'); + result := result and resolvesymbol(pointer(iconv_open),'iconv_open'); + result := result and resolvesymbol(pointer(iconv_close),'iconv_close'); // if not res then // dlclose(iconv_lib); - end - else - error:=error+#13#10+dlerror(); + end else + error:=error+#13#10+dlerror(); end; {$ENDIF} -function InitIconv(Var error:string): Boolean; +function InitIconv(var error: string): boolean; begin - result:=true; + result := true; {$ifdef LOADDYNAMIC} - error:=''; - if not TryLoadLib('libc.so.6',error) then - if not TryLoadLib('libiconv.so',error) then - result:=false; + error := ''; + if not TryLoadLib('libc.so.6', error) then + if not TryLoadLib('libiconv.so', error) then + result := false; {$endif} - iconvlibfound:=iconvlibfound or result; + iconvlibfound := iconvlibfound or result; end; -function Iconvert(S:string;var res:string; FromEncoding, ToEncoding: string): cint; +function Iconvert(S: string; var Res: string; FromEncoding, ToEncoding: string): cint; var InLen, OutLen, Offset: size_t; - Src, Dst: PChar; + Src, Dst: pchar; H: iconv_t; lerr: cint; - iconvres : cint; + iconvres: size_t; begin - H:=iconv_open(PChar(ToEncoding), PChar(FromEncoding)); + H := iconv_open(PChar(ToEncoding), PChar(FromEncoding)); if not assigned(H) then - begin - Res:=S; - Exit(-1); + begin + Res := S; + exit(-1); end; + try SetLength(Res, Length(S)); - InLen:=Length(S); - OutLen:=Length(Res); - Src:=PChar(S); - Dst:=PChar(Res); - while InLen>0 do + InLen := Length(S); + OutLen := Length(Res); + Src := PChar(S); + Dst := PChar(Res); + + while InLen > 0 do begin - iconvres:= iconv(H, @Src, @InLen, @Dst, @OutLen); - if iconvres=Cint(-1) then + iconvres := iconv(H, @Src, @InLen, @Dst, @OutLen); + if iconvres = size_t(-1) then begin - lerr:=cerrno; - if lerr=ESysEILSEQ then // unknown char, skip - begin - Dst^:=Src^; - Inc(Src); - Inc(Dst); - Dec(InLen); - Dec(OutLen); - end - else - if lerr=ESysE2BIG then + lerr := cerrno; + if lerr = ESysEILSEQ then // unknown char, skip + begin + Dst^ := Src^; + Inc(Src); + Inc(Dst); + Dec(InLen); + Dec(OutLen); + end + else + if lerr = ESysE2BIG then begin - Offset:=Dst-PChar(Res); + Offset := Dst - PChar(Res); SetLength(Res, Length(Res)+InLen*2+5); // 5 is minimally one utf-8 char - Dst:=PChar(Res)+Offset; - OutLen:=Length(Res)-Offset; + Dst := PChar(Res) + Offset; + OutLen := Length(Res) - Offset; end else exit(-1) end; end; + // iconv has a buffer that needs flushing, specially if the last char is not #0 - iconvres:=iconv(H, nil, nil, @Dst, @Outlen); - - SetLength(Res, Length(Res)-outlen); + iconv(H, nil, nil, @Dst, @Outlen); + + // trim output buffer + SetLength(Res, Length(Res) - Outlen); finally iconv_close(H); - end; - result:=0; + end; + + Result := 0; end; end. diff --git a/rtl/inc/compproc.inc b/rtl/inc/compproc.inc index 37ae529f33..b4f6b7d9fb 100644 --- a/rtl/inc/compproc.inc +++ b/rtl/inc/compproc.inc @@ -123,9 +123,16 @@ procedure fpc_AnsiStr_Currency(c : currency;len,fr : SizeInt;out s : ansistring) {$endif FPC_HAS_FEATURE_ANSISTRINGS} {$ifdef FPC_HAS_FEATURE_WIDESTRINGS} -procedure fpc_WideStr_sint(v : valsint; Len : SizeInt; out S : WideString); compilerproc; -procedure fpc_WideStr_uint(v : valuint;Len : SizeInt; out S : WideString); compilerproc; + {$if not(defined(FPC_WIDESTRING_EQUAL_UNICODESTRING)) or defined(VER2_2)} + procedure fpc_WideStr_sint(v : valsint; Len : SizeInt; out S : WideString); compilerproc; + procedure fpc_WideStr_uint(v : valuint;Len : SizeInt; out S : WideString); compilerproc; + {$endif not(defined(FPC_WIDESTRING_EQUAL_UNICODESTRING)) or defined(VER2_2)} + {$ifndef VER2_2} + procedure fpc_UnicodeStr_sint(v : valsint; Len : SizeInt; out S : UnicodeString); compilerproc; + procedure fpc_UnicodeStr_uint(v : valuint;Len : SizeInt; out S : UnicodeString); compilerproc; + {$endif VER2_2} {$endif FPC_HAS_FEATURE_WIDESTRINGS} + {$ifndef CPU64} procedure fpc_shortstr_qword(v : qword;len : SizeInt;out s : shortstring); compilerproc; procedure fpc_shortstr_int64(v : int64;len : SizeInt;out s : shortstring); compilerproc; @@ -137,17 +144,33 @@ procedure fpc_WideStr_uint(v : valuint;Len : SizeInt; out S : WideString); compi {$endif FPC_HAS_FEATURE_ANSISTRINGS} {$ifdef FPC_HAS_FEATURE_WIDESTRINGS} - procedure fpc_widestr_qword(v : qword;len : SizeInt;out s : widestring); compilerproc; - procedure fpc_widestr_int64(v : int64;len : SizeInt;out s : widestring); compilerproc; + {$if not(defined(FPC_WIDESTRING_EQUAL_UNICODESTRING)) or defined(VER2_2)} + procedure fpc_widestr_qword(v : qword;len : SizeInt;out s : widestring); compilerproc; + procedure fpc_widestr_int64(v : int64;len : SizeInt;out s : widestring); compilerproc; + {$endif not(defined(FPC_WIDESTRING_EQUAL_UNICODESTRING)) or defined(VER2_2)} + {$ifndef VER2_2} + procedure fpc_UnicodeStr_qword(v : qword;len : SizeInt;out s : UnicodeString); compilerproc; + procedure fpc_UnicodeStr_int64(v : int64;len : SizeInt;out s : UnicodeString); compilerproc; + {$endif VER2_2} {$endif FPC_HAS_FEATURE_WIDESTRINGS} {$endif CPU64} {$ifdef FPC_HAS_FEATURE_WIDESTRINGS} -{$ifndef FPUNONE} -procedure fpc_WideStr_Float(d : ValReal;len,fr,rt : SizeInt;out s : WideString); compilerproc; -{$endif} -{$ifdef FPC_HAS_STR_CURRENCY} -procedure fpc_WideStr_Currency(c : Currency;len,fr : SizeInt;out s : WideString);compilerproc; -{$endif FPC_HAS_STR_CURRENCY} + {$if not(defined(FPC_WIDESTRING_EQUAL_UNICODESTRING)) or defined(VER2_2)} + {$ifndef FPUNONE} + procedure fpc_WideStr_Float(d : ValReal;len,fr,rt : SizeInt;out s : WideString); compilerproc; + {$endif} + {$ifdef FPC_HAS_STR_CURRENCY} + procedure fpc_WideStr_Currency(c : Currency;len,fr : SizeInt;out s : WideString);compilerproc; + {$endif FPC_HAS_STR_CURRENCY} + {$endif not(defined(FPC_WIDESTRING_EQUAL_UNICODESTRING)) or defined(VER2_2)} + {$ifndef VER2_2} + {$ifndef FPUNONE} + procedure fpc_UnicodeStr_Float(d : ValReal;len,fr,rt : SizeInt;out s : UnicodeString); compilerproc; + {$endif} + {$ifdef FPC_HAS_STR_CURRENCY} + procedure fpc_UnicodeStr_Currency(c : Currency;len,fr : SizeInt;out s : UnicodeString);compilerproc; + {$endif FPC_HAS_STR_CURRENCY} + {$endif VER2_2} {$endif FPC_HAS_FEATURE_WIDESTRINGS} {$ifndef FPUNONE} @@ -174,15 +197,28 @@ Function fpc_Val_SInt_AnsiStr (DestSize: SizeInt; Const S : AnsiString; out Code Function fpc_Val_Currency_AnsiStr(Const S : AnsiString; out Code : ValSInt): Currency; compilerproc; function fpc_Val_enum_ansistr(str2ordindex:pointer;const s:ansistring;out code:valsint):longint; compilerproc; {$endif FPC_HAS_FEATURE_ANSISTRINGS} + {$ifdef FPC_HAS_FEATURE_WIDESTRINGS} -{$ifndef FPUNONE} -Function fpc_Val_Real_WideStr(Const S : WideString; out Code : ValSInt): ValReal; compilerproc; -{$endif} -Function fpc_Val_SInt_WideStr (DestSize: SizeInt; Const S : WideString; out Code : ValSInt): ValSInt; compilerproc; -Function fpc_Val_UInt_WideStr (Const S : WideString; out Code : ValSInt): ValUInt; compilerproc; -function fpc_val_enum_widestr(str2ordindex:pointer;const s:widestring;out code:valsint):longint;compilerproc; -Function fpc_Val_Currency_WideStr(Const S : WideString; out Code : ValSInt): Currency; compilerproc; + {$if not(defined(FPC_WIDESTRING_EQUAL_UNICODESTRING)) or defined(VER2_2)} + {$ifndef FPUNONE} + Function fpc_Val_Real_WideStr(Const S : WideString; out Code : ValSInt): ValReal; compilerproc; + {$endif} + Function fpc_Val_SInt_WideStr (DestSize: SizeInt; Const S : WideString; out Code : ValSInt): ValSInt; compilerproc; + Function fpc_Val_UInt_WideStr (Const S : WideString; out Code : ValSInt): ValUInt; compilerproc; + function fpc_val_Enum_WideStr (str2ordindex:pointer;const s:WideString;out code:valsint):longint;compilerproc; + Function fpc_Val_Currency_WideStr(Const S : WideString; out Code : ValSInt): Currency; compilerproc; + {$endif not(defined(FPC_WIDESTRING_EQUAL_UNICODESTRING)) or defined(VER2_2)} + {$ifndef VER2_2} + {$ifndef FPUNONE} + Function fpc_Val_Real_UnicodeStr(Const S : UnicodeString; out Code : ValSInt): ValReal; compilerproc; + {$endif} + Function fpc_Val_SInt_UnicodeStr (DestSize: SizeInt; Const S : UnicodeString; out Code : ValSInt): ValSInt; compilerproc; + Function fpc_Val_UInt_UnicodeStr (Const S : UnicodeString; out Code : ValSInt): ValUInt; compilerproc; + function fpc_val_Enum_UnicodeStr(str2ordindex:pointer;const s:UnicodeString;out code:valsint):longint;compilerproc; + Function fpc_Val_Currency_UnicodeStr(Const S : UnicodeString; out Code : ValSInt): Currency; compilerproc; + {$endif VER2_2} {$endif FPC_HAS_FEATURE_WIDESTRINGS} + {$ifndef CPU64} Function fpc_val_int64_shortstr(Const S: ShortString; out Code: ValSInt): Int64; compilerproc; Function fpc_val_qword_shortstr(Const S: ShortString; out Code: ValSInt): QWord; compilerproc; @@ -190,10 +226,18 @@ Function fpc_val_qword_shortstr(Const S: ShortString; out Code: ValSInt): QWord; Function fpc_Val_qword_AnsiStr (Const S : AnsiString; out Code : ValSInt): qword;compilerproc; Function fpc_Val_int64_AnsiStr (Const S : AnsiString; out Code : ValSInt): Int64; compilerproc; {$endif FPC_HAS_FEATURE_ANSISTRINGS} + {$ifdef FPC_HAS_FEATURE_WIDESTRINGS} +{$if not(defined(FPC_WIDESTRING_EQUAL_UNICODESTRING)) or defined(VER2_2)} Function fpc_Val_qword_WideStr (Const S : WideString; out Code : ValSInt): qword; compilerproc; Function fpc_Val_int64_WideStr (Const S : WideString; out Code : ValSInt): Int64; compilerproc; +{$endif not(defined(FPC_WIDESTRING_EQUAL_UNICODESTRING)) or defined(VER2_2)} +{$ifndef VER2_2} +Function fpc_Val_qword_UnicodeStr (Const S : UnicodeString; out Code : ValSInt): qword; compilerproc; +Function fpc_Val_int64_UnicodeStr (Const S : UnicodeString; out Code : ValSInt): Int64; compilerproc; +{$endif VER2_2} {$endif FPC_HAS_FEATURE_WIDESTRINGS} + {$endif CPU64} {$ifdef FPC_HAS_FEATURE_ANSISTRINGS} @@ -243,6 +287,11 @@ Function fpc_AnsiStr_ShortStr_Compare (Var S1 : Pointer; Var S2 : ShortString): Function fpc_ansistr_Unique(Var S : Pointer): Pointer; compilerproc; {$endif FPC_HAS_FEATURE_ANSISTRINGS} +{***************************************************************************** + Widestring support +*****************************************************************************} + +{$if not(defined(FPC_WIDESTRING_EQUAL_UNICODESTRING)) or defined(VER2_2)} {$ifdef FPC_HAS_FEATURE_WIDESTRINGS} Procedure fpc_WideStr_Decr_Ref (Var S : Pointer); compilerproc; Procedure fpc_WideStr_Incr_Ref (Var S : Pointer); compilerproc; @@ -267,22 +316,11 @@ Function fpc_PChar_To_WideStr(const p : pchar): WideString; compilerproc; Function fpc_CharArray_To_WideStr(const arr: array of char; zerobased: boolean = true): WideString; compilerproc; {$ifndef FPC_STRTOCHARARRAYPROC} function fpc_widestr_to_chararray(arraysize: SizeInt; const src: WideString): fpc_big_chararray; compilerproc; -Function fpc_shortstr_to_widechararray(arraysize: SizeInt; const src: ShortString): fpc_big_widechararray; compilerproc; -Function fpc_ansistr_to_widechararray(arraysize: SizeInt; const src: AnsiString): fpc_big_widechararray; compilerproc; Function fpc_widestr_to_widechararray(arraysize: SizeInt; const src: WideString): fpc_big_widechararray; compilerproc; {$else ndef FPC_STRTOCHARARRAYPROC} procedure fpc_widestr_to_chararray(out res: array of char; const src: WideString); compilerproc; -procedure fpc_shortstr_to_widechararray(out res: array of widechar; const src: ShortString); compilerproc; -procedure fpc_ansistr_to_widechararray(out res: array of widechar; const src: AnsiString); compilerproc; procedure fpc_widestr_to_widechararray(out res: array of widechar; const src: WideString); compilerproc; {$endif ndef FPC_STRTOCHARARRAYPROC} -{$ifndef FPC_STRTOSHORTSTRINGPROC} -Function fpc_WideCharArray_To_ShortStr(const arr: array of widechar; zerobased: boolean = true): shortstring; compilerproc; -{$else FPC_STRTOSHORTSTRINGPROC} -procedure fpc_WideCharArray_To_ShortStr(out res : shortstring;const arr: array of widechar; zerobased: boolean = true); compilerproc; -{$endif FPC_STRTOSHORTSTRINGPROC} -Function fpc_WideCharArray_To_AnsiStr(const arr: array of widechar; zerobased: boolean = true): AnsiString; compilerproc; -Function fpc_WideCharArray_To_WideStr(const arr: array of widechar; zerobased: boolean = true): WideString; compilerproc; Function fpc_WideStr_Compare(const S1,S2 : WideString): SizeInt; compilerproc; Function fpc_WideStr_Compare_equal(const S1,S2 : WideString): SizeInt; compilerproc; Procedure fpc_WideStr_CheckZero(p : pointer); compilerproc; @@ -292,28 +330,131 @@ Function fpc_widestr_Copy (Const S : WideString; Index,Size : SizeInt) : WideSt {$ifndef FPC_WINLIKEWIDESTRING} function fpc_widestr_Unique(Var S : Pointer): Pointer; compilerproc; {$endif FPC_WINLIKEWIDESTRING} -Function fpc_Char_To_WChar(const c : Char): WideChar; compilerproc; -Function fpc_WChar_To_Char(const c : WideChar): Char; compilerproc; +Function fpc_WChar_To_AnsiStr(const c : WideChar): AnsiString; compilerproc; +Function fpc_WChar_To_WideStr(const c : WideChar): WideString; compilerproc; +{$ifndef VER2_2} +Function fpc_UChar_To_WideStr(const c : WideChar): WideString; compilerproc; +{$endif VER2_2} +{$endif FPC_HAS_FEATURE_WIDESTRINGS} + +{$ifdef FPC_HAS_FEATURE_WIDESTRINGS} +Function fpc_PWideChar_To_WideStr(const p : pwidechar): widestring; compilerproc; +{$endif FPC_HAS_FEATURE_WIDESTRINGS} +{$endif defined(WINDOWS) or defined(VER2_2)} + +{***************************************************************************** + Unicode string support +*****************************************************************************} + +{$ifndef VER2_2} +{$ifdef FPC_HAS_FEATURE_WIDESTRINGS} +Procedure fpc_UnicodeStr_Decr_Ref (Var S : Pointer); compilerproc; +Procedure fpc_UnicodeStr_Incr_Ref (S : Pointer); compilerproc; +{$ifndef FPC_STRTOSHORTSTRINGPROC} +function fpc_UnicodeStr_To_ShortStr (high_of_res: SizeInt;const S2 : UnicodeString): shortstring; compilerproc; +{$else FPC_STRTOSHORTSTRINGPROC} +procedure fpc_UnicodeStr_To_ShortStr (out res: ShortString;const S2 : UnicodeString); compilerproc; +{$endif FPC_STRTOSHORTSTRINGPROC} +Function fpc_ShortStr_To_UnicodeStr (Const S2 : ShortString): UnicodeString; compilerproc; +Function fpc_UnicodeStr_To_AnsiStr (const S2 : UnicodeString): AnsiString; compilerproc; +Function fpc_AnsiStr_To_UnicodeStr (Const S2 : AnsiString): UnicodeString; compilerproc; +Function fpc_UnicodeStr_To_WideStr (const S2 : UnicodeString): WideString; compilerproc; +Function fpc_WideStr_To_UnicodeStr (Const S2 : WideString): UnicodeString; compilerproc; +Procedure fpc_UnicodeStr_Assign (Var S1 : Pointer;S2 : Pointer); compilerproc; +{$ifndef STR_CONCAT_PROCS} +Function fpc_UnicodeStr_Concat (const S1,S2 : UnicodeString) : UnicodeString; compilerproc; +function fpc_UnicodeStr_Concat_multi (const sarr:array of Unicodestring): unicodestring; compilerproc; +{$else STR_CONCAT_PROCS} +Procedure fpc_UnicodeStr_Concat (Var DestS : Unicodestring;const S1,S2 : UnicodeString); compilerproc; +Procedure fpc_UnicodeStr_Concat_multi (Var DestS : Unicodestring;const sarr:array of Unicodestring); compilerproc; +{$endif STR_CONCAT_PROCS} +Function fpc_Char_To_UnicodeStr(const c : Char): UnicodeString; compilerproc; +Function fpc_PChar_To_UnicodeStr(const p : pchar): UnicodeString; compilerproc; +Function fpc_CharArray_To_UnicodeStr(const arr: array of char; zerobased: boolean = true): UnicodeString; compilerproc; +{$ifndef FPC_STRTOCHARARRAYPROC} +function fpc_unicodestr_to_chararray(arraysize: SizeInt; const src: UnicodeString): fpc_big_chararray; compilerproc; +Function fpc_shortstr_to_unicodechararray(arraysize: SizeInt; const src: ShortString): fpc_big_unicodechararray; compilerproc; +Function fpc_ansistr_to_unicodechararray(arraysize: SizeInt; const src: AnsiString): fpc_big_unicodechararray; compilerproc; +Function fpc_unicodestr_to_unicodechararray(arraysize: SizeInt; const src: UnicodeString): fpc_big_unicodechararray; compilerproc; +{$else ndef FPC_STRTOCHARARRAYPROC} +procedure fpc_unicodestr_to_chararray(out res: array of char; const src: UnicodeString); compilerproc; +procedure fpc_shortstr_to_unicodechararray(out res: array of unicodechar; const src: ShortString); compilerproc; +procedure fpc_ansistr_to_unicodechararray(out res: array of unicodechar; const src: AnsiString); compilerproc; +procedure fpc_unicodestr_to_unicodechararray(out res: array of unicodechar; const src: UnicodeString); compilerproc; +{$endif ndef FPC_STRTOCHARARRAYPROC} +{$ifndef FPC_STRTOSHORTSTRINGPROC} +Function fpc_UnicodeCharArray_To_ShortStr(const arr: array of unicodechar; zerobased: boolean = true): shortstring; compilerproc; +{$else FPC_STRTOSHORTSTRINGPROC} +procedure fpc_UnicodeCharArray_To_ShortStr(out res : shortstring;const arr: array of unicodechar; zerobased: boolean = true); compilerproc; +{$endif FPC_STRTOSHORTSTRINGPROC} +Function fpc_UnicodeCharArray_To_AnsiStr(const arr: array of unicodechar; zerobased: boolean = true): AnsiString; compilerproc; +Function fpc_UnicodeCharArray_To_UnicodeStr(const arr: array of unicodechar; zerobased: boolean = true): UnicodeString; compilerproc; +{$ifndef VER2_2} +{$ifndef FPC_STRTOSHORTSTRINGPROC} +Function fpc_WideCharArray_To_ShortStr(const arr: array of widechar; zerobased: boolean = true): shortstring; compilerproc; +{$else FPC_STRTOSHORTSTRINGPROC} +procedure fpc_WideCharArray_To_ShortStr(out res : shortstring;const arr: array of widechar; zerobased: boolean = true); compilerproc; +{$endif FPC_STRTOSHORTSTRINGPROC} +Function fpc_WideCharArray_To_AnsiStr(const arr: array of widechar; zerobased: boolean = true): AnsiString; compilerproc; +Function fpc_WideCharArray_To_WideStr(const arr: array of widechar; zerobased: boolean = true): WideString; compilerproc; +Function fpc_WideCharArray_To_UnicodeStr(const arr: array of widechar; zerobased: boolean = true): UnicodeString; compilerproc; +{$ifndef FPC_STRTOCHARARRAYPROC} +Function fpc_shortstr_to_widechararray(arraysize: SizeInt; const src: ShortString): fpc_big_widechararray; compilerproc; +Function fpc_ansistr_to_widechararray(arraysize: SizeInt; const src: AnsiString): fpc_big_widechararray; compilerproc; +{$else ndef FPC_STRTOCHARARRAYPROC} +procedure fpc_shortstr_to_widechararray(out res: array of widechar; const src: ShortString); compilerproc; +procedure fpc_ansistr_to_widechararray(out res: array of widechar; const src: AnsiString); compilerproc; +procedure fpc_unicodestr_to_widechararray(out res: array of widechar; const src: UnicodeString); compilerproc; +{$endif ndef FPC_STRTOCHARARRAYPROC} +{$endif VER2_2} +Function fpc_UnicodeStr_Compare(const S1,S2 : UnicodeString): SizeInt; compilerproc; +Function fpc_UnicodeStr_Compare_equal(const S1,S2 : UnicodeString): SizeInt; compilerproc; +Procedure fpc_UnicodeStr_CheckZero(p : pointer); compilerproc; +Procedure fpc_UnicodeStr_CheckRange(len,index : SizeInt); compilerproc; +Procedure fpc_UnicodeStr_SetLength (Var S : UnicodeString; l : SizeInt); compilerproc; +Function fpc_unicodestr_Copy (Const S : UnicodeString; Index,Size : SizeInt) : UnicodeString;compilerproc; +function fpc_unicodestr_Unique(Var S : Pointer): Pointer; compilerproc; +Function fpc_Char_To_UChar(const c : Char): UnicodeChar; compilerproc; +Function fpc_UChar_To_Char(const c : UnicodeChar): Char; compilerproc; +Function fpc_UChar_To_UnicodeStr(const c : UnicodeChar): UnicodeString; compilerproc; +Function fpc_WChar_To_UnicodeStr(const c : WideChar): UnicodeString; compilerproc; +Function fpc_UChar_To_AnsiStr(const c : UnicodeChar): AnsiString; compilerproc; {$ifndef FPC_STRTOSHORTSTRINGPROC} Function fpc_WChar_To_ShortStr(const c : WideChar): ShortString; compilerproc; {$else FPC_STRTOSHORTSTRINGPROC} procedure fpc_WChar_To_ShortStr(out res : shortstring;const c : WideChar) compilerproc; {$endif FPC_STRTOSHORTSTRINGPROC} -Function fpc_WChar_To_AnsiStr(const c : WideChar): AnsiString; compilerproc; -Function fpc_WChar_To_WideStr(const c : WideChar): WideString; compilerproc; +{$endif FPC_HAS_FEATURE_WIDESTRINGS} + +{$ifdef FPC_HAS_FEATURE_WIDESTRINGS} +{$ifdef FPC_HAS_FEATURE_ANSISTRINGS} +Function fpc_PUnicodeChar_To_AnsiStr(const p : punicodechar): ansistring; compilerproc; +{$endif FPC_HAS_FEATURE_ANSISTRINGS} +Function fpc_PUnicodeChar_To_UnicodeStr(const p : punicodechar): unicodestring; compilerproc; +Function fpc_PWideChar_To_UnicodeStr(const p : pwidechar): unicodestring; compilerproc; +{$ifndef FPC_STRTOSHORTSTRINGPROC} +Function fpc_PUnicodeChar_To_ShortStr(const p : punicodechar): shortstring; compilerproc; +{$else FPC_STRTOSHORTSTRINGPROC} +procedure fpc_PUnicodeChar_To_ShortStr(out res : shortstring;const p : punicodechar); compilerproc; +{$endif FPC_STRTOSHORTSTRINGPROC} {$endif FPC_HAS_FEATURE_WIDESTRINGS} {$ifdef FPC_HAS_FEATURE_WIDESTRINGS} {$ifdef FPC_HAS_FEATURE_ANSISTRINGS} Function fpc_PWideChar_To_AnsiStr(const p : pwidechar): ansistring; compilerproc; {$endif FPC_HAS_FEATURE_ANSISTRINGS} -Function fpc_PWideChar_To_WideStr(const p : pwidechar): widestring; compilerproc; {$ifndef FPC_STRTOSHORTSTRINGPROC} Function fpc_PWideChar_To_ShortStr(const p : pwidechar): shortstring; compilerproc; {$else FPC_STRTOSHORTSTRINGPROC} procedure fpc_PWideChar_To_ShortStr(out res : shortstring;const p : pwidechar); compilerproc; {$endif FPC_STRTOSHORTSTRINGPROC} {$endif FPC_HAS_FEATURE_WIDESTRINGS} +{$endif VER2_2} + +{$ifdef FPC_HAS_FEATURE_WIDESTRINGS} +Function fpc_Char_To_WChar(const c : Char): WideChar; compilerproc; +Function fpc_WChar_To_Char(const c : WideChar): Char; compilerproc; +{$endif FPC_HAS_FEATURE_WIDESTRINGS} {$ifdef FPC_HAS_FEATURE_TEXTIO} { from text.inc } @@ -325,7 +466,10 @@ Procedure fpc_Write_Text_ShortStr(Len : Longint;var f : Text;const s : String); Procedure fpc_Write_Text_Pchar_as_Array(Len : Longint;var f : Text;const s : array of char; zerobased: boolean = true); compilerproc; Procedure fpc_Write_Text_PChar_As_Pointer(Len : Longint;var f : Text;p : PChar); compilerproc; Procedure fpc_Write_Text_AnsiStr (Len : Longint; Var f : Text; const S : AnsiString); compilerproc; +{$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING} Procedure fpc_Write_Text_WideStr (Len : Longint; Var f : Text; const S : WideString); compilerproc; +{$endif FPC_WIDESTRING_EQUAL_UNICODESTRING} +Procedure fpc_Write_Text_UnicodeStr (Len : Longint; Var f : Text; const S : WideString); compilerproc; Procedure fpc_Write_Text_SInt(Len : Longint;var t : Text;l : ValSInt); compilerproc; Procedure fpc_Write_Text_UInt(Len : Longint;var t : Text;l : ValUInt); compilerproc; {$ifndef CPU64} diff --git a/rtl/inc/rtti.inc b/rtl/inc/rtti.inc index f2cfb6435c..c51b0afe4e 100644 --- a/rtl/inc/rtti.inc +++ b/rtl/inc/rtti.inc @@ -40,6 +40,9 @@ Const tkInt64 = 19; tkQWord = 20; tkDynArray = 21; + tkInterfaceCorba = 22; + tkProcVar = 23; + tkUString = 24; type @@ -130,7 +133,7 @@ end; Procedure fpc_Initialize (Data,TypeInfo : pointer);[Public,Alias : 'FPC_INITIALIZE']; compilerproc; begin case PByte(TypeInfo)^ of - tkAstring,tkWstring,tkInterface,tkDynArray: + tkAstring,tkWstring,tkUString,tkInterface,tkDynArray: PPchar(Data)^:=Nil; tkArray: arrayrtti(data,typeinfo,@int_initialize); @@ -151,11 +154,20 @@ begin fpc_AnsiStr_Decr_Ref(PPointer(Data)^); PPointer(Data)^:=nil; end; +{$ifndef VER2_2} + tkUstring : + begin + fpc_UnicodeStr_Decr_Ref(PPointer(Data)^); + PPointer(Data)^:=nil; + end; +{$endif VER2_2} +{$ifdef WINDOWS} tkWstring : begin fpc_WideStr_Decr_Ref(PPointer(Data)^); PPointer(Data)^:=nil; end; +{$endif WINDOWS} tkArray : arrayrtti(data,typeinfo,@int_finalize); tkObject, @@ -179,8 +191,14 @@ begin case PByte(TypeInfo)^ of tkAstring : fpc_AnsiStr_Incr_Ref(PPointer(Data)^); +{$ifdef WINDOWS} tkWstring : fpc_WideStr_Incr_Ref(PPointer(Data)^); +{$endif WINDOWS} +{$ifndef VER2_2} + tkUstring : + fpc_UnicodeStr_Incr_Ref(PPointer(Data)^); +{$endif VER2_2} tkArray : arrayrtti(data,typeinfo,@int_addref); tkobject, @@ -206,8 +224,14 @@ begin { see AddRef for comment about below construct (JM) } tkAstring: fpc_AnsiStr_Decr_Ref(PPointer(Data)^); +{$ifdef WINDOWS} tkWstring: fpc_WideStr_Decr_Ref(PPointer(Data)^); +{$endif WINDOWS} +{$ifndef VER2_2} + tkUString: + fpc_UnicodeStr_Decr_Ref(PPointer(Data)^); +{$endif VER2_2} tkArray: arrayrtti(data,typeinfo,@fpc_systemDecRef); tkobject, @@ -245,8 +269,14 @@ begin fpc_AnsiStr_Decr_Ref(PPointer(Dest)^); PPointer(Dest)^:=PPointer(Src)^; end; +{$ifdef WINDOWS} tkWstring: fpc_WideStr_Assign(PPointer(Dest)^,PPointer(Src)^); +{$endif WINDOWS} +{$ifndef VER2_2} + tkUstring: + fpc_UnicodeStr_Assign(PPointer(Dest)^,PPointer(Src)^); +{$endif VER2_2} tkArray: begin Temp:=PByte(TypeInfo); diff --git a/rtl/inc/system.inc b/rtl/inc/system.inc index 72512533f3..79a4590c2c 100644 --- a/rtl/inc/system.inc +++ b/rtl/inc/system.inc @@ -331,7 +331,15 @@ function aligntoptr(p : pointer) : pointer;inline; {$endif FPC_HAS_FEATURE_ANSISTRINGS} {$ifdef FPC_HAS_FEATURE_WIDESTRINGS} -{$i wstrings.inc} +{ this is for bootstrappung with 2.2.x } +{$ifdef VER2_2} +{$i wustring22.inc} +{$else VER2_2} + {$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING} + {$i wstrings.inc} + {$endif FPC_WIDESTRING_EQUAL_UNICODESTRING} + {$i ustrings.inc} +{$endif VER2_2} {$endif FPC_HAS_FEATURE_WIDESTRINGS} {$i aliases.inc} diff --git a/rtl/inc/systemh.inc b/rtl/inc/systemh.inc index cd99876038..4267429816 100644 --- a/rtl/inc/systemh.inc +++ b/rtl/inc/systemh.inc @@ -345,6 +345,14 @@ Type PUCS2Char = PWideChar; PWideString = ^WideString; + UnicodeChar = type WideChar; + PUnicodeChar = ^UnicodeChar; +{$ifdef VER2_2} + { this is only to avoid too much ifdefs in the code } + UnicodeString = type WideString; +{$endif VER2_2} + PUnicodeString = ^UnicodeString; + { Needed for fpc_get_output } PText = ^Text; @@ -761,7 +769,14 @@ function lowercase(const s : ansistring) : ansistring; ****************************************************************************} {$ifdef FPC_HAS_FEATURE_WIDESTRINGS} -{$i wstringh.inc} +{$ifdef VER2_2} +{$i wstring22h.inc} +{$else VER2_2} + {$i ustringh.inc} + {$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING} + {$i wstringh.inc} + {$endif FPC_WIDESTRING_EQUAL_UNICODESTRING} +{$endif VER2_2} {$endif FPC_HAS_FEATURE_WIDESTRINGS} diff --git a/rtl/inc/text.inc b/rtl/inc/text.inc index 1819522e71..a73e2fe38d 100644 --- a/rtl/inc/text.inc +++ b/rtl/inc/text.inc @@ -617,6 +617,32 @@ begin end; +Procedure fpc_Write_Text_UnicodeStr (Len : Longint; Var f : Text; const S : WideString); iocheck; [Public,alias:'FPC_WRITE_TEXT_UNICODESTR']; compilerproc; +{ + Writes a UnicodeString to the Text file T +} +var + SLen : longint; + a: ansistring; +begin + If (pointer(S)=nil) or (InOutRes<>0) then + exit; + case TextRec(f).mode of + fmOutput { fmAppend gets changed to fmOutPut in do_open (JM) }: + begin + SLen:=Length(s); + If Len>SLen Then + fpc_WriteBlanks(f,Len-SLen); + a:=s; + { length(a) can be > slen, e.g. after utf-16 -> utf-8 } + fpc_WriteBuffer(f,pchar(a)^,length(a)); + end; + fmInput: InOutRes:=105 + else InOutRes:=103; + end; +end; + +{$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING} Procedure fpc_Write_Text_WideStr (Len : Longint; Var f : Text; const S : WideString); iocheck; [Public,alias:'FPC_WRITE_TEXT_WIDESTR']; compilerproc; { Writes a WideString to the Text file T @@ -641,7 +667,7 @@ begin else InOutRes:=103; end; end; - +{$endif FPC_WIDESTRING_EQUAL_UNICODESTRING} Procedure fpc_Write_Text_SInt(Len : Longint;var t : Text;l : ValSInt); iocheck; [Public,Alias:'FPC_WRITE_TEXT_SINT']; compilerproc; var diff --git a/rtl/inc/ustringh.inc b/rtl/inc/ustringh.inc new file mode 100644 index 0000000000..8583400c1f --- /dev/null +++ b/rtl/inc/ustringh.inc @@ -0,0 +1,119 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2005 by Florian Klaempfl, + member of the Free Pascal development team. + + This file implements support routines for UnicodeStrings with FPC + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + + +Procedure UniqueString (Var S : UnicodeString);external name 'FPC_UNICODESTR_UNIQUE'; +Function Pos (Const Substr : UnicodeString; Const Source : UnicodeString) : SizeInt; +Function Pos (c : Char; Const s : UnicodeString) : SizeInt; +Function Pos (c : UnicodeChar; Const s : UnicodeString) : SizeInt; +Function Pos (c : AnsiString; Const s : UnicodeString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} +Function Pos (c : UnicodeString; Const s : AnsiString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} +Function Pos (c : ShortString; Const s : UnicodeString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} + +Function UpCase(const s : UnicodeString) : UnicodeString; +Function UpCase(c:UnicodeChar):UnicodeChar; + +Procedure Insert (Const Source : UnicodeString; Var S : UnicodeString; Index : SizeInt); +Procedure Delete (Var S : UnicodeString; Index,Size: SizeInt); +Procedure SetString (Out S : UnicodeString; Buf : PUnicodeChar; Len : SizeInt); +Procedure SetString (Out S : UnicodeString; Buf : PChar; Len : SizeInt); + +function WideCharToString(S : PWideChar) : AnsiString; +function StringToWideChar(const Src : AnsiString;Dest : PWideChar;DestSize : SizeInt) : PWideChar; +function WideCharLenToString(S : PWideChar;Len : SizeInt) : AnsiString; +procedure WideCharLenToStrVar(Src : PWideChar;Len : SizeInt;out Dest : AnsiString); +procedure WideCharToStrVar(S : PWideChar;out Dest : AnsiString); + +function UnicodeCharToString(S : PUnicodeChar) : AnsiString; +function StringToUnicodeChar(const Src : AnsiString;Dest : PUnicodeChar;DestSize : SizeInt) : PUnicodeChar; +function UnicodeCharLenToString(S : PUnicodeChar;Len : SizeInt) : AnsiString; +procedure UnicodeCharLenToStrVar(Src : PUnicodeChar;Len : SizeInt;out Dest : AnsiString); +procedure UnicodeCharToStrVar(S : PUnicodeChar;out Dest : AnsiString); + +procedure DefaultUnicode2AnsiMove(source:punicodechar;var dest:ansistring;len:SizeInt); +procedure DefaultAnsi2UnicodeMove(source:pchar;var dest:unicodestring;len:SizeInt); + +Type + { hooks for internationalization + please add new procedures at the end, it makes it easier to detect new procedures } + TUnicodeStringManager = record + Wide2AnsiMoveProc : procedure(source:pwidechar;var dest:ansistring;len:SizeInt); + Ansi2WideMoveProc : procedure(source:pchar;var dest:widestring;len:SizeInt); + +// UpperUTF8 : procedure(p:PUTF8String); + + UpperWideStringProc : function(const S: WideString): WideString; +// UpperUCS4 : procedure(p:PUCS4Char); +// LowerUTF8 : procedure(p:PUTF8String); + LowerWideStringProc : function(const S: WideString): WideString; +// LowerUCS4 : procedure(p:PUCS4Char); +{ + CompUTF8 : function(p1,p2:PUTF8String) : shortint; + CompUCS2 : function(p1,p2:PUCS2Char) : shortint; + CompUCS4 : function(p1,p2:PUC42Char) : shortint; +} + CompareWideStringProc : function(const s1, s2 : WideString) : PtrInt; + CompareTextWideStringProc : function(const s1, s2 : WideString): PtrInt; + CharLengthPCharProc : function(const Str: PChar): PtrInt; + + UpperAnsiStringProc : function(const s : ansistring) : ansistring; + LowerAnsiStringProc : function(const s : ansistring) : ansistring; + CompareStrAnsiStringProc : function(const S1, S2: ansistring): PtrInt; + CompareTextAnsiStringProc : function(const S1, S2: ansistring): PtrInt; + StrCompAnsiStringProc : function(S1, S2: PChar): PtrInt; + StrICompAnsiStringProc : function(S1, S2: PChar): PtrInt; + StrLCompAnsiStringProc : function(S1, S2: PChar; MaxLen: PtrUInt): PtrInt; + StrLICompAnsiStringProc : function(S1, S2: PChar; MaxLen: PtrUInt): PtrInt; + StrLowerAnsiStringProc : function(Str: PChar): PChar; + StrUpperAnsiStringProc : function(Str: PChar): PChar; + ThreadInitProc : procedure; + ThreadFiniProc : procedure; + + { this is only different on windows } + Unicode2AnsiMoveProc : procedure(source:punicodechar;var dest:ansistring;len:SizeInt); + Ansi2UnicodeMoveProc : procedure(source:pchar;var dest:unicodestring;len:SizeInt); + UpperUnicodeStringProc : function(const S: UnicodeString): UnicodeString; + LowerUnicodeStringProc : function(const S: UnicodeString): UnicodeString; + CompareUnicodeStringProc : function(const s1, s2 : UnicodeString) : PtrInt; + CompareTextUnicodeStringProc : function(const s1, s2 : UnicodeString): PtrInt; + end; + +var + widestringmanager : TUnicodeStringManager; + +function UnicodeToUtf8(Dest: PChar; Source: PUnicodeChar; MaxBytes: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} +function UnicodeToUtf8(Dest: PChar; MaxDestBytes: SizeUInt; Source: PUnicodeChar; SourceChars: SizeUInt): SizeUInt; +function Utf8ToUnicode(Dest: PUnicodeChar; Source: PChar; MaxChars: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} +function Utf8ToUnicode(Dest: PUnicodeChar; MaxDestChars: SizeUInt; Source: PChar; SourceBytes: SizeUInt): SizeUInt; +function UTF8Encode(const s : Ansistring) : UTF8String; inline; +function UTF8Encode(const s : UnicodeString) : UTF8String; +function UTF8Decode(const s : UTF8String): UnicodeString; +function AnsiToUtf8(const s : ansistring): UTF8String;{$ifdef SYSTEMINLINE}inline;{$endif} +function Utf8ToAnsi(const s : UTF8String) : ansistring;{$ifdef SYSTEMINLINE}inline;{$endif} +function UnicodeStringToUCS4String(const s : UnicodeString) : UCS4String; +function UCS4StringToUnicodeString(const s : UCS4String) : UnicodeString; +function WideStringToUCS4String(const s : WideString) : UCS4String; +function UCS4StringToWideString(const s : UCS4String) : WideString; + +Procedure GetWideStringManager (Var Manager : TUnicodeStringManager); +Procedure SetWideStringManager (Const New : TUnicodeStringManager); +Procedure SetWideStringManager (Const New : TUnicodeStringManager; Var Old: TUnicodeStringManager); + +Procedure GetUnicodeStringManager (Var Manager : TUnicodeStringManager); +Procedure SetUnicodeStringManager (Const New : TUnicodeStringManager); +Procedure SetUnicodeStringManager (Const New : TUnicodeStringManager; Var Old: TUnicodeStringManager); + + diff --git a/rtl/inc/ustrings.inc b/rtl/inc/ustrings.inc new file mode 100644 index 0000000000..c1894474b5 --- /dev/null +++ b/rtl/inc/ustrings.inc @@ -0,0 +1,2325 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2005 by Florian Klaempfl, + member of the Free Pascal development team. + + This file implements support routines for UTF-8 strings with FPC + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +{$i wustrings.inc} + +{ + This file contains the implementation of the UnicodeString type, + and all things that are needed for it. + UnicodeString is defined as a 'silent' punicodechar : + a punicodechar that points to : + + @-8 : SizeInt for reference count; + @-4 : SizeInt for size; size=number of bytes, not the number of chars. Divide or multiply + with sizeof(UnicodeChar) to convert. This is needed to be compatible with Delphi and + Windows COM BSTR. + @ : String + Terminating #0; + Punicodechar(Unicodestring) is a valid typecast. + So WS[i] is converted to the address @WS+i-1. + + Constants should be assigned a reference count of -1 + Meaning that they can't be disposed of. +} + +Type + PUnicodeRec = ^TUnicodeRec; + TUnicodeRec = Packed Record + Ref : SizeInt; + Len : SizeInt; + First : UnicodeChar; + end; + +Const + UnicodeRecLen = SizeOf(TUnicodeRec); + UnicodeFirstOff = SizeOf(TUnicodeRec)-sizeof(UnicodeChar); + +{ + Default UnicodeChar <-> Char conversion is to only convert the + lower 127 chars, all others are translated to spaces. + + These routines can be overwritten for the Current Locale +} + +procedure DefaultUnicode2AnsiMove(source:punicodechar;var dest:ansistring;len:SizeInt); +var + i : SizeInt; +begin + setlength(dest,len); + for i:=1 to len do + begin + if word(source^)<256 then + dest[i]:=char(word(source^)) + else + dest[i]:='?'; + inc(source); + end; +end; + + +procedure DefaultAnsi2UnicodeMove(source:pchar;var dest:unicodestring;len:SizeInt); +var + i : SizeInt; +begin + setlength(dest,len); + for i:=1 to len do + begin + dest[i]:=unicodechar(byte(source^)); + inc(source); + end; +end; + + +Procedure GetUnicodeStringManager (Var Manager : TUnicodeStringManager); +begin + manager:=widestringmanager; +end; + + +Procedure SetUnicodeStringManager (Const New : TUnicodeStringManager; Var Old: TUnicodeStringManager); +begin + Old:=widestringmanager; + widestringmanager:=New; +end; + + +Procedure SetUnicodeStringManager (Const New : TUnicodeStringManager); +begin + widestringmanager:=New; +end; + + +Procedure GetWideStringManager (Var Manager : TUnicodeStringManager); +begin + manager:=widestringmanager; +end; + + +Procedure SetWideStringManager (Const New : TUnicodeStringManager; Var Old: TUnicodeStringManager); +begin + Old:=widestringmanager; + widestringmanager:=New; +end; + + +Procedure SetWideStringManager (Const New : TUnicodeStringManager); +begin + widestringmanager:=New; +end; + {**************************************************************************** + Internal functions, not in interface. +****************************************************************************} + + +procedure UnicodeStringError; + begin + HandleErrorFrame(204,get_frame); + end; + + +{$ifdef UnicodeStrDebug} +Procedure DumpUnicodeRec(S : Pointer); +begin + If S=Nil then + Writeln ('String is nil') + Else + Begin + With PUnicodeRec(S-UnicodeFirstOff)^ do + begin + Write ('(Len:',len); + Writeln (' Ref: ',ref,')'); + end; + end; +end; +{$endif} + + +Function NewUnicodeString(Len : SizeInt) : Pointer; +{ + Allocate a new UnicodeString on the heap. + initialize it to zero length and reference count 1. +} +Var + P : Pointer; +begin + GetMem(P,Len*sizeof(UnicodeChar)+UnicodeRecLen); + If P<>Nil then + begin + PUnicodeRec(P)^.Len:=Len*2; { Initial length } + PUnicodeRec(P)^.Ref:=1; { Initial Refcount } + PUnicodeRec(P)^.First:=#0; { Terminating #0 } + inc(p,UnicodeFirstOff); { Points to string now } + end + else + UnicodeStringError; + NewUnicodeString:=P; +end; + + +Procedure DisposeUnicodeString(Var S : Pointer); +{ + Deallocates a UnicodeString From the heap. +} +begin + If S=Nil then + exit; + Dec (S,UnicodeFirstOff); + Freemem(S); + S:=Nil; +end; + + +Procedure fpc_UnicodeStr_Decr_Ref (Var S : Pointer);[Public,Alias:'FPC_UNICODESTR_DECR_REF']; compilerproc; +{ + Decreases the ReferenceCount of a non constant unicodestring; + If the reference count is zero, deallocate the string; +} +Type + pSizeInt = ^SizeInt; +Var + l : pSizeInt; +Begin + { Zero string } + if S=Nil then + exit; + { check for constant strings ...} + l:=@PUnicodeRec(S-UnicodeFirstOff)^.Ref; + if l^<0 then + exit; + + { declocked does a MT safe dec and returns true, if the counter is 0 } + if declocked(l^) then + { Ref count dropped to zero ... + ... remove } + DisposeUnicodeString(S); +end; + +{ alias for internal use } +Procedure fpc_UnicodeStr_Decr_Ref (Var S : Pointer);[external name 'FPC_UNICODESTR_DECR_REF']; + +Procedure fpc_UnicodeStr_Incr_Ref(S : Pointer);[Public,Alias:'FPC_UNICODESTR_INCR_REF']; compilerproc; + Begin + If S=Nil then + exit; + { constant string ? } + If PUnicodeRec(S-UnicodeFirstOff)^.Ref<0 then + exit; + inclocked(PUnicodeRec(S-UnicodeFirstOff)^.Ref); + end; + +{ alias for internal use } +Procedure fpc_UnicodeStr_Incr_Ref (S : Pointer);[external name 'FPC_UNICODESTR_INCR_REF']; + +{$ifndef FPC_STRTOSHORTSTRINGPROC} +function fpc_UnicodeStr_To_ShortStr (high_of_res: SizeInt;const S2 : UnicodeString): shortstring;[Public, alias: 'FPC_UNICODESTR_TO_SHORTSTR']; compilerproc; +{ + Converts a UnicodeString to a ShortString; +} +Var + Size : SizeInt; + temp : ansistring; +begin + result:=''; + Size:=Length(S2); + if Size>0 then + begin + If Size>high_of_res then + Size:=high_of_res; + widestringmanager.Unicode2AnsiMoveProc(PUnicodeChar(S2),temp,Size); + result:=temp; + end; +end; +{$else FPC_STRTOSHORTSTRINGPROC} +procedure fpc_UnicodeStr_To_ShortStr (out res: ShortString;const S2 : UnicodeString); [Public, alias: 'FPC_UNICODESTR_TO_SHORTSTR'];compilerproc; +{ + Converts a UnicodeString to a ShortString; +} +Var + Size : SizeInt; + temp : ansistring; +begin + res:=''; + Size:=Length(S2); + if Size>0 then + begin + If Size>high(res) then + Size:=high(res); + widestringmanager.Unicode2AnsiMoveProc(PUnicodeChar(S2),temp,Size); + res:=temp; + end; +end; +{$endif FPC_STRTOSHORTSTRINGPROC} + + +Function fpc_ShortStr_To_UnicodeStr (Const S2 : ShortString): UnicodeString;compilerproc; +{ + Converts a ShortString to a UnicodeString; +} +Var + Size : SizeInt; +begin + result:=''; + Size:=Length(S2); + if Size>0 then + begin + widestringmanager.Ansi2UnicodeMoveProc(PChar(@S2[1]),result,Size); + { Terminating Zero } + PUnicodeChar(Pointer(fpc_ShortStr_To_UnicodeStr)+Size*sizeof(UnicodeChar))^:=#0; + end; +end; + + +Function fpc_UnicodeStr_To_AnsiStr (const S2 : UnicodeString): AnsiString; compilerproc; +{ + Converts a UnicodeString to an AnsiString +} +Var + Size : SizeInt; +begin + result:=''; + Size:=Length(S2); + if Size>0 then + widestringmanager.Unicode2AnsiMoveProc(PUnicodeChar(Pointer(S2)),result,Size); +end; + + +Function fpc_AnsiStr_To_UnicodeStr (Const S2 : AnsiString): UnicodeString; compilerproc; +{ + Converts an AnsiString to a UnicodeString; +} +Var + Size : SizeInt; +begin + result:=''; + Size:=Length(S2); + if Size>0 then + widestringmanager.Ansi2UnicodeMoveProc(PChar(S2),result,Size); +end; + + +Function fpc_UnicodeStr_To_WideStr (const S2 : UnicodeString): WideString; compilerproc; + begin + SetLength(Result,Length(S2)); + Move(pointer(S2)^,Pointer(Result)^,Length(S2)*sizeof(WideChar)); + end; + + +Function fpc_WideStr_To_UnicodeStr (Const S2 : WideString): UnicodeString; compilerproc; + begin + SetLength(Result,Length(S2)); + Move(pointer(S2)^,Pointer(Result)^,Length(S2)*sizeof(WideChar)); + end; + + +Function fpc_PUnicodeChar_To_AnsiStr(const p : punicodechar): ansistring; compilerproc; +var + Size : SizeInt; +begin + result:=''; + if p=nil then + exit; + Size := IndexWord(p^, -1, 0); + if Size>0 then + widestringmanager.Unicode2AnsiMoveProc(P,result,Size); +end; + + +Function fpc_PUnicodeChar_To_UnicodeStr(const p : punicodechar): unicodestring; compilerproc; +var + Size : SizeInt; +begin + result:=''; + if p=nil then + exit; + Size := IndexWord(p^, -1, 0); + Setlength(result,Size); + if Size>0 then + begin + Move(p^,PUnicodeChar(Pointer(result))^,Size*sizeof(UnicodeChar)); + { Terminating Zero } + PUnicodeChar(Pointer(result)+Size*sizeof(UnicodeChar))^:=#0; + end; +end; + + +Function fpc_PWideChar_To_UnicodeStr(const p : pwidechar): unicodestring; compilerproc; +var + Size : SizeInt; +begin + result:=''; + if p=nil then + exit; + Size := IndexWord(p^, -1, 0); + Setlength(result,Size); + if Size>0 then + begin + Move(p^,PUnicodeChar(Pointer(result))^,Size*sizeof(UnicodeChar)); + { Terminating Zero } + PUnicodeChar(Pointer(result)+Size*sizeof(UnicodeChar))^:=#0; + end; +end; + + +{$ifndef FPC_STRTOSHORTSTRINGPROC} +Function fpc_PUnicodeChar_To_ShortStr(const p : punicodechar): shortstring; compilerproc; +var + Size : SizeInt; + temp: ansistring; +begin + result:=''; + if p=nil then + exit; + Size := IndexWord(p^, $7fffffff, 0); + if Size>0 then + begin + widestringmanager.Unicode2AnsiMoveProc(p,temp,Size); + result:=temp; + end; +end; +{$else FPC_STRTOSHORTSTRINGPROC} +procedure fpc_PUnicodeChar_To_ShortStr(out res : shortstring;const p : punicodechar); compilerproc; +var + Size : SizeInt; + temp: ansistring; +begin + res:=''; + if p=nil then + exit; + Size:=IndexWord(p^, high(PtrInt), 0); + if Size>0 then + begin + widestringmanager.Unicode2AnsiMoveProc(p,temp,Size); + res:=temp; + end; +end; +{$endif FPC_STRTOSHORTSTRINGPROC} + + +Function fpc_PWideChar_To_AnsiStr(const p : pwidechar): ansistring; compilerproc; +var + Size : SizeInt; +begin + result:=''; + if p=nil then + exit; + Size := IndexWord(p^, -1, 0); + if Size>0 then + widestringmanager.Wide2AnsiMoveProc(P,result,Size); +end; + + +{$ifndef FPC_STRTOSHORTSTRINGPROC} +Function fpc_PWideChar_To_ShortStr(const p : pwidechar): shortstring; compilerproc; +var + Size : SizeInt; + temp: ansistring; +begin + result:=''; + if p=nil then + exit; + Size := IndexWord(p^, $7fffffff, 0); + if Size>0 then + begin + widestringmanager.Wide2AnsiMoveProc(p,temp,Size); + result:=temp; + end; +end; +{$else FPC_STRTOSHORTSTRINGPROC} +procedure fpc_PWideChar_To_ShortStr(out res : shortstring;const p : pwidechar); compilerproc; +var + Size : SizeInt; + temp: ansistring; +begin + res:=''; + if p=nil then + exit; + Size:=IndexWord(p^, high(PtrInt), 0); + if Size>0 then + begin + widestringmanager.Wide2AnsiMoveProc(p,temp,Size); + res:=temp; + end; +end; +{$endif FPC_STRTOSHORTSTRINGPROC} + + +{ checked against the ansistring routine, 2001-05-27 (FK) } +Procedure fpc_UnicodeStr_Assign (Var S1 : Pointer;S2 : Pointer);[Public,Alias:'FPC_UNICODESTR_ASSIGN']; compilerproc; +{ + Assigns S2 to S1 (S1:=S2), taking in account reference counts. +} +begin + If S2<>nil then + If PUnicodeRec(S2-UnicodeFirstOff)^.Ref>0 then + inclocked(PUnicodeRec(S2-UnicodeFirstOff)^.ref); + { Decrease the reference count on the old S1 } + fpc_unicodestr_decr_ref (S1); + s1:=s2; +end; + + +{ alias for internal use } +Procedure fpc_UnicodeStr_Assign (Var S1 : Pointer;S2 : Pointer);[external name 'FPC_UNICODESTR_ASSIGN']; + +{$ifndef STR_CONCAT_PROCS} + +function fpc_UnicodeStr_Concat (const S1,S2 : UnicodeString): UnicodeString; compilerproc; +Var + Size,Location : SizeInt; + pc : punicodechar; +begin + { only assign if s1 or s2 is empty } + if (S1='') then + begin + result:=s2; + exit; + end; + if (S2='') then + begin + result:=s1; + exit; + end; + Location:=Length(S1); + Size:=length(S2); + SetLength(result,Size+Location); + pc:=punicodechar(result); + Move(S1[1],pc^,Location*sizeof(UnicodeChar)); + inc(pc,location); + Move(S2[1],pc^,(Size+1)*sizeof(UnicodeChar)); +end; + + +function fpc_UnicodeStr_Concat_multi (const sarr:array of Unicodestring): unicodestring; compilerproc; +Var + i : Longint; + p : pointer; + pc : punicodechar; + Size,NewSize : SizeInt; +begin + { First calculate size of the result so we can do + a single call to SetLength() } + NewSize:=0; + for i:=low(sarr) to high(sarr) do + inc(Newsize,length(sarr[i])); + SetLength(result,NewSize); + pc:=punicodechar(result); + for i:=low(sarr) to high(sarr) do + begin + p:=pointer(sarr[i]); + if assigned(p) then + begin + Size:=length(unicodestring(p)); + Move(punicodechar(p)^,pc^,(Size+1)*sizeof(UnicodeChar)); + inc(pc,size); + end; + end; +end; + +{$else STR_CONCAT_PROCS} + +procedure fpc_UnicodeStr_Concat (var DestS:Unicodestring;const S1,S2 : UnicodeString); compilerproc; +Var + Size,Location : SizeInt; + same : boolean; +begin + { only assign if s1 or s2 is empty } + if (S1='') then + begin + DestS:=s2; + exit; + end; + if (S2='') then + begin + DestS:=s1; + exit; + end; + Location:=Length(S1); + Size:=length(S2); + { Use Pointer() typecasts to prevent extra conversion code } + if Pointer(DestS)=Pointer(S1) then + begin + same:=Pointer(S1)=Pointer(S2); + SetLength(DestS,Size+Location); + if same then + Move(Pointer(DestS)^,(Pointer(DestS)+Location*sizeof(UnicodeChar))^,(Size)*sizeof(UnicodeChar)) + else + Move(Pointer(S2)^,(Pointer(DestS)+Location*sizeof(UnicodeChar))^,(Size+1)*sizeof(UnicodeChar)); + end + else if Pointer(DestS)=Pointer(S2) then + begin + SetLength(DestS,Size+Location); + Move(Pointer(DestS)^,(Pointer(DestS)+Location*sizeof(UnicodeChar))^,(Size+1)*sizeof(UnicodeChar)); + Move(Pointer(S1)^,Pointer(DestS)^,Location*sizeof(UnicodeChar)); + end + else + begin + DestS:=''; + SetLength(DestS,Size+Location); + Move(Pointer(S1)^,Pointer(DestS)^,Location*sizeof(UnicodeChar)); + Move(Pointer(S2)^,(Pointer(DestS)+Location*sizeof(UnicodeChar))^,(Size+1)*sizeof(UnicodeChar)); + end; +end; + + +procedure fpc_UnicodeStr_Concat_multi (var DestS:Unicodestring;const sarr:array of Unicodestring); compilerproc; +Var + i : Longint; + p,pc : pointer; + Size,NewLen : SizeInt; + lowstart : longint; + destcopy : pointer; + OldDestLen : SizeInt; +begin + if high(sarr)=0 then + begin + DestS:=''; + exit; + end; + destcopy:=nil; + lowstart:=low(sarr); + if Pointer(DestS)=Pointer(sarr[lowstart]) then + inc(lowstart); + { Check for another reuse, then we can't use + the append optimization } + for i:=lowstart to high(sarr) do + begin + if Pointer(DestS)=Pointer(sarr[i]) then + begin + { if DestS is used somewhere in the middle of the expression, + we need to make sure the original string still exists after + we empty/modify DestS. + This trick only works with reference counted strings. Therefor + this optimization is disabled for WINLIKEUNICODESTRING } + destcopy:=pointer(dests); + fpc_UnicodeStr_Incr_Ref(destcopy); + lowstart:=low(sarr); + break; + end; + end; + { Start with empty DestS if we start with concatting + the first array element } + if lowstart=low(sarr) then + DestS:=''; + OldDestLen:=length(DestS); + { Calculate size of the result so we can do + a single call to SetLength() } + NewLen:=0; + for i:=low(sarr) to high(sarr) do + inc(NewLen,length(sarr[i])); + SetLength(DestS,NewLen); + { Concat all strings, except the string we already + copied in DestS } + pc:=Pointer(DestS)+OldDestLen*sizeof(UnicodeChar); + for i:=lowstart to high(sarr) do + begin + p:=pointer(sarr[i]); + if assigned(p) then + begin + Size:=length(unicodestring(p)); + Move(p^,pc^,(Size+1)*sizeof(UnicodeChar)); + inc(pc,size*sizeof(UnicodeChar)); + end; + end; + fpc_UnicodeStr_Decr_Ref(destcopy); +end; + +{$endif STR_CONCAT_PROCS} + +Function fpc_Char_To_UChar(const c : Char): UnicodeChar; compilerproc; +var + w: unicodestring; +begin + widestringmanager.Ansi2UnicodeMoveProc(@c, w, 1); + fpc_Char_To_UChar:= w[1]; +end; + + + +Function fpc_Char_To_UnicodeStr(const c : Char): UnicodeString; compilerproc; +{ + Converts a Char to a UnicodeString; +} +begin + Setlength(fpc_Char_To_UnicodeStr,1); + fpc_Char_To_UnicodeStr[1]:=c; + { Terminating Zero } + PUnicodeChar(Pointer(fpc_Char_To_UnicodeStr)+sizeof(UnicodeChar))^:=#0; +end; + + +Function fpc_UChar_To_Char(const c : UnicodeChar): Char; compilerproc; +{ + Converts a UnicodeChar to a Char; +} +var + s: ansistring; +begin + widestringmanager.Unicode2AnsiMoveProc(@c, s, 1); + if length(s)=1 then + fpc_UChar_To_Char:= s[1] + else + fpc_UChar_To_Char:='?'; +end; + + +Function fpc_WChar_To_UnicodeStr(const c : WideChar): UnicodeString; compilerproc; +{ + Converts a WideChar to a UnicodeString; +} +begin + Setlength (Result,1); + Result[1]:= c; +end; + + +Function fpc_Char_To_WChar(const c : Char): WideChar; compilerproc; +var + w: widestring; +begin + widestringmanager.Ansi2WideMoveProc(@c, w, 1); + fpc_Char_To_WChar:= w[1]; +end; + + +Function fpc_WChar_To_Char(const c : WideChar): Char; compilerproc; +{ + Converts a WideChar to a Char; +} +var + s: ansistring; +begin + widestringmanager.Wide2AnsiMoveProc(@c, s, 1); + if length(s)=1 then + fpc_WChar_To_Char:= s[1] + else + fpc_WChar_To_Char:='?'; +end; + + +{$ifndef FPC_STRTOSHORTSTRINGPROC} +Function fpc_WChar_To_ShortStr(const c : WideChar): ShortString; compilerproc; +{ + Converts a WideChar to a ShortString; +} +var + s: ansistring; +begin + widestringmanager.Wide2AnsiMoveProc(@c, s, 1); + fpc_WChar_To_ShortStr:= s; +end; +{$else FPC_STRTOSHORTSTRINGPROC} +procedure fpc_WChar_To_ShortStr(out res : shortstring;const c : WideChar) compilerproc; +{ + Converts a WideChar to a ShortString; +} +var + s: ansistring; +begin + widestringmanager.Wide2AnsiMoveProc(@c,s,1); + res:=s; +end; +{$endif FPC_STRTOSHORTSTRINGPROC} + + +Function fpc_UChar_To_UnicodeStr(const c : UnicodeChar): UnicodeString; compilerproc; +{ + Converts a UnicodeChar to a UnicodeString; +} +begin + Setlength (fpc_UChar_To_UnicodeStr,1); + fpc_UChar_To_UnicodeStr[1]:= c; +end; + + +Function fpc_UChar_To_AnsiStr(const c : UnicodeChar): AnsiString; compilerproc; +{ + Converts a UnicodeChar to a AnsiString; +} +begin + widestringmanager.Unicode2AnsiMoveProc(@c, fpc_UChar_To_AnsiStr, 1); +end; + + +{$ifndef FPC_STRTOSHORTSTRINGPROC} +Function fpc_UChar_To_ShortStr(const c : UnicodeChar): ShortString; compilerproc; +{ + Converts a UnicodeChar to a ShortString; +} +var + s: ansistring; +begin + widestringmanager.Unicode2AnsiMoveProc(@c, s, 1); + fpc_UChar_To_ShortStr:= s; +end; +{$else FPC_STRTOSHORTSTRINGPROC} +procedure fpc_UChar_To_ShortStr(out res : shortstring;const c : UnicodeChar) compilerproc; +{ + Converts a UnicodeChar to a ShortString; +} +var + s: ansistring; +begin + widestringmanager.Unicode2AnsiMoveProc(@c,s,1); + res:=s; +end; +{$endif FPC_STRTOSHORTSTRINGPROC} + + +Function fpc_PChar_To_UnicodeStr(const p : pchar): UnicodeString; compilerproc; +Var + L : SizeInt; +begin + if (not assigned(p)) or (p[0]=#0) Then + begin + fpc_pchar_to_unicodestr := ''; + exit; + end; + l:=IndexChar(p^,-1,#0); + widestringmanager.Ansi2UnicodeMoveProc(P,fpc_PChar_To_UnicodeStr,l); +end; + + +Function fpc_CharArray_To_UnicodeStr(const arr: array of char; zerobased: boolean = true): UnicodeString; compilerproc; +var + i : SizeInt; +begin + if (zerobased) then + begin + if (arr[0]=#0) Then + begin + fpc_chararray_to_unicodestr := ''; + exit; + end; + i:=IndexChar(arr,high(arr)+1,#0); + if i = -1 then + i := high(arr)+1; + end + else + i := high(arr)+1; + SetLength(fpc_CharArray_To_UnicodeStr,i); + widestringmanager.Ansi2UnicodeMoveProc (pchar(@arr),fpc_CharArray_To_UnicodeStr,i); +end; + + +{$ifndef FPC_STRTOSHORTSTRINGPROC} +function fpc_UnicodeCharArray_To_ShortStr(const arr: array of unicodechar; zerobased: boolean = true): shortstring;[public,alias:'FPC_UNICODECHARARRAY_TO_SHORTSTR']; compilerproc; +var + l: longint; + index: longint; + len: byte; + temp: ansistring; +begin + l := high(arr)+1; + if l>=256 then + l:=255 + else if l<0 then + l:=0; + if zerobased then + begin + index:=IndexWord(arr[0],l,0); + if (index < 0) then + len := l + else + len := index; + end + else + len := l; + widestringmanager.Unicode2AnsiMoveProc (punicodechar(@arr),temp,len); + fpc_UnicodeCharArray_To_ShortStr := temp; +end; +{$else FPC_STRTOSHORTSTRINGPROC} +procedure fpc_UnicodeCharArray_To_ShortStr(out res : shortstring;const arr: array of unicodechar; zerobased: boolean = true);[public,alias:'FPC_UNICODECHARARRAY_TO_SHORTSTR']; compilerproc; +var + l: longint; + index: ptrint; + len: byte; + temp: ansistring; +begin + l := high(arr)+1; + if l>=high(res)+1 then + l:=high(res) + else if l<0 then + l:=0; + if zerobased then + begin + index:=IndexWord(arr[0],l,0); + if index<0 then + len:=l + else + len:=index; + end + else + len:=l; + widestringmanager.Unicode2AnsiMoveProc (punicodechar(@arr),temp,len); + res:=temp; +end; +{$endif FPC_STRTOSHORTSTRINGPROC} + +Function fpc_UnicodeCharArray_To_AnsiStr(const arr: array of unicodechar; zerobased: boolean = true): AnsiString; compilerproc; +var + i : SizeInt; +begin + if (zerobased) then + begin + i:=IndexWord(arr,high(arr)+1,0); + if i = -1 then + i := high(arr)+1; + end + else + i := high(arr)+1; + SetLength(fpc_UnicodeCharArray_To_AnsiStr,i); + widestringmanager.Unicode2AnsiMoveProc (punicodechar(@arr),fpc_UnicodeCharArray_To_AnsiStr,i); +end; + + +Function fpc_UnicodeCharArray_To_UnicodeStr(const arr: array of unicodechar; zerobased: boolean = true): UnicodeString; compilerproc; +var + i : SizeInt; +begin + if (zerobased) then + begin + i:=IndexWord(arr,high(arr)+1,0); + if i = -1 then + i := high(arr)+1; + end + else + i := high(arr)+1; + SetLength(fpc_UnicodeCharArray_To_UnicodeStr,i); + Move(arr[0], Pointer(fpc_UnicodeCharArray_To_UnicodeStr)^,i*sizeof(UnicodeChar)); +end; + + +Function fpc_WideCharArray_To_UnicodeStr(const arr: array of widechar; zerobased: boolean = true): UnicodeString; compilerproc; +var + i : SizeInt; +begin + if (zerobased) then + begin + i:=IndexWord(arr,high(arr)+1,0); + if i = -1 then + i := high(arr)+1; + end + else + i := high(arr)+1; + SetLength(fpc_WideCharArray_To_UnicodeStr,i); + Move(arr[0], Pointer(fpc_WideCharArray_To_UnicodeStr)^,i*sizeof(WideChar)); +end; + + +{ due to their names, the following procedures should be in wstrings.inc, + however, the compiler generates code using this functions on all platforms } +{$ifndef FPC_STRTOSHORTSTRINGPROC} +function fpc_WideCharArray_To_ShortStr(const arr: array of widechar; zerobased: boolean = true): shortstring;[public,alias:'FPC_WIDECHARARRAY_TO_SHORTSTR']; compilerproc; +var + l: longint; + index: longint; + len: byte; + temp: ansistring; +begin + l := high(arr)+1; + if l>=256 then + l:=255 + else if l<0 then + l:=0; + if zerobased then + begin + index:=IndexWord(arr[0],l,0); + if (index < 0) then + len := l + else + len := index; + end + else + len := l; + widestringmanager.Wide2AnsiMoveProc (pwidechar(@arr),temp,len); + fpc_WideCharArray_To_ShortStr := temp; +end; +{$else FPC_STRTOSHORTSTRINGPROC} +procedure fpc_WideCharArray_To_ShortStr(out res : shortstring;const arr: array of widechar; zerobased: boolean = true);[public,alias:'FPC_WIDECHARARRAY_TO_SHORTSTR']; compilerproc; +var + l: longint; + index: ptrint; + len: byte; + temp: ansistring; +begin + l := high(arr)+1; + if l>=high(res)+1 then + l:=high(res) + else if l<0 then + l:=0; + if zerobased then + begin + index:=IndexWord(arr[0],l,0); + if index<0 then + len:=l + else + len:=index; + end + else + len:=l; + widestringmanager.Wide2AnsiMoveProc (pwidechar(@arr),temp,len); + res:=temp; +end; +{$endif FPC_STRTOSHORTSTRINGPROC} + +Function fpc_WideCharArray_To_AnsiStr(const arr: array of widechar; zerobased: boolean = true): AnsiString; compilerproc; +var + i : SizeInt; +begin + if (zerobased) then + begin + i:=IndexWord(arr,high(arr)+1,0); + if i = -1 then + i := high(arr)+1; + end + else + i := high(arr)+1; + SetLength(fpc_WideCharArray_To_AnsiStr,i); + widestringmanager.Wide2AnsiMoveProc (pwidechar(@arr),fpc_WideCharArray_To_AnsiStr,i); +end; + +Function fpc_WideCharArray_To_WideStr(const arr: array of widechar; zerobased: boolean = true): WideString; compilerproc; +var + i : SizeInt; +begin + if (zerobased) then + begin + i:=IndexWord(arr,high(arr)+1,0); + if i = -1 then + i := high(arr)+1; + end + else + i := high(arr)+1; + SetLength(fpc_WideCharArray_To_WideStr,i); + Move(arr[0], Pointer(fpc_WideCharArray_To_WideStr)^,i*sizeof(WideChar)); +end; + +{$ifndef FPC_STRTOCHARARRAYPROC} + +{ inside the compiler, the resulttype is modified to that of the actual } +{ chararray we're converting to (JM) } +function fpc_unicodestr_to_chararray(arraysize: SizeInt; const src: UnicodeString): fpc_big_chararray;[public,alias: 'FPC_UNICODESTR_TO_CHARARRAY']; compilerproc; +var + len: SizeInt; + temp: ansistring; +begin + len := length(src); + { make sure we don't dereference src if it can be nil (JM) } + if len > 0 then + widestringmanager.unicode2ansimoveproc(punicodechar(@src[1]),temp,len); + len := length(temp); + if len > arraysize then + len := arraysize; +{$r-} + move(temp[1],fpc_unicodestr_to_chararray[0],len); + fillchar(fpc_unicodestr_to_chararray[len],arraysize-len,0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + + +{ inside the compiler, the resulttype is modified to that of the actual } +{ unicodechararray we're converting to (JM) } +function fpc_unicodestr_to_unicodechararray(arraysize: SizeInt; const src: UnicodeString): fpc_big_unicodechararray;[public,alias: 'FPC_UNICODESTR_TO_UNICODECHARARRAY']; compilerproc; +var + len: SizeInt; +begin + len := length(src); + if len > arraysize then + len := arraysize; +{$r-} + { make sure we don't try to access element 1 of the ansistring if it's nil } + if len > 0 then + move(src[1],fpc_unicodestr_to_unicodechararray[0],len*SizeOf(UnicodeChar)); + fillchar(fpc_unicodestr_to_unicodechararray[len],(arraysize-len)*SizeOf(UnicodeChar),0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + + +{ inside the compiler, the resulttype is modified to that of the actual } +{ chararray we're converting to (JM) } +function fpc_ansistr_to_unicodechararray(arraysize: SizeInt; const src: AnsiString): fpc_big_unicodechararray;[public,alias: 'FPC_ANSISTR_TO_UNICODECHARARRAY']; compilerproc; +var + len: SizeInt; + temp: unicodestring; +begin + len := length(src); + { make sure we don't dereference src if it can be nil (JM) } + if len > 0 then + widestringmanager.ansi2unicodemoveproc(pchar(@src[1]),temp,len); + len := length(temp); + if len > arraysize then + len := arraysize; + +{$r-} + move(temp[1],fpc_ansistr_to_unicodechararray[0],len*sizeof(unicodechar)); + fillchar(fpc_ansistr_to_unicodechararray[len],(arraysize-len)*SizeOf(UnicodeChar),0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + +function fpc_shortstr_to_unicodechararray(arraysize: SizeInt; const src: ShortString): fpc_big_unicodechararray;[public,alias: 'FPC_SHORTSTR_TO_UNICODECHARARRAY']; compilerproc; +var + len: longint; + temp : unicodestring; +begin + len := length(src); + { make sure we don't access char 1 if length is 0 (JM) } + if len > 0 then + widestringmanager.ansi2unicodemoveproc(pchar(@src[1]),temp,len); + len := length(temp); + if len > arraysize then + len := arraysize; +{$r-} + move(temp[1],fpc_shortstr_to_unicodechararray[0],len*sizeof(unicodechar)); + fillchar(fpc_shortstr_to_unicodechararray[len],(arraysize-len)*SizeOf(UnicodeChar),0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + +{$else ndef FPC_STRTOCHARARRAYPROC} + +procedure fpc_unicodestr_to_chararray(out res: array of char; const src: UnicodeString); compilerproc; +var + len: SizeInt; + temp: ansistring; +begin + len := length(src); + { make sure we don't dereference src if it can be nil (JM) } + if len > 0 then + widestringmanager.unicode2ansimoveproc(punicodechar(@src[1]),temp,len); + len := length(temp); + if len > length(res) then + len := length(res); +{$r-} + move(temp[1],res[0],len); + fillchar(res[len],length(res)-len,0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + + +procedure fpc_unicodestr_to_unicodechararray(out res: array of unicodechar; const src: UnicodeString); compilerproc; +var + len: SizeInt; +begin + len := length(src); + if len > length(res) then + len := length(res); +{$r-} + { make sure we don't try to access element 1 of the ansistring if it's nil } + if len > 0 then + move(src[1],res[0],len*SizeOf(UnicodeChar)); + fillchar(res[len],(length(res)-len)*SizeOf(UnicodeChar),0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + + +procedure fpc_ansistr_to_unicodechararray(out res: array of unicodechar; const src: AnsiString); compilerproc; +var + len: SizeInt; + temp: unicodestring; +begin + len := length(src); + { make sure we don't dereference src if it can be nil (JM) } + if len > 0 then + widestringmanager.ansi2unicodemoveproc(pchar(@src[1]),temp,len); + len := length(temp); + if len > length(res) then + len := length(res); + +{$r-} + move(temp[1],res[0],len*sizeof(unicodechar)); + fillchar(res[len],(length(res)-len)*SizeOf(UnicodeChar),0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + +procedure fpc_shortstr_to_unicodechararray(out res: array of unicodechar; const src: ShortString); compilerproc; +var + len: longint; + temp : unicodestring; +begin + len := length(src); + { make sure we don't access char 1 if length is 0 (JM) } + if len > 0 then + widestringmanager.ansi2unicodemoveproc(pchar(@src[1]),temp,len); + len := length(temp); + if len > length(res) then + len := length(res); +{$r-} + move(temp[1],res[0],len*sizeof(unicodechar)); + fillchar(res[len],(length(res)-len)*SizeOf(UnicodeChar),0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + +procedure fpc_ansistr_to_widechararray(out res: array of widechar; const src: AnsiString); compilerproc; +var + len: SizeInt; + temp: widestring; +begin + len := length(src); + { make sure we don't dereference src if it can be nil (JM) } + if len > 0 then + widestringmanager.ansi2widemoveproc(pchar(@src[1]),temp,len); + len := length(temp); + if len > length(res) then + len := length(res); + +{$r-} + move(temp[1],res[0],len*sizeof(widechar)); + fillchar(res[len],(length(res)-len)*SizeOf(WideChar),0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + +procedure fpc_shortstr_to_widechararray(out res: array of widechar; const src: ShortString); compilerproc; +var + len: longint; + temp : widestring; +begin + len := length(src); + { make sure we don't access char 1 if length is 0 (JM) } + if len > 0 then + widestringmanager.ansi2widemoveproc(pchar(@src[1]),temp,len); + len := length(temp); + if len > length(res) then + len := length(res); +{$r-} + move(temp[1],res[0],len*sizeof(widechar)); + fillchar(res[len],(length(res)-len)*SizeOf(WideChar),0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + + +procedure fpc_unicodestr_to_widechararray(out res: array of widechar; const src: UnicodeString); compilerproc; +var + len: SizeInt; +begin + len := length(src); + if len > length(res) then + len := length(res); +{$r-} + { make sure we don't try to access element 1 of the widestring if it's nil } + if len > 0 then + move(src[1],res[0],len*SizeOf(WideChar)); + fillchar(res[len],(length(res)-len)*SizeOf(WideChar),0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + + +{$endif ndef FPC_STRTOCHARARRAYPROC} + +Function fpc_UnicodeStr_Compare(const S1,S2 : UnicodeString): SizeInt;[Public,Alias : 'FPC_UNICODESTR_COMPARE']; compilerproc; +{ + Compares 2 UnicodeStrings; + The result is + <0 if S1<S2 + 0 if S1=S2 + >0 if S1>S2 +} +Var + MaxI,Temp : SizeInt; +begin + if pointer(S1)=pointer(S2) then + begin + fpc_UnicodeStr_Compare:=0; + exit; + end; + Maxi:=Length(S1); + temp:=Length(S2); + If MaxI>Temp then + MaxI:=Temp; + Temp:=CompareWord(S1[1],S2[1],MaxI); + if temp=0 then + temp:=Length(S1)-Length(S2); + fpc_UnicodeStr_Compare:=Temp; +end; + +Function fpc_UnicodeStr_Compare_Equal(const S1,S2 : UnicodeString): SizeInt;[Public,Alias : 'FPC_UNICODESTR_COMPARE_EQUAL']; compilerproc; +{ + Compares 2 UnicodeStrings for equality only; + The result is + 0 if S1=S2 + <>0 if S1<>S2 +} +Var + MaxI : SizeInt; +begin + if pointer(S1)=pointer(S2) then + exit(0); + Maxi:=Length(S1); + If MaxI<>Length(S2) then + exit(-1) + else + exit(CompareWord(S1[1],S2[1],MaxI)); +end; + +Procedure fpc_UnicodeStr_CheckZero(p : pointer);[Public,Alias : 'FPC_UNICODESTR_CHECKZERO']; compilerproc; +begin + if p=nil then + HandleErrorFrame(201,get_frame); +end; + + +Procedure fpc_UnicodeStr_CheckRange(len,index : SizeInt);[Public,Alias : 'FPC_UNICODESTR_RANGECHECK']; compilerproc; +begin + if (index>len div 2) or (Index<1) then + HandleErrorFrame(201,get_frame); +end; + +Procedure fpc_UnicodeStr_SetLength(Var S : UnicodeString; l : SizeInt);[Public,Alias : 'FPC_UNICODESTR_SETLENGTH']; compilerproc; +{ + Sets The length of string S to L. + Makes sure S is unique, and contains enough room. +} +Var + Temp : Pointer; + movelen: SizeInt; +begin + if (l>0) then + begin + if Pointer(S)=nil then + begin + { Need a complete new string...} + Pointer(s):=NewUnicodeString(l); + end + { windows doesn't support reallocing unicodestrings, this code + is anyways subject to be removed because unicodestrings shouldn't be + ref. counted anymore (FK) } + else + if (PUnicodeRec(Pointer(S)-UnicodeFirstOff)^.Ref = 1) then + begin + Dec(Pointer(S),UnicodeFirstOff); + if SizeUInt(L*sizeof(UnicodeChar)+UnicodeRecLen)>MemSize(Pointer(S)) then + reallocmem(pointer(S), L*sizeof(UnicodeChar)+UnicodeRecLen); + Inc(Pointer(S), UnicodeFirstOff); + end + else + begin + { Reallocation is needed... } + Temp:=Pointer(NewUnicodeString(L)); + if Length(S)>0 then + begin + if l < succ(length(s)) then + movelen := l + { also move terminating null } + else + movelen := succ(length(s)); + Move(Pointer(S)^,Temp^,movelen * Sizeof(UnicodeChar)); + end; + fpc_unicodestr_decr_ref(Pointer(S)); + Pointer(S):=Temp; + end; + { Force nil termination in case it gets shorter } + PWord(Pointer(S)+l*sizeof(UnicodeChar))^:=0; + PUnicodeRec(Pointer(S)-UnicodeFirstOff)^.Len:=l*sizeof(UnicodeChar); + end + else + begin + { Length=0 } + if Pointer(S)<>nil then + fpc_unicodestr_decr_ref (Pointer(S)); + Pointer(S):=Nil; + end; +end; + +{***************************************************************************** + Public functions, In interface. +*****************************************************************************} + +function UnicodeCharToString(S : PUnicodeChar) : AnsiString; + begin + result:=UnicodeCharLenToString(s,Length(UnicodeString(s))); + end; + +function StringToUnicodeChar(const Src : AnsiString;Dest : PUnicodeChar;DestSize : SizeInt) : PUnicodeChar; + var + temp:unicodestring; + begin + widestringmanager.Ansi2UnicodeMoveProc(PChar(Src),temp,Length(Src)); + if Length(temp)<DestSize then + move(temp[1],Dest^,Length(temp)*SizeOf(UnicodeChar)) + else + move(temp[1],Dest^,(DestSize-1)*SizeOf(UnicodeChar)); + + Dest[DestSize-1]:=#0; + + result:=Dest; + + end; + + +function WideCharToString(S : PWideChar) : AnsiString; + begin + result:=WideCharLenToString(s,Length(WideString(s))); + end; + + +function StringToWideChar(const Src : AnsiString;Dest : PWideChar;DestSize : SizeInt) : PWideChar; + var + temp:widestring; + begin + widestringmanager.Ansi2WideMoveProc(PChar(Src),temp,Length(Src)); + if Length(temp)<DestSize then + move(temp[1],Dest^,Length(temp)*SizeOf(WideChar)) + else + move(temp[1],Dest^,(DestSize-1)*SizeOf(WideChar)); + + Dest[DestSize-1]:=#0; + + result:=Dest; + + end; + + +function UnicodeCharLenToString(S : PUnicodeChar;Len : SizeInt) : AnsiString; + begin + //SetLength(result,Len); + widestringmanager.Unicode2AnsiMoveproc(S,result,Len); + end; + + +procedure UnicodeCharLenToStrVar(Src : PUnicodeChar;Len : SizeInt;out Dest : AnsiString); + begin + Dest:=UnicodeCharLenToString(Src,Len); + end; + + +procedure UnicodeCharToStrVar(S : PUnicodeChar;out Dest : AnsiString); + begin + Dest:=UnicodeCharToString(S); + end; + + +function WideCharLenToString(S : PWideChar;Len : SizeInt) : AnsiString; + begin + //SetLength(result,Len); + widestringmanager.Wide2AnsiMoveproc(S,result,Len); + end; + + +procedure WideCharLenToStrVar(Src : PWideChar;Len : SizeInt;out Dest : AnsiString); + begin + Dest:=WideCharLenToString(Src,Len); + end; + + +procedure WideCharToStrVar(S : PWideChar;out Dest : AnsiString); + begin + Dest:=WideCharToString(S); + end; + + +Function fpc_unicodestr_Unique(Var S : Pointer): Pointer; [Public,Alias : 'FPC_UNICODESTR_UNIQUE']; compilerproc; +{ + Make sure reference count of S is 1, + using copy-on-write semantics. +} +Var + SNew : Pointer; + L : SizeInt; +begin + pointer(result) := pointer(s); + If Pointer(S)=Nil then + exit; + if PUnicodeRec(Pointer(S)-UnicodeFirstOff)^.Ref<>1 then + begin + L:=PUnicodeRec(Pointer(S)-UnicodeFirstOff)^.len div sizeof(UnicodeChar); + SNew:=NewUnicodeString (L); + Move (PUnicodeChar(S)^,SNew^,(L+1)*sizeof(UnicodeChar)); + PUnicodeRec(SNew-UnicodeFirstOff)^.len:=L * sizeof(UnicodeChar); + fpc_unicodestr_decr_ref (Pointer(S)); { Thread safe } + pointer(S):=SNew; + pointer(result):=SNew; + end; +end; + + +Function Fpc_UnicodeStr_Copy (Const S : UnicodeString; Index,Size : SizeInt) : UnicodeString;compilerproc; +var + ResultAddress : Pointer; +begin + ResultAddress:=Nil; + dec(index); + if Index < 0 then + Index := 0; + { Check Size. Accounts for Zero-length S, the double check is needed because + Size can be maxint and will get <0 when adding index } + if (Size>Length(S)) or + (Index+Size>Length(S)) then + Size:=Length(S)-Index; + If Size>0 then + begin + If Index<0 Then + Index:=0; + ResultAddress:=Pointer(NewUnicodeString (Size)); + if ResultAddress<>Nil then + begin + Move (PUnicodeChar(S)[Index],ResultAddress^,Size*sizeof(UnicodeChar)); + PUnicodeRec(ResultAddress-UnicodeFirstOff)^.Len:=Size*sizeof(UnicodeChar); + PUnicodeChar(ResultAddress+Size*sizeof(UnicodeChar))^:=#0; + end; + end; + fpc_unicodestr_decr_ref(Pointer(fpc_unicodestr_copy)); + Pointer(fpc_unicodestr_Copy):=ResultAddress; +end; + + +Function Pos (Const Substr : UnicodeString; Const Source : UnicodeString) : SizeInt; +var + i,MaxLen : SizeInt; + pc : punicodechar; +begin + Pos:=0; + if Length(SubStr)>0 then + begin + MaxLen:=Length(source)-Length(SubStr); + i:=0; + pc:=@source[1]; + while (i<=MaxLen) do + begin + inc(i); + if (SubStr[1]=pc^) and + (CompareWord(Substr[1],pc^,Length(SubStr))=0) then + begin + Pos:=i; + exit; + end; + inc(pc); + end; + end; +end; + + +{ Faster version for a unicodechar alone } +Function Pos (c : UnicodeChar; Const s : UnicodeString) : SizeInt; +var + i: SizeInt; + pc : punicodechar; +begin + pc:=@s[1]; + for i:=1 to length(s) do + begin + if pc^=c then + begin + pos:=i; + exit; + end; + inc(pc); + end; + pos:=0; +end; + + +Function Pos (c : AnsiString; Const s : UnicodeString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + result:=Pos(UnicodeString(c),s); + end; + + +Function Pos (c : ShortString; Const s : UnicodeString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + result:=Pos(UnicodeString(c),s); + end; + + +Function Pos (c : UnicodeString; Const s : AnsiString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + result:=Pos(c,UnicodeString(s)); + end; + +{ Faster version for a char alone. Must be implemented because } +{ pos(c: char; const s: shortstring) also exists, so otherwise } +{ using pos(char,pchar) will always call the shortstring version } +{ (exact match for first argument), also with $h+ (JM) } +Function Pos (c : Char; Const s : UnicodeString) : SizeInt; +var + i: SizeInt; + wc : unicodechar; + pc : punicodechar; +begin + wc:=c; + pc:=@s[1]; + for i:=1 to length(s) do + begin + if pc^=wc then + begin + pos:=i; + exit; + end; + inc(pc); + end; + pos:=0; +end; + + + +Procedure Delete (Var S : UnicodeString; Index,Size: SizeInt); +Var + LS : SizeInt; +begin + If Length(S)=0 then + exit; + if index<=0 then + exit; + LS:=PUnicodeRec(Pointer(S)-UnicodeFirstOff)^.Len div sizeof(UnicodeChar); + if (Index<=LS) and (Size>0) then + begin + UniqueString (S); + if Size+Index>LS then + Size:=LS-Index+1; + if Index+Size<=LS then + begin + Dec(Index); + Move(PUnicodeChar(S)[Index+Size],PUnicodeChar(S)[Index],(LS-Index-Size+1)*sizeof(UnicodeChar)); + end; + Setlength(s,LS-Size); + end; +end; + + +Procedure Insert (Const Source : UnicodeString; Var S : UnicodeString; Index : SizeInt); +var + Temp : UnicodeString; + LS : SizeInt; +begin + If Length(Source)=0 then + exit; + if index <= 0 then + index := 1; + Ls:=Length(S); + if index > LS then + index := LS+1; + Dec(Index); + Pointer(Temp) := NewUnicodeString(Length(Source)+LS); + SetLength(Temp,Length(Source)+LS); + If Index>0 then + move (PUnicodeChar(S)^,PUnicodeChar(Temp)^,Index*sizeof(UnicodeChar)); + Move (PUnicodeChar(Source)^,PUnicodeChar(Temp)[Index],Length(Source)*sizeof(UnicodeChar)); + If (LS-Index)>0 then + Move(PUnicodeChar(S)[Index],PUnicodeChar(temp)[Length(Source)+index],(LS-Index)*sizeof(UnicodeChar)); + S:=Temp; +end; + + +Function UpCase(c:UnicodeChar):UnicodeChar; +var + s : UnicodeString; +begin + s:=c; + result:=widestringmanager.UpperUnicodeStringProc(s)[1]; +end; + + +function UpCase(const s : UnicodeString) : UnicodeString; +begin + result:=widestringmanager.UpperUnicodeStringProc(s); +end; + + +Procedure SetString (Out S : UnicodeString; Buf : PUnicodeChar; Len : SizeInt); +var + BufLen: SizeInt; +begin + SetLength(S,Len); + If (Buf<>Nil) and (Len>0) then + begin + BufLen := IndexWord(Buf^, Len+1, 0); + If (BufLen>0) and (BufLen < Len) then + Len := BufLen; + Move (Buf[0],S[1],Len*sizeof(UnicodeChar)); + PUnicodeChar(Pointer(S)+Len*sizeof(UnicodeChar))^:=#0; + end; +end; + + +Procedure SetString (Out S : UnicodeString; Buf : PChar; Len : SizeInt); +var + BufLen: SizeInt; +begin + SetLength(S,Len); + If (Buf<>Nil) and (Len>0) then + begin + BufLen := IndexByte(Buf^, Len+1, 0); + If (BufLen>0) and (BufLen < Len) then + Len := BufLen; + widestringmanager.Ansi2UnicodeMoveProc(Buf,S,Len); + //PUnicodeChar(Pointer(S)+Len*sizeof(UnicodeChar))^:=#0; + end; +end; + + +{$ifndef FPUNONE} +Function fpc_Val_Real_UnicodeStr(Const S : UnicodeString; out Code : ValSInt): ValReal; [public, alias:'FPC_VAL_REAL_UNICODESTR']; compilerproc; +Var + SS : String; +begin + fpc_Val_Real_UnicodeStr := 0; + if length(S) > 255 then + code := 256 + else + begin + SS := S; + Val(SS,fpc_Val_Real_UnicodeStr,code); + end; +end; +{$endif} + +function fpc_val_enum_unicodestr(str2ordindex:pointer;const s:unicodestring;out code:valsint):longint;compilerproc; + +var ss:shortstring; + +begin + if length(s)>255 then + code:=256 + else + begin + ss:=s; + val(ss,fpc_val_enum_unicodestr,code); + end; +end; + +Function fpc_Val_Currency_UnicodeStr(Const S : UnicodeString; out Code : ValSInt): Currency; [public, alias:'FPC_VAL_CURRENCY_UNICODESTR']; compilerproc; +Var + SS : String; +begin + if length(S) > 255 then + begin + fpc_Val_Currency_UnicodeStr:=0; + code := 256; + end + else + begin + SS := S; + Val(SS,fpc_Val_Currency_UnicodeStr,code); + end; +end; + + +Function fpc_Val_UInt_UnicodeStr (Const S : UnicodeString; out Code : ValSInt): ValUInt; [public, alias:'FPC_VAL_UINT_UNICODESTR']; compilerproc; +Var + SS : ShortString; +begin + fpc_Val_UInt_UnicodeStr := 0; + if length(S) > 255 then + code := 256 + else + begin + SS := S; + Val(SS,fpc_Val_UInt_UnicodeStr,code); + end; +end; + + +Function fpc_Val_SInt_UnicodeStr (DestSize: SizeInt; Const S : UnicodeString; out Code : ValSInt): ValSInt; [public, alias:'FPC_VAL_SINT_UNICODESTR']; compilerproc; +Var + SS : ShortString; +begin + fpc_Val_SInt_UnicodeStr:=0; + if length(S)>255 then + code:=256 + else + begin + SS := S; + fpc_Val_SInt_UnicodeStr := int_Val_SInt_ShortStr(DestSize,SS,Code); + end; +end; + + +{$ifndef CPU64} + +Function fpc_Val_qword_UnicodeStr (Const S : UnicodeString; out Code : ValSInt): qword; [public, alias:'FPC_VAL_QWORD_UNICODESTR']; compilerproc; +Var + SS : ShortString; +begin + fpc_Val_qword_UnicodeStr:=0; + if length(S)>255 then + code:=256 + else + begin + SS := S; + Val(SS,fpc_Val_qword_UnicodeStr,Code); + end; +end; + + +Function fpc_Val_int64_UnicodeStr (Const S : UnicodeString; out Code : ValSInt): Int64; [public, alias:'FPC_VAL_INT64_UNICODESTR']; compilerproc; +Var + SS : ShortString; +begin + fpc_Val_int64_UnicodeStr:=0; + if length(S)>255 then + code:=256 + else + begin + SS := S; + Val(SS,fpc_Val_int64_UnicodeStr,Code); + end; +end; + +{$endif CPU64} + + +{$ifndef FPUNONE} +procedure fpc_UnicodeStr_Float(d : ValReal;len,fr,rt : SizeInt;out s : UnicodeString);compilerproc; +var + ss : shortstring; +begin + str_real(len,fr,d,treal_type(rt),ss); + s:=ss; +end; +{$endif} + +procedure fpc_unicodestr_enum(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out s:unicodestring);compilerproc; + +var ss:shortstring; + +begin + fpc_shortstr_enum(ordinal,len,typinfo,ord2strindex,ss); + s:=ss; +end; + +{$ifdef FPC_HAS_STR_CURRENCY} +procedure fpc_UnicodeStr_Currency(c : Currency;len,fr : SizeInt;out s : UnicodeString);compilerproc; +var + ss : shortstring; +begin + str(c:len:fr,ss); + s:=ss; +end; +{$endif FPC_HAS_STR_CURRENCY} + +Procedure fpc_UnicodeStr_SInt(v : ValSint; Len : SizeInt; out S : UnicodeString);compilerproc; +Var + SS : ShortString; +begin + Str (v:Len,SS); + S:=SS; +end; + + +Procedure fpc_UnicodeStr_UInt(v : ValUInt;Len : SizeInt; out S : UnicodeString);compilerproc; +Var + SS : ShortString; +begin + str(v:Len,SS); + S:=SS; +end; + + +{$ifndef CPU64} + +Procedure fpc_UnicodeStr_Int64(v : Int64; Len : SizeInt; out S : UnicodeString);compilerproc; +Var + SS : ShortString; +begin + Str (v:Len,SS); + S:=SS; +end; + + +Procedure fpc_UnicodeStr_Qword(v : Qword;Len : SizeInt; out S : UnicodeString);compilerproc; +Var + SS : ShortString; +begin + str(v:Len,SS); + S:=SS; +end; + +{$endif CPU64} + +function UnicodeToUtf8(Dest: PChar; Source: PUnicodeChar; MaxBytes: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + if assigned(Source) then + Result:=UnicodeToUtf8(Dest,MaxBytes,Source,IndexWord(Source^,-1,0)) + else + Result:=0; + end; + + +function UnicodeToUtf8(Dest: PChar; MaxDestBytes: SizeUInt; Source: PUnicodeChar; SourceChars: SizeUInt): SizeUInt; + var + i,j : SizeUInt; + w : word; + begin + result:=0; + if source=nil then + exit; + i:=0; + j:=0; + if assigned(Dest) then + begin + while (i<SourceChars) and (j<MaxDestBytes) do + begin + w:=word(Source[i]); + case w of + 0..$7f: + begin + Dest[j]:=char(w); + inc(j); + end; + $80..$7ff: + begin + if j+1>=MaxDestBytes then + break; + Dest[j]:=char($c0 or (w shr 6)); + Dest[j+1]:=char($80 or (w and $3f)); + inc(j,2); + end; + else + begin + if j+2>=MaxDestBytes then + break; + Dest[j]:=char($e0 or (w shr 12)); + Dest[j+1]:=char($80 or ((w shr 6)and $3f)); + Dest[j+2]:=char($80 or (w and $3f)); + inc(j,3); + end; + end; + inc(i); + end; + + if j>SizeUInt(MaxDestBytes-1) then + j:=MaxDestBytes-1; + + Dest[j]:=#0; + end + else + begin + while i<SourceChars do + begin + case word(Source[i]) of + $0..$7f: + inc(j); + $80..$7ff: + inc(j,2); + else + inc(j,3); + end; + inc(i); + end; + end; + result:=j+1; + end; + + +function Utf8ToUnicode(Dest: PUnicodeChar; Source: PChar; MaxChars: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + if assigned(Source) then + Result:=Utf8ToUnicode(Dest,MaxChars,Source,strlen(Source)) + else + Result:=0; + end; + + +function Utf8ToUnicode(Dest: PUnicodeChar; MaxDestChars: SizeUInt; Source: PChar; SourceBytes: SizeUInt): SizeUInt; + +var + i,j : SizeUInt; + w: SizeUInt; + b : byte; +begin + if not assigned(Source) then + begin + result:=0; + exit; + end; + result:=SizeUInt(-1); + i:=0; + j:=0; + if assigned(Dest) then + begin + while (j<MaxDestChars) and (i<SourceBytes) do + begin + b:=byte(Source[i]); + w:=b; + inc(i); + // 2 or 3 bytes? + if b>=$80 then + begin + w:=b and $3f; + if i>=SourceBytes then + exit; + // 3 bytes? + if (b and $20)<>0 then + begin + b:=byte(Source[i]); + inc(i); + if i>=SourceBytes then + exit; + if (b and $c0)<>$80 then + exit; + w:=(w shl 6) or (b and $3f); + end; + b:=byte(Source[i]); + w:=(w shl 6) or (b and $3f); + if (b and $c0)<>$80 then + exit; + inc(i); + end; + Dest[j]:=UnicodeChar(w); + inc(j); + end; + if j>=MaxDestChars then j:=MaxDestChars-1; + Dest[j]:=#0; + end + else + begin + while i<SourceBytes do + begin + b:=byte(Source[i]); + inc(i); + // 2 or 3 bytes? + if b>=$80 then + begin + if i>=SourceBytes then + exit; + // 3 bytes? + b := b and $3f; + if (b and $20)<>0 then + begin + b:=byte(Source[i]); + inc(i); + if i>=SourceBytes then + exit; + if (b and $c0)<>$80 then + exit; + end; + if (byte(Source[i]) and $c0)<>$80 then + exit; + inc(i); + end; + inc(j); + end; + end; + result:=j+1; +end; + + +function UTF8Encode(const s : Ansistring) : UTF8String; inline; + begin + Result:=UTF8Encode(UnicodeString(s)); + end; + + +function UTF8Encode(const s : UnicodeString) : UTF8String; + var + i : SizeInt; + hs : UTF8String; + begin + result:=''; + if s='' then + exit; + SetLength(hs,length(s)*3); + i:=UnicodeToUtf8(pchar(hs),length(hs)+1,PUnicodeChar(s),length(s)); + if i>0 then + begin + SetLength(hs,i-1); + result:=hs; + end; + end; + + +function UTF8Decode(const s : UTF8String): UnicodeString; + var + i : SizeInt; + hs : UnicodeString; + begin + result:=''; + if s='' then + exit; + SetLength(hs,length(s)); + i:=Utf8ToUnicode(PUnicodeChar(hs),length(hs)+1,pchar(s),length(s)); + if i>0 then + begin + SetLength(hs,i-1); + result:=hs; + end; + end; + + +function AnsiToUtf8(const s : ansistring): UTF8String;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + Result:=Utf8Encode(s); + end; + + +function Utf8ToAnsi(const s : UTF8String) : ansistring;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + Result:=Utf8Decode(s); + end; + + +{ converts an utf-16 code point or surrogate pair to utf-32 } +function utf16toutf32(const S: UnicodeString; const index: SizeInt; out len: longint): UCS4Char; [public, alias: 'FPC_UTF16TOUTF32']; +var + w: unicodechar; +begin + { UTF-16 points in the range #$0-#$D7FF and #$E000-#$FFFF } + { are the same in UTF-32 } + w:=s[index]; + if (w<=#$d7ff) or + (w>=#$e000) then + begin + result:=UCS4Char(w); + len:=1; + end + { valid surrogate pair? } + else if (w<=#$dbff) and + { w>=#$d7ff check not needed, checked above } + (index<length(s)) and + (s[index+1]>=#$dc00) and + (s[index+1]<=#$dfff) then + { convert the surrogate pair to UTF-32 } + begin + result:=(UCS4Char(w)-$d800) shl 10 + (UCS4Char(s[index+1])-$dc00) + $10000; + len:=2; + end + else + { invalid surrogate -> do nothing } + begin + result:=UCS4Char(w); + len:=1; + end; +end; + + +function UnicodeStringToUCS4String(const s : UnicodeString) : UCS4String; + var + i, slen, + destindex : SizeInt; + len : longint; + begin + slen:=length(s); + setlength(result,slen+1); + i:=1; + destindex:=0; + while (i<=slen) do + begin + result[destindex]:=utf16toutf32(s,i,len); + inc(destindex); + inc(i,len); + end; + { destindex <= slen (surrogate pairs may have been merged) } + { destindex+1 for terminating #0 (dynamic arrays are } + { implicitely filled with zero) } + setlength(result,destindex+1); + end; + + +{ concatenates an utf-32 char to a unicodestring. S *must* be unique when entering. } +procedure ConcatUTF32ToUnicodeStr(const nc: UCS4Char; var S: UnicodeString; var index: SizeInt); +var + p : PUnicodeChar; +begin + { if nc > $ffff, we need two places } + if (index+ord(nc > $ffff)>length(s)) then + if (length(s) < 10*256) then + setlength(s,length(s)+10) + else + setlength(s,length(s)+length(s) shr 8); + { we know that s is unique -> avoid uniquestring calls} + p:=@s[index]; + if (nc<$ffff) then + begin + p^:=unicodechar(nc); + inc(index); + end + else if (dword(nc)<=$10ffff) then + begin + p^:=unicodechar((nc - $10000) shr 10 + $d800); + (p+1)^:=unicodechar((nc - $10000) and $3ff + $dc00); + inc(index,2); + end + else + { invalid code point } + begin + p^:='?'; + inc(index); + end; +end; + + +function UCS4StringToUnicodeString(const s : UCS4String) : UnicodeString; + var + i : SizeInt; + resindex : SizeInt; + begin + { skip terminating #0 } + SetLength(result,length(s)-1); + resindex:=1; + for i:=0 to high(s)-1 do + ConcatUTF32ToUnicodeStr(s[i],result,resindex); + { adjust result length (may be too big due to growing } + { for surrogate pairs) } + setlength(result,resindex-1); + end; + + +function WideStringToUCS4String(const s : WideString) : UCS4String; + var + i, slen, + destindex : SizeInt; + len : longint; + begin + slen:=length(s); + setlength(result,slen+1); + i:=1; + destindex:=0; + while (i<=slen) do + begin + result[destindex]:=utf16toutf32(s,i,len); + inc(destindex); + inc(i,len); + end; + { destindex <= slen (surrogate pairs may have been merged) } + { destindex+1 for terminating #0 (dynamic arrays are } + { implicitely filled with zero) } + setlength(result,destindex+1); + end; + + +{ concatenates an utf-32 char to a widestring. S *must* be unique when entering. } +procedure ConcatUTF32ToWideStr(const nc: UCS4Char; var S: WideString; var index: SizeInt); +var + p : PWideChar; +begin + { if nc > $ffff, we need two places } + if (index+ord(nc > $ffff)>length(s)) then + if (length(s) < 10*256) then + setlength(s,length(s)+10) + else + setlength(s,length(s)+length(s) shr 8); + { we know that s is unique -> avoid uniquestring calls} + p:=@s[index]; + if (nc<$ffff) then + begin + p^:=widechar(nc); + inc(index); + end + else if (dword(nc)<=$10ffff) then + begin + p^:=widechar((nc - $10000) shr 10 + $d800); + (p+1)^:=widechar((nc - $10000) and $3ff + $dc00); + inc(index,2); + end + else + { invalid code point } + begin + p^:='?'; + inc(index); + end; +end; + + +function UCS4StringToWideString(const s : UCS4String) : WideString; + var + i : SizeInt; + resindex : SizeInt; + begin + { skip terminating #0 } + SetLength(result,length(s)-1); + resindex:=1; + for i:=0 to high(s)-1 do + ConcatUTF32ToWideStr(s[i],result,resindex); + { adjust result length (may be too big due to growing } + { for surrogate pairs) } + setlength(result,resindex-1); + end; + + +const + SNoUnicodestrings = 'This binary has no unicodestrings support compiled in.'; + SRecompileWithUnicodestrings = 'Recompile the application with a unicodestrings-manager in the program uses clause.'; + +procedure unimplementedunicodestring; + begin +{$ifdef FPC_HAS_FEATURE_CONSOLEIO} + If IsConsole then + begin + Writeln(StdErr,SNoUnicodestrings); + Writeln(StdErr,SRecompileWithUnicodestrings); + end; +{$endif FPC_HAS_FEATURE_CONSOLEIO} + HandleErrorFrame(233,get_frame); + end; + +{$warnings off} +function GenericUnicodeCase(const s : UnicodeString) : UnicodeString; + begin + unimplementedunicodestring; + end; + + +function CompareUnicodeString(const s1, s2 : UnicodeString) : PtrInt; + begin + unimplementedunicodestring; + end; + + +function CompareTextUnicodeString(const s1, s2 : UnicodeString): PtrInt; + begin + unimplementedunicodestring; + end; + + +function CharLengthPChar(const Str: PChar): PtrInt; + begin + unimplementedunicodestring; + end; + +{$warnings on} + +procedure initunicodestringmanager; + begin +{$ifndef HAS_WIDESTRINGMANAGER} + widestringmanager.Unicode2AnsiMoveProc:=@defaultUnicode2AnsiMove; + widestringmanager.Ansi2UnicodeMoveProc:=@defaultAnsi2UnicodeMove; + widestringmanager.UpperUnicodeStringProc:=@GenericUnicodeCase; + widestringmanager.LowerUnicodeStringProc:=@GenericUnicodeCase; +{$endif HAS_WIDESTRINGMANAGER} + widestringmanager.CompareUnicodeStringProc:=@CompareUnicodeString; + widestringmanager.CompareTextUnicodeStringProc:=@CompareTextUnicodeString; + +{$ifdef FPC_WIDESTRING_EQUAL_UNICODESTRING} +{$ifndef HAS_WIDESTRINGMANAGER} + widestringmanager.Wide2AnsiMoveProc:=@defaultUnicode2AnsiMove; + widestringmanager.Ansi2WideMoveProc:=@defaultAnsi2UnicodeMove; + widestringmanager.UpperWideStringProc:=@GenericUnicodeCase; + widestringmanager.LowerWideStringProc:=@GenericUnicodeCase; +{$endif HAS_WIDESTRINGMANAGER} + widestringmanager.CompareWideStringProc:=@CompareUnicodeString; + widestringmanager.CompareTextWideStringProc:=@CompareTextUnicodeString; + widestringmanager.CharLengthPCharProc:=@CharLengthPChar; +{$endif FPC_WIDESTRING_EQUAL_UNICODESTRING} + end; + diff --git a/rtl/inc/variant.inc b/rtl/inc/variant.inc index 70458c5743..6b0b594347 100644 --- a/rtl/inc/variant.inc +++ b/rtl/inc/variant.inc @@ -225,25 +225,30 @@ end; { Strings } operator :=(const source : shortstring) dest : variant;{$ifdef SYSTEMINLINE}inline;{$endif} - begin VariantManager.VarFromPStr(Dest,Source); end; operator :=(const source : ansistring) dest : variant;{$ifdef SYSTEMINLINE}inline;{$endif} - begin VariantManager.VarFromLStr(Dest,Source); end; operator :=(const source : widestring) dest : variant;{$ifdef SYSTEMINLINE}inline;{$endif} - begin VariantManager.VarFromWStr(Dest,Source); end; + +{$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING} +operator :=(const source : UnicodeString) dest : variant;{$ifdef SYSTEMINLINE}inline;{$endif} +begin + VariantManager.VarFromWStr(Dest,Source); +end; +{$endif FPC_WIDESTRING_EQUAL_UNICODESTRING} + { Floats } {$ifdef SUPPORT_SINGLE} @@ -412,23 +417,34 @@ end; { Strings } operator :=(const source : variant) dest : shortstring;{$ifdef SYSTEMINLINE}inline;{$endif} - begin VariantManager.VarToPStr(Dest,Source); end; -operator :=(const source : variant) dest : ansistring;{$ifdef SYSTEMINLINE}inline;{$endif} +operator :=(const source : variant) dest : ansistring;{$ifdef SYSTEMINLINE}inline;{$endif} begin VariantManager.vartolstr(dest,source); end; -operator :=(const source : variant) dest : widestring;{$ifdef SYSTEMINLINE}inline;{$endif} +operator :=(const source : variant) dest : widestring;{$ifdef SYSTEMINLINE}inline;{$endif} begin variantmanager.vartowstr(dest,source); end; + +{$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING} +operator :=(const source : variant) dest : UnicodeString;{$ifdef SYSTEMINLINE}inline;{$endif} +var + res : WideString; +begin + variantmanager.vartowstr(res,source); + dest:=res; +end; +{$endif FPC_WIDESTRING_EQUAL_UNICODESTRING} + + { Floats } {$ifdef SUPPORT_SINGLE} @@ -623,7 +639,7 @@ procedure VarArrayRedim(var A: Variant; HighBound: SizeInt); procedure VarArrayPut(var A: Variant; const Value: Variant; const Indices: array of SizeInt); begin - if Length(Indices)>0 then + if Length(Indices)>0 then variantmanager.vararrayput(A, Value, Length(Indices), @Indices[0]) else variantmanager.vararrayput(A, Value, 0, nil); @@ -632,13 +648,13 @@ procedure VarArrayPut(var A: Variant; const Value: Variant; const Indices: array function VarArrayGet(const A: Variant; const Indices: array of SizeInt): Variant; begin - if Length(Indices)>0 then + if Length(Indices)>0 then Result:=variantmanager.vararrayget(A, Length(Indices), @Indices[0]) - else + else Result:=variantmanager.vararrayget(A, 0, nil); end; - - + + procedure VarCast(var dest : variant;const source : variant;vartype : longint); begin @@ -763,6 +779,16 @@ operator :=(const source : olevariant) dest : widestring;{$ifdef SYSTEMINLINE}in end; +{$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING} +operator :=(const source : olevariant) dest : UnicodeString;{$ifdef SYSTEMINLINE}inline;{$endif} + var + res : WideString; + begin + variantmanager.vartowstr(res,variant(tvardata(source))); + dest:=res; + end; +{$endif FPC_WIDESTRING_EQUAL_UNICODESTRING} + { Floats } {$ifdef SUPPORT_SINGLE} operator :=(const source : olevariant) dest : single;{$ifdef SYSTEMINLINE}inline;{$endif} @@ -931,6 +957,14 @@ operator :=(const source : widestring) dest : olevariant;{$ifdef SYSTEMINLINE}in end; +{$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING} +operator :=(const source : UnicodeString) dest : olevariant;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + variantmanager.varfromwstr(variant(tvardata(dest)),source); + end; +{$endif FPC_WIDESTRING_EQUAL_UNICODESTRING} + + { Floats } {$ifdef SUPPORT_SINGLE} operator :=(const source : single) dest : olevariant;{$ifdef SYSTEMINLINE}inline;{$endif} @@ -1050,6 +1084,14 @@ Function Pos (w : WideString; Const v : Variant) : SizeInt;{$ifdef SYSTEMINLINE} end; +{$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING} +Function Pos (w : UnicodeString; Const v : Variant) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + Result:=Pos(w,UnicodeString(v)); + end; +{$endif FPC_WIDESTRING_EQUAL_UNICODESTRING} + + Function Pos (v : Variant; Const c : Char) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} begin Result:=Pos(ShortString(v),c); @@ -1074,6 +1116,14 @@ Function Pos (v : Variant; Const w : WideString) : SizeInt;{$ifdef SYSTEMINLINE} end; +{$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING} +Function Pos (v : Variant; Const w : UnicodeString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + Result:=Pos(UnicodeString(v),w); + end; +{$endif FPC_WIDESTRING_EQUAL_UNICODESTRING} + + Function Pos (v1 : Variant; Const v2 : Variant) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} begin Result:=Pos(WideString(v1),WideString(v2)); diff --git a/rtl/inc/varianth.inc b/rtl/inc/varianth.inc index 09b1bda314..09513fbafb 100644 --- a/rtl/inc/varianth.inc +++ b/rtl/inc/varianth.inc @@ -243,6 +243,9 @@ operator :=(const source : widechar) dest : variant;{$ifdef SYSTEMINLINE}inline; operator :=(const source : shortstring) dest : variant;{$ifdef SYSTEMINLINE}inline;{$endif} operator :=(const source : ansistring) dest : variant;{$ifdef SYSTEMINLINE}inline;{$endif} operator :=(const source : widestring) dest : variant;{$ifdef SYSTEMINLINE}inline;{$endif} +{$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING} +operator :=(const source : UnicodeString) dest : variant;{$ifdef SYSTEMINLINE}inline;{$endif} +{$endif FPC_WIDESTRING_EQUAL_UNICODESTRING} { Floats } {$ifdef SUPPORT_SINGLE} @@ -297,6 +300,9 @@ operator :=(const source : variant) dest : widechar;{$ifdef SYSTEMINLINE}inline; operator :=(const source : variant) dest : shortstring;{$ifdef SYSTEMINLINE}inline;{$endif} operator :=(const source : variant) dest : ansistring;{$ifdef SYSTEMINLINE}inline;{$endif} operator :=(const source : variant) dest : widestring;{$ifdef SYSTEMINLINE}inline;{$endif} +{$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING} +operator :=(const source : variant) dest : unicodestring;{$ifdef SYSTEMINLINE}inline;{$endif} +{$endif FPC_WIDESTRING_EQUAL_UNICODESTRING} { Floats } {$ifdef SUPPORT_SINGLE} @@ -388,6 +394,9 @@ operator :=(const source : olevariant) dest : widechar;{$ifdef SYSTEMINLINE}inli operator :=(const source : olevariant) dest : shortstring;{$ifdef SYSTEMINLINE}inline;{$endif} operator :=(const source : olevariant) dest : ansistring;{$ifdef SYSTEMINLINE}inline;{$endif} operator :=(const source : olevariant) dest : widestring;{$ifdef SYSTEMINLINE}inline;{$endif} +{$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING} +operator :=(const source : olevariant) dest : UnicodeString;{$ifdef SYSTEMINLINE}inline;{$endif} +{$endif FPC_WIDESTRING_EQUAL_UNICODESTRING} { Floats } {$ifdef SUPPORT_SINGLE} @@ -442,6 +451,9 @@ operator :=(const source : widechar) dest : olevariant;{$ifdef SYSTEMINLINE}inli operator :=(const source : shortstring) dest : olevariant;{$ifdef SYSTEMINLINE}inline;{$endif} operator :=(const source : ansistring) dest : olevariant;{$ifdef SYSTEMINLINE}inline;{$endif} operator :=(const source : widestring) dest : olevariant;{$ifdef SYSTEMINLINE}inline;{$endif} +{$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING} +operator :=(const source : UnicodeString) dest : olevariant;{$ifdef SYSTEMINLINE}inline;{$endif} +{$endif FPC_WIDESTRING_EQUAL_UNICODESTRING} { Floats } {$ifdef SUPPORT_SINGLE} @@ -474,10 +486,16 @@ Function Pos (c : Char; Const v : Variant) : SizeInt;{$ifdef SYSTEMINLINE}inline Function Pos (s : ShortString; Const v : Variant) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} Function Pos (a : AnsiString; Const v : Variant) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} Function Pos (w : WideString; Const v : Variant) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} +{$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING} +Function Pos (w : UnicodeString; Const v : Variant) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} +{$endif FPC_WIDESTRING_EQUAL_UNICODESTRING} Function Pos (v : Variant; Const c : Char) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} Function Pos (v : Variant; Const s : ShortString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} Function Pos (v : Variant; Const a : AnsiString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} Function Pos (v : Variant; Const w : WideString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} +{$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING} +Function Pos (v : Variant; Const w : UnicodeString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} +{$endif FPC_WIDESTRING_EQUAL_UNICODESTRING} Function Pos (v1 : Variant; Const v2 : Variant) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} {********************************************************************** diff --git a/rtl/inc/wstring22h.inc b/rtl/inc/wstring22h.inc new file mode 100644 index 0000000000..5861197dcf --- /dev/null +++ b/rtl/inc/wstring22h.inc @@ -0,0 +1,108 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2005 by Florian Klaempfl, + member of the Free Pascal development team. + + This file implements support routines for WideStrings with FPC 2.2 + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +{ this file can be removed when the 2.2.x series is outdated } + +Procedure UniqueString (Var S : WideString);external name 'FPC_WIDESTR_UNIQUE'; +Function Pos (Const Substr : WideString; Const Source : WideString) : SizeInt; +Function Pos (c : Char; Const s : WideString) : SizeInt; +Function Pos (c : WideChar; Const s : WideString) : SizeInt; +Function Pos (c : WideChar; Const s : AnsiString) : SizeInt; +Function Pos (c : AnsiString; Const s : WideString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} +Function Pos (c : WideString; Const s : AnsiString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} +Function Pos (c : ShortString; Const s : WideString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} + +Function UpCase(const s : WideString) : WideString; + +Procedure Insert (Const Source : WideString; Var S : WideString; Index : SizeInt); +Procedure Delete (Var S : WideString; Index,Size: SizeInt); +Procedure SetString (Out S : WideString; Buf : PWideChar; Len : SizeInt); +Procedure SetString (Out S : WideString; Buf : PChar; Len : SizeInt); + +function WideCharToString(S : PWideChar) : AnsiString; +function StringToWideChar(const Src : AnsiString;Dest : PWideChar;DestSize : SizeInt) : PWideChar; +function WideCharLenToString(S : PWideChar;Len : SizeInt) : AnsiString; +procedure WideCharLenToStrVar(Src : PWideChar;Len : SizeInt;out Dest : AnsiString); +procedure WideCharToStrVar(S : PWideChar;out Dest : AnsiString); + +procedure DefaultWide2AnsiMove(source:pwidechar;var dest:ansistring;len:SizeInt); +procedure DefaultAnsi2WideMove(source:pchar;var dest:widestring;len:SizeInt); + +Type + { hooks for internationalization + please add new procedures at the end, it makes it easier to detect new procedures } + TWideStringManager = record + Wide2AnsiMoveProc : procedure(source:pwidechar;var dest:ansistring;len:SizeInt); + Ansi2WideMoveProc : procedure(source:pchar;var dest:widestring;len:SizeInt); + +// UpperUTF8 : procedure(p:PUTF8String); + + UpperWideStringProc : function(const S: WideString): WideString; +// UpperUCS4 : procedure(p:PUCS4Char); +// LowerUTF8 : procedure(p:PUTF8String); + LowerWideStringProc : function(const S: WideString): WideString; +// LowerUCS4 : procedure(p:PUCS4Char); +{ + CompUTF8 : function(p1,p2:PUTF8String) : shortint; + CompUCS2 : function(p1,p2:PUCS2Char) : shortint; + CompUCS4 : function(p1,p2:PUC42Char) : shortint; +} + CompareWideStringProc : function(const s1, s2 : WideString) : PtrInt; + CompareTextWideStringProc : function(const s1, s2 : WideString): PtrInt; + CharLengthPCharProc : function(const Str: PChar): PtrInt; + + UpperAnsiStringProc : function(const s : ansistring) : ansistring; + LowerAnsiStringProc : function(const s : ansistring) : ansistring; + CompareStrAnsiStringProc : function(const S1, S2: ansistring): PtrInt; + CompareTextAnsiStringProc : function(const S1, S2: ansistring): PtrInt; + StrCompAnsiStringProc : function(S1, S2: PChar): PtrInt; + StrICompAnsiStringProc : function(S1, S2: PChar): PtrInt; + StrLCompAnsiStringProc : function(S1, S2: PChar; MaxLen: PtrUInt): PtrInt; + StrLICompAnsiStringProc : function(S1, S2: PChar; MaxLen: PtrUInt): PtrInt; + StrLowerAnsiStringProc : function(Str: PChar): PChar; + StrUpperAnsiStringProc : function(Str: PChar): PChar; + ThreadInitProc : procedure; + ThreadFiniProc : procedure; + end; + TUnicodeStringManager = TWideStringManager; + +function UnicodeToUtf8(Dest: PChar; Source: PWideChar; MaxBytes: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} +function UnicodeToUtf8(Dest: PChar; MaxDestBytes: SizeUInt; Source: PWideChar; SourceChars: SizeUInt): SizeUInt; +function Utf8ToUnicode(Dest: PWideChar; Source: PChar; MaxChars: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} +function Utf8ToUnicode(Dest: PWideChar; MaxDestChars: SizeUInt; Source: PChar; SourceBytes: SizeUInt): SizeUInt; +function UTF8Encode(const s : WideString) : UTF8String; +function UTF8Decode(const s : UTF8String): WideString; +function AnsiToUtf8(const s : ansistring): UTF8String;{$ifdef SYSTEMINLINE}inline;{$endif} +function Utf8ToAnsi(const s : UTF8String) : ansistring;{$ifdef SYSTEMINLINE}inline;{$endif} +function WideStringToUCS4String(const s : WideString) : UCS4String; +function UCS4StringToWideString(const s : UCS4String) : WideString; + +{$ifdef MSWINDOWS} +const + winwidestringalloc : boolean = true; +{$endif MSWINDOWS} + +var + widestringmanager : TWideStringManager; + +Procedure GetWideStringManager (Var Manager : TWideStringManager); +Procedure SetWideStringManager (Const New : TWideStringManager); +Procedure SetWideStringManager (Const New : TWideStringManager; Var Old: TWideStringManager); + +Procedure GetUnicodeStringManager (Var Manager : TUnicodeStringManager); +Procedure SetUnicodeStringManager (Const New : TUnicodeStringManager); +Procedure SetUnicodeStringManager (Const New : TUnicodeStringManager; Var Old: TUnicodeStringManager); + diff --git a/rtl/inc/wstringh.inc b/rtl/inc/wstringh.inc index 1d9f2f23b9..d933fef0c0 100644 --- a/rtl/inc/wstringh.inc +++ b/rtl/inc/wstringh.inc @@ -31,73 +31,20 @@ Procedure Delete (Var S : WideString; Index,Size: SizeInt); Procedure SetString (Out S : WideString; Buf : PWideChar; Len : SizeInt); Procedure SetString (Out S : WideString; Buf : PChar; Len : SizeInt); -function WideCharToString(S : PWideChar) : AnsiString; -function StringToWideChar(const Src : AnsiString;Dest : PWideChar;DestSize : SizeInt) : PWideChar; -function WideCharLenToString(S : PWideChar;Len : SizeInt) : AnsiString; -procedure WideCharLenToStrVar(Src : PWideChar;Len : SizeInt;out Dest : AnsiString); -procedure WideCharToStrVar(S : PWideChar;out Dest : AnsiString); - procedure DefaultWide2AnsiMove(source:pwidechar;var dest:ansistring;len:SizeInt); procedure DefaultAnsi2WideMove(source:pchar;var dest:widestring;len:SizeInt); -Type - { hooks for internationalization - please add new procedures at the end, it makes it easier to detect new procedures } - TWideStringManager = record - Wide2AnsiMoveProc : procedure(source:pwidechar;var dest:ansistring;len:SizeInt); - Ansi2WideMoveProc : procedure(source:pchar;var dest:widestring;len:SizeInt); - -// UpperUTF8 : procedure(p:PUTF8String); - - UpperWideStringProc : function(const S: WideString): WideString; -// UpperUCS4 : procedure(p:PUCS4Char); -// LowerUTF8 : procedure(p:PUTF8String); - LowerWideStringProc : function(const S: WideString): WideString; -// LowerUCS4 : procedure(p:PUCS4Char); -{ - CompUTF8 : function(p1,p2:PUTF8String) : shortint; - CompUCS2 : function(p1,p2:PUCS2Char) : shortint; - CompUCS4 : function(p1,p2:PUC42Char) : shortint; -} - CompareWideStringProc : function(const s1, s2 : WideString) : PtrInt; - CompareTextWideStringProc : function(const s1, s2 : WideString): PtrInt; - CharLengthPCharProc : function(const Str: PChar): PtrInt; - - UpperAnsiStringProc : function(const s : ansistring) : ansistring; - LowerAnsiStringProc : function(const s : ansistring) : ansistring; - CompareStrAnsiStringProc : function(const S1, S2: ansistring): PtrInt; - CompareTextAnsiStringProc : function(const S1, S2: ansistring): PtrInt; - StrCompAnsiStringProc : function(S1, S2: PChar): PtrInt; - StrICompAnsiStringProc : function(S1, S2: PChar): PtrInt; - StrLCompAnsiStringProc : function(S1, S2: PChar; MaxLen: PtrUInt): PtrInt; - StrLICompAnsiStringProc : function(S1, S2: PChar; MaxLen: PtrUInt): PtrInt; - StrLowerAnsiStringProc : function(Str: PChar): PChar; - StrUpperAnsiStringProc : function(Str: PChar): PChar; - ThreadInitProc : procedure; - ThreadFiniProc : procedure; - end; - +type + TWideStringManager = TUnicodeStringManager; function UnicodeToUtf8(Dest: PChar; Source: PWideChar; MaxBytes: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} function UnicodeToUtf8(Dest: PChar; MaxDestBytes: SizeUInt; Source: PWideChar; SourceChars: SizeUInt): SizeUInt; function Utf8ToUnicode(Dest: PWideChar; Source: PChar; MaxChars: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} function Utf8ToUnicode(Dest: PWideChar; MaxDestChars: SizeUInt; Source: PChar; SourceBytes: SizeUInt): SizeUInt; function UTF8Encode(const s : WideString) : UTF8String; -function UTF8Decode(const s : UTF8String): WideString; -function AnsiToUtf8(const s : ansistring): UTF8String;{$ifdef SYSTEMINLINE}inline;{$endif} -function Utf8ToAnsi(const s : UTF8String) : ansistring;{$ifdef SYSTEMINLINE}inline;{$endif} -function WideStringToUCS4String(const s : WideString) : UCS4String; -function UCS4StringToWideString(const s : UCS4String) : WideString; {$ifdef MSWINDOWS} const winwidestringalloc : boolean = true; {$endif MSWINDOWS} -var - widestringmanager : TWideStringManager; - -Procedure GetWideStringManager (Var Manager : TWideStringManager); -Procedure SetWideStringManager (Const New : TWideStringManager); -Procedure SetWideStringManager (Const New : TWideStringManager; Var Old: TWideStringManager); - diff --git a/rtl/inc/wstrings.inc b/rtl/inc/wstrings.inc index 65c455e1f2..fc3ec06730 100644 --- a/rtl/inc/wstrings.inc +++ b/rtl/inc/wstrings.inc @@ -1,17 +1,1501 @@ -{ - This file is part of the Free Pascal run time library. - Copyright (c) 1999-2005 by Florian Klaempfl, - member of the Free Pascal development team. - - This file implements support routines for WideStrings with FPC - - See the file COPYING.FPC, included in this distribution, - for details about the copyright. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - **********************************************************************} - -{$i wustrings.inc} +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2005 by Florian Klaempfl, + member of the Free Pascal development team. + + This file implements support routines for WideStrings with FPC + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +{ + This file contains the implementation of the WideString type, + and all things that are needed for it. + WideString is defined as a 'silent' pwidechar : + a pwidechar that points to : + + @-8 : SizeInt for reference count; + @-4 : SizeInt for size; size=number of bytes, not the number of chars. Divide or multiply + with sizeof(WideChar) to convert. This is needed to be compatible with Delphi and + Windows COM BSTR. + @ : String + Terminating #0; + Pwidechar(Widestring) is a valid typecast. + So WS[i] is converted to the address @WS+i-1. + + Constants should be assigned a reference count of -1 + Meaning that they can't be disposed of. +} + +Type + PWideRec = ^TWideRec; + TWideRec = Packed Record + Len : DWord; + First : WideChar; + end; + +Const + WideRecLen = SizeOf(TWideRec); + WideFirstOff = SizeOf(TWideRec)-sizeof(WideChar); + +{ + Default WideChar <-> Char conversion is to only convert the + lower 127 chars, all others are translated to spaces. + + These routines can be overwritten for the Current Locale +} + +procedure DefaultWide2AnsiMove(source:pwidechar;var dest:ansistring;len:SizeInt); +var + i : SizeInt; +begin + setlength(dest,len); + for i:=1 to len do + begin + if word(source^)<256 then + dest[i]:=char(word(source^)) + else + dest[i]:='?'; + inc(source); + end; +end; + + +procedure DefaultAnsi2WideMove(source:pchar;var dest:widestring;len:SizeInt); +var + i : SizeInt; +begin + setlength(dest,len); + for i:=1 to len do + begin + dest[i]:=widechar(byte(source^)); + inc(source); + end; +end; + + +(* +Procedure UniqueWideString(Var S : WideString); [Public,Alias : 'FPC_WIDESTR_UNIQUE']; +{ + Make sure reference count of S is 1, + using copy-on-write semantics. +} + +begin +end; +*) + + +{**************************************************************************** + Internal functions, not in interface. +****************************************************************************} + + +procedure WideStringError; + begin + HandleErrorFrame(204,get_frame); + end; + + +{$ifdef WideStrDebug} +Procedure DumpWideRec(S : Pointer); +begin + If S=Nil then + Writeln ('String is nil') + Else + Begin + With PWideRec(S-WideFirstOff)^ do + begin + Write ('(Len:',len); + Writeln (' Ref: ',ref,')'); + end; + end; +end; +{$endif} + + +Function NewWideString(Len : SizeInt) : Pointer; +{ + Allocate a new WideString on the heap. + initialize it to zero length and reference count 1. +} +Var + P : Pointer; +begin +{$ifdef MSWINDOWS} + if winwidestringalloc then + begin + P:=SysAllocStringLen(nil,Len); + if P=nil then + WideStringError; + end + else +{$endif MSWINDOWS} + begin + GetMem(P,Len*sizeof(WideChar)+WideRecLen); + If P<>Nil then + begin + PWideRec(P)^.Len:=Len*2; { Initial length } + PWideRec(P)^.First:=#0; { Terminating #0 } + inc(p,WideFirstOff); { Points to string now } + end + else + WideStringError; + end; + NewWideString:=P; +end; + + +Procedure DisposeWideString(Var S : Pointer); +{ + Deallocates a WideString From the heap. +} +begin + If S=Nil then + exit; +{$ifndef MSWINDOWS} + Dec (S,WideFirstOff); + Freemem(S); +{$else MSWINDOWS} + if winwidestringalloc then + SysFreeString(S) + else + begin + Dec (S,WideFirstOff); + Freemem(S); + end; +{$endif MSWINDOWS} + S:=Nil; +end; + +var + __data_start: byte; external name '__data_start__'; + __data_end: byte; external name '__data_end__'; + +function IsWideStringConstant(S: pointer): boolean;{$ifdef SYSTEMINLINE}inline;{$endif} +{ + Returns True if widestring is constant (located in .data section); +} +begin + Result:=(S>=@__data_start) and (S<@__data_end); +end; + +Procedure fpc_WideStr_Decr_Ref (Var S : Pointer);[Public,Alias:'FPC_WIDESTR_DECR_REF']; compilerproc; +{ + Decreases the ReferenceCount of a non constant widestring; + If the reference count is zero, deallocate the string; +} +Type + pSizeInt = ^SizeInt; +Begin + { Zero string } + if S=Nil then + exit; + if not IsWideStringConstant(S) then + DisposeWideString(S); +end; + +{ alias for internal use } +Procedure fpc_WideStr_Decr_Ref (Var S : Pointer);[external name 'FPC_WIDESTR_DECR_REF']; + +Procedure fpc_WideStr_Incr_Ref(Var S : Pointer);[Public,Alias:'FPC_WIDESTR_INCR_REF']; compilerproc; + var + p : pointer; + Begin + If S=Nil then + exit; + p:=NewWidestring(length(WideString(S))); + move(s^,p^,(length(WideString(s))+1)*sizeof(widechar)); // double #0 too + s:=p; + end; + +{ alias for internal use } +Procedure fpc_WideStr_Incr_Ref (Var S : Pointer);[external name 'FPC_WIDESTR_INCR_REF']; + +{$ifndef FPC_STRTOSHORTSTRINGPROC} +function fpc_WideStr_To_ShortStr (high_of_res: SizeInt;const S2 : WideString): shortstring;[Public, alias: 'FPC_WIDESTR_TO_SHORTSTR']; compilerproc; +{ + Converts a WideString to a ShortString; +} +Var + Size : SizeInt; + temp : ansistring; +begin + result:=''; + Size:=Length(S2); + if Size>0 then + begin + If Size>high_of_res then + Size:=high_of_res; + widestringmanager.Wide2AnsiMoveProc(PWideChar(S2),temp,Size); + result:=temp; + end; +end; +{$else FPC_STRTOSHORTSTRINGPROC} +procedure fpc_WideStr_To_ShortStr (out res: ShortString;const S2 : WideString); [Public, alias: 'FPC_WIDESTR_TO_SHORTSTR'];compilerproc; +{ + Converts a WideString to a ShortString; +} +Var + Size : SizeInt; + temp : ansistring; +begin + res:=''; + Size:=Length(S2); + if Size>0 then + begin + If Size>high(res) then + Size:=high(res); + widestringmanager.Wide2AnsiMoveProc(PWideChar(S2),temp,Size); + res:=temp; + end; +end; +{$endif FPC_STRTOSHORTSTRINGPROC} + + +Function fpc_ShortStr_To_WideStr (Const S2 : ShortString): WideString;compilerproc; +{ + Converts a ShortString to a WideString; +} +Var + Size : SizeInt; +begin + result:=''; + Size:=Length(S2); + if Size>0 then + begin + widestringmanager.Ansi2WideMoveProc(PChar(@S2[1]),result,Size); + { Terminating Zero } + PWideChar(Pointer(fpc_ShortStr_To_WideStr)+Size*sizeof(WideChar))^:=#0; + end; +end; + + +Function fpc_WideStr_To_AnsiStr (const S2 : WideString): AnsiString; compilerproc; +{ + Converts a WideString to an AnsiString +} +Var + Size : SizeInt; +begin + result:=''; + Size:=Length(S2); + if Size>0 then + widestringmanager.Wide2AnsiMoveProc(PWideChar(Pointer(S2)),result,Size); +end; + + +Function fpc_AnsiStr_To_WideStr (Const S2 : AnsiString): WideString; compilerproc; +{ + Converts an AnsiString to a WideString; +} +Var + Size : SizeInt; +begin + result:=''; + Size:=Length(S2); + if Size>0 then + widestringmanager.Ansi2WideMoveProc(PChar(S2),result,Size); +end; + + +Function fpc_PWideChar_To_WideStr(const p : pwidechar): widestring; compilerproc; +var + Size : SizeInt; +begin + result:=''; + if p=nil then + exit; + Size := IndexWord(p^, -1, 0); + Setlength(result,Size); + if Size>0 then + begin + Move(p^,PWideChar(Pointer(result))^,Size*sizeof(WideChar)); + { Terminating Zero } + PWideChar(Pointer(result)+Size*sizeof(WideChar))^:=#0; + end; +end; + + +{ checked against the ansistring routine, 2001-05-27 (FK) } +Procedure fpc_WideStr_Assign (Var S1 : Pointer;S2 : Pointer);[Public,Alias:'FPC_WIDESTR_ASSIGN']; compilerproc; +{ + Assigns S2 to S1 (S1:=S2), taking in account reference counts. +} +begin + if S1=S2 then exit; + if S2<>nil then + begin + if IsWideStringConstant(S1) then + begin + S1:=NewWidestring(length(WideString(S2))); + move(s2^,s1^,(length(WideString(s1))+1)*sizeof(widechar)); + end + else +{$ifdef MSWINDOWS} + if winwidestringalloc then + begin + if SysReAllocStringLen(S1, S2, Length(WideString(S2))) = 0 then + WideStringError; + end + else +{$endif MSWINDOWS} + begin + SetLength(WideString(S1),length(WideString(S2))); + move(s2^,s1^,(length(WideString(s1))+1)*sizeof(widechar)); + end; + end + else + begin + { Free S1 } + fpc_widestr_decr_ref (S1); + S1:=nil; + end; +end; + + +{ alias for internal use } +Procedure fpc_WideStr_Assign (Var S1 : Pointer;S2 : Pointer);[external name 'FPC_WIDESTR_ASSIGN']; + +{$ifndef STR_CONCAT_PROCS} + +function fpc_WideStr_Concat (const S1,S2 : WideString): WideString; compilerproc; +Var + Size,Location : SizeInt; + pc : pwidechar; +begin + { only assign if s1 or s2 is empty } + if (S1='') then + begin + result:=s2; + exit; + end; + if (S2='') then + begin + result:=s1; + exit; + end; + Location:=Length(S1); + Size:=length(S2); + SetLength(result,Size+Location); + pc:=pwidechar(result); + Move(S1[1],pc^,Location*sizeof(WideChar)); + inc(pc,location); + Move(S2[1],pc^,(Size+1)*sizeof(WideChar)); +end; + + +function fpc_WideStr_Concat_multi (const sarr:array of Widestring): widestring; compilerproc; +Var + i : Longint; + p : pointer; + pc : pwidechar; + Size,NewSize : SizeInt; +begin + { First calculate size of the result so we can do + a single call to SetLength() } + NewSize:=0; + for i:=low(sarr) to high(sarr) do + inc(Newsize,length(sarr[i])); + SetLength(result,NewSize); + pc:=pwidechar(result); + for i:=low(sarr) to high(sarr) do + begin + p:=pointer(sarr[i]); + if assigned(p) then + begin + Size:=length(widestring(p)); + Move(pwidechar(p)^,pc^,(Size+1)*sizeof(WideChar)); + inc(pc,size); + end; + end; +end; + +{$else STR_CONCAT_PROCS} + +procedure fpc_WideStr_Concat (var DestS:Widestring;const S1,S2 : WideString); compilerproc; +Var + Size,Location : SizeInt; + same : boolean; +begin + { only assign if s1 or s2 is empty } + if (S1='') then + begin + DestS:=s2; + exit; + end; + if (S2='') then + begin + DestS:=s1; + exit; + end; + Location:=Length(S1); + Size:=length(S2); + { Use Pointer() typecasts to prevent extra conversion code } + if Pointer(DestS)=Pointer(S1) then + begin + same:=Pointer(S1)=Pointer(S2); + SetLength(DestS,Size+Location); + if same then + Move(Pointer(DestS)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size)*sizeof(WideChar)) + else + Move(Pointer(S2)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size+1)*sizeof(WideChar)); + end + else if Pointer(DestS)=Pointer(S2) then + begin + SetLength(DestS,Size+Location); + Move(Pointer(DestS)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size+1)*sizeof(WideChar)); + Move(Pointer(S1)^,Pointer(DestS)^,Location*sizeof(WideChar)); + end + else + begin + DestS:=''; + SetLength(DestS,Size+Location); + Move(Pointer(S1)^,Pointer(DestS)^,Location*sizeof(WideChar)); + Move(Pointer(S2)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size+1)*sizeof(WideChar)); + end; +end; + + +procedure fpc_WideStr_Concat_multi (var DestS:Widestring;const sarr:array of Widestring); compilerproc; +Var + i : Longint; + p,pc : pointer; + Size,NewLen : SizeInt; + DestTmp : Widestring; +begin + if high(sarr)=0 then + begin + DestS:=''; + exit; + end; + { First calculate size of the result so we can do + a single call to SetLength() } + NewLen:=0; + for i:=low(sarr) to high(sarr) do + inc(NewLen,length(sarr[i])); + SetLength(DestTmp,NewLen); + pc:=pwidechar(DestTmp); + for i:=low(sarr) to high(sarr) do + begin + p:=pointer(sarr[i]); + if assigned(p) then + begin + Size:=length(widestring(p)); + Move(p^,pc^,(Size+1)*sizeof(WideChar)); + inc(pc,size*sizeof(WideChar)); + end; + end; + DestS:=DestTmp; +end; + +{$endif STR_CONCAT_PROCS} + + +Function fpc_Char_To_WideStr(const c : Char): WideString; compilerproc; +{ + Converts a Char to a WideString; +} +begin + Setlength(fpc_Char_To_WideStr,1); + fpc_Char_To_WideStr[1]:=c; + { Terminating Zero } + PWideChar(Pointer(fpc_Char_To_WideStr)+sizeof(WideChar))^:=#0; +end; + + +Function fpc_WChar_To_WideStr(const c : WideChar): WideString; compilerproc; +{ + Converts a WideChar to a WideString; +} +begin + Setlength (fpc_WChar_To_WideStr,1); + fpc_WChar_To_WideStr[1]:= c; +end; + + +Function fpc_WChar_To_AnsiStr(const c : WideChar): AnsiString; compilerproc; +{ + Converts a WideChar to a AnsiString; +} +begin + widestringmanager.Wide2AnsiMoveProc(@c, fpc_WChar_To_AnsiStr, 1); +end; + + +Function fpc_UChar_To_WideStr(const c : WideChar): WideString; compilerproc; +{ + Converts a WideChar to a WideString; +} +begin + Setlength (fpc_UChar_To_WideStr,1); + fpc_UChar_To_WideStr[1]:= c; +end; + + +Function fpc_PChar_To_WideStr(const p : pchar): WideString; compilerproc; +Var + L : SizeInt; +begin + if (not assigned(p)) or (p[0]=#0) Then + begin + fpc_pchar_to_widestr := ''; + exit; + end; + l:=IndexChar(p^,-1,#0); + widestringmanager.Ansi2WideMoveProc(P,fpc_PChar_To_WideStr,l); +end; + + +Function fpc_CharArray_To_WideStr(const arr: array of char; zerobased: boolean = true): WideString; compilerproc; +var + i : SizeInt; +begin + if (zerobased) then + begin + if (arr[0]=#0) Then + begin + fpc_chararray_to_widestr := ''; + exit; + end; + i:=IndexChar(arr,high(arr)+1,#0); + if i = -1 then + i := high(arr)+1; + end + else + i := high(arr)+1; + SetLength(fpc_CharArray_To_WideStr,i); + widestringmanager.Ansi2WideMoveProc (pchar(@arr),fpc_CharArray_To_WideStr,i); +end; + + +{$ifndef FPC_STRTOCHARARRAYPROC} + +{ inside the compiler, the resulttype is modified to that of the actual } +{ chararray we're converting to (JM) } +function fpc_widestr_to_chararray(arraysize: SizeInt; const src: WideString): fpc_big_chararray;[public,alias: 'FPC_WIDESTR_TO_CHARARRAY']; compilerproc; +var + len: SizeInt; + temp: ansistring; +begin + len := length(src); + { make sure we don't dereference src if it can be nil (JM) } + if len > 0 then + widestringmanager.wide2ansimoveproc(pwidechar(@src[1]),temp,len); + len := length(temp); + if len > arraysize then + len := arraysize; +{$r-} + move(temp[1],fpc_widestr_to_chararray[0],len); + fillchar(fpc_widestr_to_chararray[len],arraysize-len,0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + + +{ inside the compiler, the resulttype is modified to that of the actual } +{ widechararray we're converting to (JM) } +function fpc_widestr_to_widechararray(arraysize: SizeInt; const src: WideString): fpc_big_widechararray;[public,alias: 'FPC_WIDESTR_TO_WIDECHARARRAY']; compilerproc; +var + len: SizeInt; +begin + len := length(src); + if len > arraysize then + len := arraysize; +{$r-} + { make sure we don't try to access element 1 of the ansistring if it's nil } + if len > 0 then + move(src[1],fpc_widestr_to_widechararray[0],len*SizeOf(WideChar)); + fillchar(fpc_widestr_to_widechararray[len],(arraysize-len)*SizeOf(WideChar),0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + + +{ inside the compiler, the resulttype is modified to that of the actual } +{ chararray we're converting to (JM) } +function fpc_ansistr_to_widechararray(arraysize: SizeInt; const src: AnsiString): fpc_big_widechararray;[public,alias: 'FPC_ANSISTR_TO_WIDECHARARRAY']; compilerproc; +var + len: SizeInt; + temp: widestring; +begin + len := length(src); + { make sure we don't dereference src if it can be nil (JM) } + if len > 0 then + widestringmanager.ansi2widemoveproc(pchar(@src[1]),temp,len); + len := length(temp); + if len > arraysize then + len := arraysize; + +{$r-} + move(temp[1],fpc_ansistr_to_widechararray[0],len*sizeof(widechar)); + fillchar(fpc_ansistr_to_widechararray[len],(arraysize-len)*SizeOf(WideChar),0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + +function fpc_shortstr_to_widechararray(arraysize: SizeInt; const src: ShortString): fpc_big_widechararray;[public,alias: 'FPC_SHORTSTR_TO_WIDECHARARRAY']; compilerproc; +var + len: longint; + temp : widestring; +begin + len := length(src); + { make sure we don't access char 1 if length is 0 (JM) } + if len > 0 then + widestringmanager.ansi2widemoveproc(pchar(@src[1]),temp,len); + len := length(temp); + if len > arraysize then + len := arraysize; +{$r-} + move(temp[1],fpc_shortstr_to_widechararray[0],len*sizeof(widechar)); + fillchar(fpc_shortstr_to_widechararray[len],(arraysize-len)*SizeOf(WideChar),0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + +{$else ndef FPC_STRTOCHARARRAYPROC} + +procedure fpc_widestr_to_chararray(out res: array of char; const src: WideString); compilerproc; +var + len: SizeInt; + temp: ansistring; +begin + len := length(src); + { make sure we don't dereference src if it can be nil (JM) } + if len > 0 then + widestringmanager.wide2ansimoveproc(pwidechar(@src[1]),temp,len); + len := length(temp); + if len > length(res) then + len := length(res); +{$r-} + move(temp[1],res[0],len); + fillchar(res[len],length(res)-len,0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + + +procedure fpc_widestr_to_widechararray(out res: array of widechar; const src: WideString); compilerproc; +var + len: SizeInt; +begin + len := length(src); + if len > length(res) then + len := length(res); +{$r-} + { make sure we don't try to access element 1 of the ansistring if it's nil } + if len > 0 then + move(src[1],res[0],len*SizeOf(WideChar)); + fillchar(res[len],(length(res)-len)*SizeOf(WideChar),0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + + +{$endif ndef FPC_STRTOCHARARRAYPROC} + +Function fpc_WideStr_Compare(const S1,S2 : WideString): SizeInt;[Public,Alias : 'FPC_WIDESTR_COMPARE']; compilerproc; +{ + Compares 2 WideStrings; + The result is + <0 if S1<S2 + 0 if S1=S2 + >0 if S1>S2 +} +Var + MaxI,Temp : SizeInt; +begin + if pointer(S1)=pointer(S2) then + begin + fpc_WideStr_Compare:=0; + exit; + end; + Maxi:=Length(S1); + temp:=Length(S2); + If MaxI>Temp then + MaxI:=Temp; + Temp:=CompareWord(S1[1],S2[1],MaxI); + if temp=0 then + temp:=Length(S1)-Length(S2); + fpc_WideStr_Compare:=Temp; +end; + +Function fpc_WideStr_Compare_Equal(const S1,S2 : WideString): SizeInt;[Public,Alias : 'FPC_WIDESTR_COMPARE_EQUAL']; compilerproc; +{ + Compares 2 WideStrings for equality only; + The result is + 0 if S1=S2 + <>0 if S1<>S2 +} +Var + MaxI : SizeInt; +begin + if pointer(S1)=pointer(S2) then + exit(0); + Maxi:=Length(S1); + If MaxI<>Length(S2) then + exit(-1) + else + exit(CompareWord(S1[1],S2[1],MaxI)); +end; + +Procedure fpc_WideStr_CheckZero(p : pointer);[Public,Alias : 'FPC_WIDESTR_CHECKZERO']; compilerproc; +begin + if p=nil then + HandleErrorFrame(201,get_frame); +end; + + +Procedure fpc_WideStr_CheckRange(len,index : SizeInt);[Public,Alias : 'FPC_WIDESTR_RANGECHECK']; compilerproc; +begin + if (index>len div 2) or (Index<1) then + HandleErrorFrame(201,get_frame); +end; + +Procedure fpc_WideStr_SetLength(Var S : WideString; l : SizeInt);[Public,Alias : 'FPC_WIDESTR_SETLENGTH']; compilerproc; +{ + Sets The length of string S to L. + Makes sure S is unique, and contains enough room. +} +Var + Temp : Pointer; + movelen: SizeInt; +begin + if (l>0) then + begin + if Pointer(S)=nil then + begin + { Need a complete new string...} + Pointer(s):=NewWideString(l); + end + { windows doesn't support reallocing widestrings, this code + is anyways subject to be removed because widestrings shouldn't be + ref. counted anymore (FK) } + else + if +{$ifdef MSWINDOWS} + not winwidestringalloc and +{$endif MSWINDOWS} + not IsWideStringConstant(pointer(S)) + then + begin + Dec(Pointer(S),WideFirstOff); + if SizeUInt(L*sizeof(WideChar)+WideRecLen)>MemSize(Pointer(S)) then + reallocmem(pointer(S), L*sizeof(WideChar)+WideRecLen); + Inc(Pointer(S), WideFirstOff); + end + else + begin + { Reallocation is needed... } + Temp:=Pointer(NewWideString(L)); + if Length(S)>0 then + begin + if l < succ(length(s)) then + movelen := l + { also move terminating null } + else + movelen := succ(length(s)); + Move(Pointer(S)^,Temp^,movelen * Sizeof(WideChar)); + end; + fpc_widestr_decr_ref(Pointer(S)); + Pointer(S):=Temp; + end; + { Force nil termination in case it gets shorter } + PWord(Pointer(S)+l*sizeof(WideChar))^:=0; +{$ifdef MSWINDOWS} + if not winwidestringalloc then +{$endif MSWINDOWS} + PWideRec(Pointer(S)-WideFirstOff)^.Len:=l*sizeof(WideChar); + end + else + begin + { Length=0 } + if Pointer(S)<>nil then + fpc_widestr_decr_ref (Pointer(S)); + Pointer(S):=Nil; + end; +end; + +{***************************************************************************** + Public functions, In interface. +*****************************************************************************} + +Function fpc_widestr_Unique(Var S : Pointer): Pointer; [Public,Alias : 'FPC_WIDESTR_UNIQUE']; compilerproc; + begin + pointer(result) := pointer(s); + end; + + +Function Fpc_WideStr_Copy (Const S : WideString; Index,Size : SizeInt) : WideString;compilerproc; +var + ResultAddress : Pointer; +begin + ResultAddress:=Nil; + dec(index); + if Index < 0 then + Index := 0; + { Check Size. Accounts for Zero-length S, the double check is needed because + Size can be maxint and will get <0 when adding index } + if (Size>Length(S)) or + (Index+Size>Length(S)) then + Size:=Length(S)-Index; + If Size>0 then + begin + If Index<0 Then + Index:=0; + ResultAddress:=Pointer(NewWideString (Size)); + if ResultAddress<>Nil then + begin + Move (PWideChar(S)[Index],ResultAddress^,Size*sizeof(WideChar)); + PWideRec(ResultAddress-WideFirstOff)^.Len:=Size*sizeof(WideChar); + PWideChar(ResultAddress+Size*sizeof(WideChar))^:=#0; + end; + end; + fpc_widestr_decr_ref(Pointer(fpc_widestr_copy)); + Pointer(fpc_widestr_Copy):=ResultAddress; +end; + + +Function Pos (Const Substr : WideString; Const Source : WideString) : SizeInt; +var + i,MaxLen : SizeInt; + pc : pwidechar; +begin + Pos:=0; + if Length(SubStr)>0 then + begin + MaxLen:=Length(source)-Length(SubStr); + i:=0; + pc:=@source[1]; + while (i<=MaxLen) do + begin + inc(i); + if (SubStr[1]=pc^) and + (CompareWord(Substr[1],pc^,Length(SubStr))=0) then + begin + Pos:=i; + exit; + end; + inc(pc); + end; + end; +end; + + +{ Faster version for a widechar alone } +Function Pos (c : WideChar; Const s : WideString) : SizeInt; +var + i: SizeInt; + pc : pwidechar; +begin + pc:=@s[1]; + for i:=1 to length(s) do + begin + if pc^=c then + begin + pos:=i; + exit; + end; + inc(pc); + end; + pos:=0; +end; + + +Function Pos (c : WideChar; Const s : AnsiString) : SizeInt; + begin + result:=Pos(c,WideString(s)); + end; + + +Function Pos (c : AnsiString; Const s : WideString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + result:=Pos(WideString(c),s); + end; + + +Function Pos (c : ShortString; Const s : WideString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + result:=Pos(WideString(c),s); + end; + + +Function Pos (c : WideString; Const s : AnsiString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + result:=Pos(c,WideString(s)); + end; + +{ Faster version for a char alone. Must be implemented because } +{ pos(c: char; const s: shortstring) also exists, so otherwise } +{ using pos(char,pchar) will always call the shortstring version } +{ (exact match for first argument), also with $h+ (JM) } +Function Pos (c : Char; Const s : WideString) : SizeInt; +var + i: SizeInt; + wc : widechar; + pc : pwidechar; +begin + wc:=c; + pc:=@s[1]; + for i:=1 to length(s) do + begin + if pc^=wc then + begin + pos:=i; + exit; + end; + inc(pc); + end; + pos:=0; +end; + + + +Procedure Delete (Var S : WideString; Index,Size: SizeInt); +Var + LS : SizeInt; +begin + If Length(S)=0 then + exit; + if index<=0 then + exit; + LS:=PWideRec(Pointer(S)-WideFirstOff)^.Len div sizeof(WideChar); + if (Index<=LS) and (Size>0) then + begin + UniqueString (S); + if Size+Index>LS then + Size:=LS-Index+1; + if Index+Size<=LS then + begin + Dec(Index); + Move(PWideChar(S)[Index+Size],PWideChar(S)[Index],(LS-Index-Size+1)*sizeof(WideChar)); + end; + Setlength(s,LS-Size); + end; +end; + + +Procedure Insert (Const Source : WideString; Var S : WideString; Index : SizeInt); +var + Temp : WideString; + LS : SizeInt; +begin + If Length(Source)=0 then + exit; + if index <= 0 then + index := 1; + Ls:=Length(S); + if index > LS then + index := LS+1; + Dec(Index); + Pointer(Temp) := NewWideString(Length(Source)+LS); + SetLength(Temp,Length(Source)+LS); + If Index>0 then + move (PWideChar(S)^,PWideChar(Temp)^,Index*sizeof(WideChar)); + Move (PWideChar(Source)^,PWideChar(Temp)[Index],Length(Source)*sizeof(WideChar)); + If (LS-Index)>0 then + Move(PWideChar(S)[Index],PWideChar(temp)[Length(Source)+index],(LS-Index)*sizeof(WideChar)); + S:=Temp; +end; + + +function UpCase(const s : WideString) : WideString; +begin + result:=widestringmanager.UpperWideStringProc(s); +end; + + +Procedure SetString (Out S : WideString; Buf : PWideChar; Len : SizeInt); +var + BufLen: SizeInt; +begin + SetLength(S,Len); + If (Buf<>Nil) and (Len>0) then + begin + BufLen := IndexWord(Buf^, Len+1, 0); + If (BufLen>0) and (BufLen < Len) then + Len := BufLen; + Move (Buf[0],S[1],Len*sizeof(WideChar)); + PWideChar(Pointer(S)+Len*sizeof(WideChar))^:=#0; + end; +end; + + +Procedure SetString (Out S : WideString; Buf : PChar; Len : SizeInt); +var + BufLen: SizeInt; +begin + SetLength(S,Len); + If (Buf<>Nil) and (Len>0) then + begin + BufLen := IndexByte(Buf^, Len+1, 0); + If (BufLen>0) and (BufLen < Len) then + Len := BufLen; + widestringmanager.Ansi2WideMoveProc(Buf,S,Len); + //PWideChar(Pointer(S)+Len*sizeof(WideChar))^:=#0; + end; +end; + + +{$ifndef FPUNONE} +Function fpc_Val_Real_WideStr(Const S : WideString; out Code : ValSInt): ValReal; [public, alias:'FPC_VAL_REAL_WIDESTR']; compilerproc; +Var + SS : String; +begin + fpc_Val_Real_WideStr := 0; + if length(S) > 255 then + code := 256 + else + begin + SS := S; + Val(SS,fpc_Val_Real_WideStr,code); + end; +end; +{$endif} + +function fpc_val_enum_widestr(str2ordindex:pointer;const s:widestring;out code:valsint):longint;compilerproc; + +var ss:shortstring; + +begin + if length(s)>255 then + code:=256 + else + begin + ss:=s; + val(ss,fpc_val_enum_widestr,code); + end; +end; + +Function fpc_Val_Currency_WideStr(Const S : WideString; out Code : ValSInt): Currency; [public, alias:'FPC_VAL_CURRENCY_WIDESTR']; compilerproc; +Var + SS : String; +begin + if length(S) > 255 then + begin + fpc_Val_Currency_WideStr:=0; + code := 256; + end + else + begin + SS := S; + Val(SS,fpc_Val_Currency_WideStr,code); + end; +end; + + +Function fpc_Val_UInt_WideStr (Const S : WideString; out Code : ValSInt): ValUInt; [public, alias:'FPC_VAL_UINT_WIDESTR']; compilerproc; +Var + SS : ShortString; +begin + fpc_Val_UInt_WideStr := 0; + if length(S) > 255 then + code := 256 + else + begin + SS := S; + Val(SS,fpc_Val_UInt_WideStr,code); + end; +end; + + +Function fpc_Val_SInt_WideStr (DestSize: SizeInt; Const S : WideString; out Code : ValSInt): ValSInt; [public, alias:'FPC_VAL_SINT_WIDESTR']; compilerproc; +Var + SS : ShortString; +begin + fpc_Val_SInt_WideStr:=0; + if length(S)>255 then + code:=256 + else + begin + SS := S; + fpc_Val_SInt_WideStr := int_Val_SInt_ShortStr(DestSize,SS,Code); + end; +end; + + +{$ifndef CPU64} + +Function fpc_Val_qword_WideStr (Const S : WideString; out Code : ValSInt): qword; [public, alias:'FPC_VAL_QWORD_WIDESTR']; compilerproc; +Var + SS : ShortString; +begin + fpc_Val_qword_WideStr:=0; + if length(S)>255 then + code:=256 + else + begin + SS := S; + Val(SS,fpc_Val_qword_WideStr,Code); + end; +end; + + +Function fpc_Val_int64_WideStr (Const S : WideString; out Code : ValSInt): Int64; [public, alias:'FPC_VAL_INT64_WIDESTR']; compilerproc; +Var + SS : ShortString; +begin + fpc_Val_int64_WideStr:=0; + if length(S)>255 then + code:=256 + else + begin + SS := S; + Val(SS,fpc_Val_int64_WideStr,Code); + end; +end; + +{$endif CPU64} + + +{$ifndef FPUNONE} +procedure fpc_WideStr_Float(d : ValReal;len,fr,rt : SizeInt;out s : WideString);compilerproc; +var + ss : shortstring; +begin + str_real(len,fr,d,treal_type(rt),ss); + s:=ss; +end; +{$endif} + +procedure fpc_widestr_enum(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out s:widestring);compilerproc; + +var ss:shortstring; + +begin + fpc_shortstr_enum(ordinal,len,typinfo,ord2strindex,ss); + s:=ss; +end; + +{$ifdef FPC_HAS_STR_CURRENCY} +procedure fpc_WideStr_Currency(c : Currency;len,fr : SizeInt;out s : WideString);compilerproc; +var + ss : shortstring; +begin + str(c:len:fr,ss); + s:=ss; +end; +{$endif FPC_HAS_STR_CURRENCY} + +Procedure fpc_WideStr_SInt(v : ValSint; Len : SizeInt; out S : WideString);compilerproc; +Var + SS : ShortString; +begin + Str (v:Len,SS); + S:=SS; +end; + + +Procedure fpc_WideStr_UInt(v : ValUInt;Len : SizeInt; out S : WideString);compilerproc; +Var + SS : ShortString; +begin + str(v:Len,SS); + S:=SS; +end; + + +{$ifndef CPU64} + +Procedure fpc_WideStr_Int64(v : Int64; Len : SizeInt; out S : WideString);compilerproc; +Var + SS : ShortString; +begin + Str (v:Len,SS); + S:=SS; +end; + + +Procedure fpc_WideStr_Qword(v : Qword;Len : SizeInt; out S : WideString);compilerproc; +Var + SS : ShortString; +begin + str(v:Len,SS); + S:=SS; +end; + +{$endif CPU64} + +function UnicodeToUtf8(Dest: PChar; Source: PWideChar; MaxBytes: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + if assigned(Source) then + Result:=UnicodeToUtf8(Dest,MaxBytes,Source,IndexWord(Source^,-1,0)) + else + Result:=0; + end; + + +function UnicodeToUtf8(Dest: PChar; MaxDestBytes: SizeUInt; Source: PWideChar; SourceChars: SizeUInt): SizeUInt; + var + i,j : SizeUInt; + w : word; + begin + result:=0; + if source=nil then + exit; + i:=0; + j:=0; + if assigned(Dest) then + begin + while (i<SourceChars) and (j<MaxDestBytes) do + begin + w:=word(Source[i]); + case w of + 0..$7f: + begin + Dest[j]:=char(w); + inc(j); + end; + $80..$7ff: + begin + if j+1>=MaxDestBytes then + break; + Dest[j]:=char($c0 or (w shr 6)); + Dest[j+1]:=char($80 or (w and $3f)); + inc(j,2); + end; + else + begin + if j+2>=MaxDestBytes then + break; + Dest[j]:=char($e0 or (w shr 12)); + Dest[j+1]:=char($80 or ((w shr 6)and $3f)); + Dest[j+2]:=char($80 or (w and $3f)); + inc(j,3); + end; + end; + inc(i); + end; + + if j>SizeUInt(MaxDestBytes-1) then + j:=MaxDestBytes-1; + + Dest[j]:=#0; + end + else + begin + while i<SourceChars do + begin + case word(Source[i]) of + $0..$7f: + inc(j); + $80..$7ff: + inc(j,2); + else + inc(j,3); + end; + inc(i); + end; + end; + result:=j+1; + end; + + +function Utf8ToUnicode(Dest: PWideChar; Source: PChar; MaxChars: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + if assigned(Source) then + Result:=Utf8ToUnicode(Dest,MaxChars,Source,strlen(Source)) + else + Result:=0; + end; + + +function Utf8ToUnicode(Dest: PWideChar; MaxDestChars: SizeUInt; Source: PChar; SourceBytes: SizeUInt): SizeUInt; + +var + i,j : SizeUInt; + w: SizeUInt; + b : byte; +begin + if not assigned(Source) then + begin + result:=0; + exit; + end; + result:=SizeUInt(-1); + i:=0; + j:=0; + if assigned(Dest) then + begin + while (j<MaxDestChars) and (i<SourceBytes) do + begin + b:=byte(Source[i]); + w:=b; + inc(i); + // 2 or 3 bytes? + if b>=$80 then + begin + w:=b and $3f; + if i>=SourceBytes then + exit; + // 3 bytes? + if (b and $20)<>0 then + begin + b:=byte(Source[i]); + inc(i); + if i>=SourceBytes then + exit; + if (b and $c0)<>$80 then + exit; + w:=(w shl 6) or (b and $3f); + end; + b:=byte(Source[i]); + w:=(w shl 6) or (b and $3f); + if (b and $c0)<>$80 then + exit; + inc(i); + end; + Dest[j]:=WideChar(w); + inc(j); + end; + if j>=MaxDestChars then j:=MaxDestChars-1; + Dest[j]:=#0; + end + else + begin + while i<SourceBytes do + begin + b:=byte(Source[i]); + inc(i); + // 2 or 3 bytes? + if b>=$80 then + begin + if i>=SourceBytes then + exit; + // 3 bytes? + b := b and $3f; + if (b and $20)<>0 then + begin + b:=byte(Source[i]); + inc(i); + if i>=SourceBytes then + exit; + if (b and $c0)<>$80 then + exit; + end; + if (byte(Source[i]) and $c0)<>$80 then + exit; + inc(i); + end; + inc(j); + end; + end; + result:=j+1; +end; + + +function UTF8Encode(const s : WideString) : UTF8String; + var + i : SizeInt; + hs : UTF8String; + begin + result:=''; + if s='' then + exit; + SetLength(hs,length(s)*3); + i:=UnicodeToUtf8(pchar(hs),length(hs)+1,PWideChar(s),length(s)); + if i>0 then + begin + SetLength(hs,i-1); + result:=hs; + end; + end; + + +{ converts an utf-16 code point or surrogate pair to utf-32 } +function utf16toutf32(const S: WideString; const index: SizeInt; out len: longint): UCS4Char; [public, alias: 'FPC_WIDETOUTF32']; +var + w: widechar; +begin + { UTF-16 points in the range #$0-#$D7FF and #$E000-#$FFFF } + { are the same in UTF-32 } + w:=s[index]; + if (w<=#$d7ff) or + (w>=#$e000) then + begin + result:=UCS4Char(w); + len:=1; + end + { valid surrogate pair? } + else if (w<=#$dbff) and + { w>=#$d7ff check not needed, checked above } + (index<length(s)) and + (s[index+1]>=#$dc00) and + (s[index+1]<=#$dfff) then + { convert the surrogate pair to UTF-32 } + begin + result:=(UCS4Char(w)-$d800) shl 10 + (UCS4Char(s[index+1])-$dc00) + $10000; + len:=2; + end + else + { invalid surrogate -> do nothing } + begin + result:=UCS4Char(w); + len:=1; + end; +end; + + +const + SNoWidestrings = 'This binary has no widestrings support compiled in.'; + SRecompileWithWidestrings = 'Recompile the application with a widestrings-manager in the program uses clause.'; + +procedure unimplementedwidestring; + begin +{$ifdef FPC_HAS_FEATURE_CONSOLEIO} + If IsConsole then + begin + Writeln(StdErr,SNoWidestrings); + Writeln(StdErr,SRecompileWithWidestrings); + end; +{$endif FPC_HAS_FEATURE_CONSOLEIO} + HandleErrorFrame(233,get_frame); + end; + +{$warnings off} +function GenericWideCase(const s : WideString) : WideString; + begin + unimplementedwidestring; + end; + + +function CompareWideString(const s1, s2 : WideString) : PtrInt; + begin + unimplementedwidestring; + end; + + +function CompareTextWideString(const s1, s2 : WideString): PtrInt; + begin + unimplementedwidestring; + end; + +{$warnings on} + +function CharLengthPChar(const Str: PChar): PtrInt;forward; + + +procedure initwidestringmanager; + begin + fillchar(widestringmanager,sizeof(widestringmanager),0); +{$ifndef HAS_WIDESTRINGMANAGER} + widestringmanager.Wide2AnsiMoveProc:=@defaultWide2AnsiMove; + widestringmanager.Ansi2WideMoveProc:=@defaultAnsi2WideMove; + widestringmanager.UpperWideStringProc:=@GenericWideCase; + widestringmanager.LowerWideStringProc:=@GenericWideCase; +{$endif HAS_WIDESTRINGMANAGER} + widestringmanager.CompareWideStringProc:=@CompareWideString; + widestringmanager.CompareTextWideStringProc:=@CompareTextWideString; + widestringmanager.CharLengthPCharProc:=@CharLengthPChar; + end; diff --git a/rtl/inc/wustring22.inc b/rtl/inc/wustring22.inc new file mode 100644 index 0000000000..3f79a7d7dd --- /dev/null +++ b/rtl/inc/wustring22.inc @@ -0,0 +1,2021 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2005 by Florian Klaempfl, + member of the Free Pascal development team. + + This file implements support routines for WideStrings/Unicode with FPC + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +{ + This file contains the implementation of the WideString type, + and all things that are needed for it. + WideString is defined as a 'silent' pwidechar : + a pwidechar that points to : + + @-8 : SizeInt for reference count; + @-4 : SizeInt for size; size=number of bytes, not the number of chars. Divide or multiply + with sizeof(WideChar) to convert. This is needed to be compatible with Delphi and + Windows COM BSTR. + @ : String + Terminating #0; + Pwidechar(Widestring) is a valid typecast. + So WS[i] is converted to the address @WS+i-1. + + Constants should be assigned a reference count of -1 + Meaning that they can't be disposed of. +} + +Type + PWideRec = ^TWideRec; + TWideRec = Packed Record +{$ifdef FPC_WINLIKEWIDESTRING} + Len : DWord; +{$else FPC_WINLIKEWIDESTRING} + Ref : SizeInt; + Len : SizeInt; +{$endif FPC_WINLIKEWIDESTRING} + First : WideChar; + end; + +Const + WideRecLen = SizeOf(TWideRec); + WideFirstOff = SizeOf(TWideRec)-sizeof(WideChar); + +{ + Default WideChar <-> Char conversion is to only convert the + lower 127 chars, all others are translated to spaces. + + These routines can be overwritten for the Current Locale +} + +procedure DefaultWide2AnsiMove(source:pwidechar;var dest:ansistring;len:SizeInt); +var + i : SizeInt; +begin + setlength(dest,len); + for i:=1 to len do + begin + if word(source^)<256 then + dest[i]:=char(word(source^)) + else + dest[i]:='?'; + inc(source); + end; +end; + + +procedure DefaultAnsi2WideMove(source:pchar;var dest:widestring;len:SizeInt); +var + i : SizeInt; +begin + setlength(dest,len); + for i:=1 to len do + begin + dest[i]:=widechar(byte(source^)); + inc(source); + end; +end; + + +Procedure GetUnicodeStringManager (Var Manager : TUnicodeStringManager); +begin + manager:=widestringmanager; +end; + + +Procedure SetUnicodeStringManager (Const New : TUnicodeStringManager; Var Old: TUnicodeStringManager); +begin + Old:=widestringmanager; + widestringmanager:=New; +end; + + +Procedure SetUnicodeStringManager (Const New : TUnicodeStringManager); +begin + widestringmanager:=New; +end; + + +Procedure GetWideStringManager (Var Manager : TWideStringManager); +begin + manager:=widestringmanager; +end; + + +Procedure SetWideStringManager (Const New : TWideStringManager; Var Old: TWideStringManager); +begin + Old:=widestringmanager; + widestringmanager:=New; +end; + + +Procedure SetWideStringManager (Const New : TWideStringManager); +begin + widestringmanager:=New; +end; + +(* +Procedure UniqueWideString(Var S : WideString); [Public,Alias : 'FPC_WIDESTR_UNIQUE']; +{ + Make sure reference count of S is 1, + using copy-on-write semantics. +} + +begin +end; +*) + + +{**************************************************************************** + Internal functions, not in interface. +****************************************************************************} + + +procedure WideStringError; + begin + HandleErrorFrame(204,get_frame); + end; + + +{$ifdef WideStrDebug} +Procedure DumpWideRec(S : Pointer); +begin + If S=Nil then + Writeln ('String is nil') + Else + Begin + With PWideRec(S-WideFirstOff)^ do + begin + Write ('(Len:',len); + Writeln (' Ref: ',ref,')'); + end; + end; +end; +{$endif} + + +Function NewWideString(Len : SizeInt) : Pointer; +{ + Allocate a new WideString on the heap. + initialize it to zero length and reference count 1. +} +Var + P : Pointer; +begin +{$ifdef MSWINDOWS} + if winwidestringalloc then + begin + P:=SysAllocStringLen(nil,Len); + if P=nil then + WideStringError; + end + else +{$endif MSWINDOWS} + begin + GetMem(P,Len*sizeof(WideChar)+WideRecLen); + If P<>Nil then + begin + PWideRec(P)^.Len:=Len*2; { Initial length } +{$ifndef FPC_WINLIKEWIDESTRING} + PWideRec(P)^.Ref:=1; { Initial Refcount } +{$endif FPC_WINLIKEWIDESTRING} + PWideRec(P)^.First:=#0; { Terminating #0 } + inc(p,WideFirstOff); { Points to string now } + end + else + WideStringError; + end; + NewWideString:=P; +end; + + +Procedure DisposeWideString(Var S : Pointer); +{ + Deallocates a WideString From the heap. +} +begin + If S=Nil then + exit; +{$ifndef MSWINDOWS} + Dec (S,WideFirstOff); + Freemem(S); +{$else MSWINDOWS} + if winwidestringalloc then + SysFreeString(S) + else + begin + Dec (S,WideFirstOff); + Freemem(S); + end; +{$endif MSWINDOWS} + S:=Nil; +end; + +{$ifdef FPC_WINLIKEWIDESTRING} +var + __data_start: byte; external name '__data_start__'; + __data_end: byte; external name '__data_end__'; + +function IsWideStringConstant(S: pointer): boolean;{$ifdef SYSTEMINLINE}inline;{$endif} +{ + Returns True if widestring is constant (located in .data section); +} +begin + Result:=(S>=@__data_start) and (S<@__data_end); +end; +{$endif FPC_WINLIKEWIDESTRING} + +Procedure fpc_WideStr_Decr_Ref (Var S : Pointer);[Public,Alias:'FPC_WIDESTR_DECR_REF']; compilerproc; +{ + Decreases the ReferenceCount of a non constant widestring; + If the reference count is zero, deallocate the string; +} +Type + pSizeInt = ^SizeInt; +{$ifndef FPC_WINLIKEWIDESTRING} +Var + l : pSizeInt; +{$endif FPC_WINLIKEWIDESTRING} +Begin + { Zero string } + if S=Nil then + exit; +{$ifndef FPC_WINLIKEWIDESTRING} + { check for constant strings ...} + l:=@PWideRec(S-WideFirstOff)^.Ref; + if l^<0 then + exit; + + { declocked does a MT safe dec and returns true, if the counter is 0 } + if declocked(l^) then + { Ref count dropped to zero ... + ... remove } +{$else} + if not IsWideStringConstant(S) then +{$endif FPC_WINLIKEWIDESTRING} + DisposeWideString(S); +end; + +{ alias for internal use } +Procedure fpc_WideStr_Decr_Ref (Var S : Pointer);[external name 'FPC_WIDESTR_DECR_REF']; + +Procedure fpc_WideStr_Incr_Ref(Var S : Pointer);[Public,Alias:'FPC_WIDESTR_INCR_REF']; compilerproc; +{$ifdef FPC_WINLIKEWIDESTRING} + var + p : pointer; +{$endif FPC_WINLIKEWIDESTRING} + Begin + If S=Nil then + exit; +{$ifdef FPC_WINLIKEWIDESTRING} + p:=NewWidestring(length(WideString(S))); + move(s^,p^,(length(WideString(s))+1)*sizeof(widechar)); // double #0 too + s:=p; +{$else FPC_WINLIKEWIDESTRING} + { Let's be paranoid : Constant string ??} + If PWideRec(S-WideFirstOff)^.Ref<0 then + exit; + inclocked(PWideRec(S-WideFirstOff)^.Ref); +{$endif FPC_WINLIKEWIDESTRING} + end; + +{ alias for internal use } +Procedure fpc_WideStr_Incr_Ref (Var S : Pointer);[external name 'FPC_WIDESTR_INCR_REF']; + +{$ifndef FPC_STRTOSHORTSTRINGPROC} +function fpc_WideStr_To_ShortStr (high_of_res: SizeInt;const S2 : WideString): shortstring;[Public, alias: 'FPC_WIDESTR_TO_SHORTSTR']; compilerproc; +{ + Converts a WideString to a ShortString; +} +Var + Size : SizeInt; + temp : ansistring; +begin + result:=''; + Size:=Length(S2); + if Size>0 then + begin + If Size>high_of_res then + Size:=high_of_res; + widestringmanager.Wide2AnsiMoveProc(PWideChar(S2),temp,Size); + result:=temp; + end; +end; +{$else FPC_STRTOSHORTSTRINGPROC} +procedure fpc_WideStr_To_ShortStr (out res: ShortString;const S2 : WideString); [Public, alias: 'FPC_WIDESTR_TO_SHORTSTR'];compilerproc; +{ + Converts a WideString to a ShortString; +} +Var + Size : SizeInt; + temp : ansistring; +begin + res:=''; + Size:=Length(S2); + if Size>0 then + begin + If Size>high(res) then + Size:=high(res); + widestringmanager.Wide2AnsiMoveProc(PWideChar(S2),temp,Size); + res:=temp; + end; +end; +{$endif FPC_STRTOSHORTSTRINGPROC} + + +Function fpc_ShortStr_To_WideStr (Const S2 : ShortString): WideString;compilerproc; +{ + Converts a ShortString to a WideString; +} +Var + Size : SizeInt; +begin + result:=''; + Size:=Length(S2); + if Size>0 then + begin + widestringmanager.Ansi2WideMoveProc(PChar(@S2[1]),result,Size); + { Terminating Zero } + PWideChar(Pointer(fpc_ShortStr_To_WideStr)+Size*sizeof(WideChar))^:=#0; + end; +end; + + +Function fpc_WideStr_To_AnsiStr (const S2 : WideString): AnsiString; compilerproc; +{ + Converts a WideString to an AnsiString +} +Var + Size : SizeInt; +begin + result:=''; + Size:=Length(S2); + if Size>0 then + widestringmanager.Wide2AnsiMoveProc(PWideChar(Pointer(S2)),result,Size); +end; + + +Function fpc_AnsiStr_To_WideStr (Const S2 : AnsiString): WideString; compilerproc; +{ + Converts an AnsiString to a WideString; +} +Var + Size : SizeInt; +begin + result:=''; + Size:=Length(S2); + if Size>0 then + widestringmanager.Ansi2WideMoveProc(PChar(S2),result,Size); +end; + + +Function fpc_PWideChar_To_AnsiStr(const p : pwidechar): ansistring; compilerproc; +var + Size : SizeInt; +begin + result:=''; + if p=nil then + exit; + Size := IndexWord(p^, -1, 0); + if Size>0 then + widestringmanager.Wide2AnsiMoveProc(P,result,Size); +end; + + +Function fpc_PWideChar_To_WideStr(const p : pwidechar): widestring; compilerproc; +var + Size : SizeInt; +begin + result:=''; + if p=nil then + exit; + Size := IndexWord(p^, -1, 0); + Setlength(result,Size); + if Size>0 then + begin + Move(p^,PWideChar(Pointer(result))^,Size*sizeof(WideChar)); + { Terminating Zero } + PWideChar(Pointer(result)+Size*sizeof(WideChar))^:=#0; + end; +end; + + +{$ifndef FPC_STRTOSHORTSTRINGPROC} +Function fpc_PWideChar_To_ShortStr(const p : pwidechar): shortstring; compilerproc; +var + Size : SizeInt; + temp: ansistring; +begin + result:=''; + if p=nil then + exit; + Size := IndexWord(p^, $7fffffff, 0); + if Size>0 then + begin + widestringmanager.Wide2AnsiMoveProc(p,temp,Size); + result:=temp; + end; +end; +{$else FPC_STRTOSHORTSTRINGPROC} +procedure fpc_PWideChar_To_ShortStr(out res : shortstring;const p : pwidechar); compilerproc; +var + Size : SizeInt; + temp: ansistring; +begin + res:=''; + if p=nil then + exit; + Size:=IndexWord(p^, high(PtrInt), 0); + if Size>0 then + begin + widestringmanager.Wide2AnsiMoveProc(p,temp,Size); + res:=temp; + end; +end; +{$endif FPC_STRTOSHORTSTRINGPROC} + + +{ checked against the ansistring routine, 2001-05-27 (FK) } +Procedure fpc_WideStr_Assign (Var S1 : Pointer;S2 : Pointer);[Public,Alias:'FPC_WIDESTR_ASSIGN']; compilerproc; +{ + Assigns S2 to S1 (S1:=S2), taking in account reference counts. +} +begin +{$ifdef FPC_WINLIKEWIDESTRING} + if S1=S2 then exit; + if S2<>nil then + begin + if IsWideStringConstant(S1) then + begin + S1:=NewWidestring(length(WideString(S2))); + move(s2^,s1^,(length(WideString(s1))+1)*sizeof(widechar)); + end + else +{$ifdef MSWINDOWS} + if winwidestringalloc then + begin + if SysReAllocStringLen(S1, S2, Length(WideString(S2))) = 0 then + WideStringError; + end + else +{$endif MSWINDOWS} + begin + SetLength(WideString(S1),length(WideString(S2))); + move(s2^,s1^,(length(WideString(s1))+1)*sizeof(widechar)); + end; + end + else + begin + { Free S1 } + fpc_widestr_decr_ref (S1); + S1:=nil; + end; +{$else FPC_WINLIKEWIDESTRING} + If S2<>nil then + If PWideRec(S2-WideFirstOff)^.Ref>0 then + inclocked(PWideRec(S2-WideFirstOff)^.ref); + { Decrease the reference count on the old S1 } + fpc_widestr_decr_ref (S1); + s1:=s2; +{$endif FPC_WINLIKEWIDESTRING} +end; + + +{ alias for internal use } +Procedure fpc_WideStr_Assign (Var S1 : Pointer;S2 : Pointer);[external name 'FPC_WIDESTR_ASSIGN']; + +{$ifndef STR_CONCAT_PROCS} + +function fpc_WideStr_Concat (const S1,S2 : WideString): WideString; compilerproc; +Var + Size,Location : SizeInt; + pc : pwidechar; +begin + { only assign if s1 or s2 is empty } + if (S1='') then + begin + result:=s2; + exit; + end; + if (S2='') then + begin + result:=s1; + exit; + end; + Location:=Length(S1); + Size:=length(S2); + SetLength(result,Size+Location); + pc:=pwidechar(result); + Move(S1[1],pc^,Location*sizeof(WideChar)); + inc(pc,location); + Move(S2[1],pc^,(Size+1)*sizeof(WideChar)); +end; + + +function fpc_WideStr_Concat_multi (const sarr:array of Widestring): widestring; compilerproc; +Var + i : Longint; + p : pointer; + pc : pwidechar; + Size,NewSize : SizeInt; +begin + { First calculate size of the result so we can do + a single call to SetLength() } + NewSize:=0; + for i:=low(sarr) to high(sarr) do + inc(Newsize,length(sarr[i])); + SetLength(result,NewSize); + pc:=pwidechar(result); + for i:=low(sarr) to high(sarr) do + begin + p:=pointer(sarr[i]); + if assigned(p) then + begin + Size:=length(widestring(p)); + Move(pwidechar(p)^,pc^,(Size+1)*sizeof(WideChar)); + inc(pc,size); + end; + end; +end; + +{$else STR_CONCAT_PROCS} + +procedure fpc_WideStr_Concat (var DestS:Widestring;const S1,S2 : WideString); compilerproc; +Var + Size,Location : SizeInt; + same : boolean; +begin + { only assign if s1 or s2 is empty } + if (S1='') then + begin + DestS:=s2; + exit; + end; + if (S2='') then + begin + DestS:=s1; + exit; + end; + Location:=Length(S1); + Size:=length(S2); + { Use Pointer() typecasts to prevent extra conversion code } + if Pointer(DestS)=Pointer(S1) then + begin + same:=Pointer(S1)=Pointer(S2); + SetLength(DestS,Size+Location); + if same then + Move(Pointer(DestS)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size)*sizeof(WideChar)) + else + Move(Pointer(S2)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size+1)*sizeof(WideChar)); + end + else if Pointer(DestS)=Pointer(S2) then + begin + SetLength(DestS,Size+Location); + Move(Pointer(DestS)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size+1)*sizeof(WideChar)); + Move(Pointer(S1)^,Pointer(DestS)^,Location*sizeof(WideChar)); + end + else + begin + DestS:=''; + SetLength(DestS,Size+Location); + Move(Pointer(S1)^,Pointer(DestS)^,Location*sizeof(WideChar)); + Move(Pointer(S2)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size+1)*sizeof(WideChar)); + end; +end; + + +procedure fpc_WideStr_Concat_multi (var DestS:Widestring;const sarr:array of Widestring); compilerproc; +Var + i : Longint; + p,pc : pointer; + Size,NewLen : SizeInt; +{$ifndef FPC_WINLIKEWIDESTRING} + lowstart : longint; + destcopy : pointer; + OldDestLen : SizeInt; +{$else FPC_WINLIKEWIDESTRING} + DestTmp : Widestring; +{$endif FPC_WINLIKEWIDESTRING} +begin + if high(sarr)=0 then + begin + DestS:=''; + exit; + end; +{$ifndef FPC_WINLIKEWIDESTRING} + destcopy:=nil; + lowstart:=low(sarr); + if Pointer(DestS)=Pointer(sarr[lowstart]) then + inc(lowstart); + { Check for another reuse, then we can't use + the append optimization } + for i:=lowstart to high(sarr) do + begin + if Pointer(DestS)=Pointer(sarr[i]) then + begin + { if DestS is used somewhere in the middle of the expression, + we need to make sure the original string still exists after + we empty/modify DestS. + This trick only works with reference counted strings. Therefor + this optimization is disabled for WINLIKEWIDESTRING } + destcopy:=pointer(dests); + fpc_WideStr_Incr_Ref(destcopy); + lowstart:=low(sarr); + break; + end; + end; + { Start with empty DestS if we start with concatting + the first array element } + if lowstart=low(sarr) then + DestS:=''; + OldDestLen:=length(DestS); + { Calculate size of the result so we can do + a single call to SetLength() } + NewLen:=0; + for i:=low(sarr) to high(sarr) do + inc(NewLen,length(sarr[i])); + SetLength(DestS,NewLen); + { Concat all strings, except the string we already + copied in DestS } + pc:=Pointer(DestS)+OldDestLen*sizeof(WideChar); + for i:=lowstart to high(sarr) do + begin + p:=pointer(sarr[i]); + if assigned(p) then + begin + Size:=length(widestring(p)); + Move(p^,pc^,(Size+1)*sizeof(WideChar)); + inc(pc,size*sizeof(WideChar)); + end; + end; + fpc_WideStr_Decr_Ref(destcopy); +{$else FPC_WINLIKEWIDESTRING} + { First calculate size of the result so we can do + a single call to SetLength() } + NewLen:=0; + for i:=low(sarr) to high(sarr) do + inc(NewLen,length(sarr[i])); + SetLength(DestTmp,NewLen); + pc:=pwidechar(DestTmp); + for i:=low(sarr) to high(sarr) do + begin + p:=pointer(sarr[i]); + if assigned(p) then + begin + Size:=length(widestring(p)); + Move(p^,pc^,(Size+1)*sizeof(WideChar)); + inc(pc,size*sizeof(WideChar)); + end; + end; + DestS:=DestTmp; +{$endif FPC_WINLIKEWIDESTRING} +end; + +{$endif STR_CONCAT_PROCS} + +Function fpc_Char_To_WChar(const c : Char): WideChar; compilerproc; +var + w: widestring; +begin + widestringmanager.Ansi2WideMoveProc(@c, w, 1); + fpc_Char_To_WChar:= w[1]; +end; + + + +Function fpc_Char_To_WideStr(const c : Char): WideString; compilerproc; +{ + Converts a Char to a WideString; +} +begin + Setlength(fpc_Char_To_WideStr,1); + fpc_Char_To_WideStr[1]:=c; + { Terminating Zero } + PWideChar(Pointer(fpc_Char_To_WideStr)+sizeof(WideChar))^:=#0; +end; + + +Function fpc_WChar_To_Char(const c : WideChar): Char; compilerproc; +{ + Converts a WideChar to a Char; +} +var + s: ansistring; +begin + widestringmanager.Wide2AnsiMoveProc(@c, s, 1); + if length(s)=1 then + fpc_WChar_To_Char:= s[1] + else + fpc_WChar_To_Char:='?'; +end; + + +Function fpc_WChar_To_WideStr(const c : WideChar): WideString; compilerproc; +{ + Converts a WideChar to a WideString; +} +begin + Setlength (fpc_WChar_To_WideStr,1); + fpc_WChar_To_WideStr[1]:= c; +end; + + +Function fpc_WChar_To_AnsiStr(const c : WideChar): AnsiString; compilerproc; +{ + Converts a WideChar to a AnsiString; +} +begin + widestringmanager.Wide2AnsiMoveProc(@c, fpc_WChar_To_AnsiStr, 1); +end; + + +{$ifndef FPC_STRTOSHORTSTRINGPROC} +Function fpc_WChar_To_ShortStr(const c : WideChar): ShortString; compilerproc; +{ + Converts a WideChar to a ShortString; +} +var + s: ansistring; +begin + widestringmanager.Wide2AnsiMoveProc(@c, s, 1); + fpc_WChar_To_ShortStr:= s; +end; +{$else FPC_STRTOSHORTSTRINGPROC} +procedure fpc_WChar_To_ShortStr(out res : shortstring;const c : WideChar) compilerproc; +{ + Converts a WideChar to a ShortString; +} +var + s: ansistring; +begin + widestringmanager.Wide2AnsiMoveProc(@c,s,1); + res:=s; +end; +{$endif FPC_STRTOSHORTSTRINGPROC} + + +Function fpc_PChar_To_WideStr(const p : pchar): WideString; compilerproc; +Var + L : SizeInt; +begin + if (not assigned(p)) or (p[0]=#0) Then + begin + fpc_pchar_to_widestr := ''; + exit; + end; + l:=IndexChar(p^,-1,#0); + widestringmanager.Ansi2WideMoveProc(P,fpc_PChar_To_WideStr,l); +end; + + +Function fpc_CharArray_To_WideStr(const arr: array of char; zerobased: boolean = true): WideString; compilerproc; +var + i : SizeInt; +begin + if (zerobased) then + begin + if (arr[0]=#0) Then + begin + fpc_chararray_to_widestr := ''; + exit; + end; + i:=IndexChar(arr,high(arr)+1,#0); + if i = -1 then + i := high(arr)+1; + end + else + i := high(arr)+1; + SetLength(fpc_CharArray_To_WideStr,i); + widestringmanager.Ansi2WideMoveProc (pchar(@arr),fpc_CharArray_To_WideStr,i); +end; + + +{$ifndef FPC_STRTOSHORTSTRINGPROC} +function fpc_WideCharArray_To_ShortStr(const arr: array of widechar; zerobased: boolean = true): shortstring;[public,alias:'FPC_WIDECHARARRAY_TO_SHORTSTR']; compilerproc; +var + l: longint; + index: longint; + len: byte; + temp: ansistring; +begin + l := high(arr)+1; + if l>=256 then + l:=255 + else if l<0 then + l:=0; + if zerobased then + begin + index:=IndexWord(arr[0],l,0); + if (index < 0) then + len := l + else + len := index; + end + else + len := l; + widestringmanager.Wide2AnsiMoveProc (pwidechar(@arr),temp,len); + fpc_WideCharArray_To_ShortStr := temp; +end; +{$else FPC_STRTOSHORTSTRINGPROC} +procedure fpc_WideCharArray_To_ShortStr(out res : shortstring;const arr: array of widechar; zerobased: boolean = true);[public,alias:'FPC_WIDECHARARRAY_TO_SHORTSTR']; compilerproc; +var + l: longint; + index: ptrint; + len: byte; + temp: ansistring; +begin + l := high(arr)+1; + if l>=high(res)+1 then + l:=high(res) + else if l<0 then + l:=0; + if zerobased then + begin + index:=IndexWord(arr[0],l,0); + if index<0 then + len:=l + else + len:=index; + end + else + len:=l; + widestringmanager.Wide2AnsiMoveProc (pwidechar(@arr),temp,len); + res:=temp; +end; +{$endif FPC_STRTOSHORTSTRINGPROC} + +Function fpc_WideCharArray_To_AnsiStr(const arr: array of widechar; zerobased: boolean = true): AnsiString; compilerproc; +var + i : SizeInt; +begin + if (zerobased) then + begin + i:=IndexWord(arr,high(arr)+1,0); + if i = -1 then + i := high(arr)+1; + end + else + i := high(arr)+1; + SetLength(fpc_WideCharArray_To_AnsiStr,i); + widestringmanager.Wide2AnsiMoveProc (pwidechar(@arr),fpc_WideCharArray_To_AnsiStr,i); +end; + +Function fpc_WideCharArray_To_WideStr(const arr: array of widechar; zerobased: boolean = true): WideString; compilerproc; +var + i : SizeInt; +begin + if (zerobased) then + begin + i:=IndexWord(arr,high(arr)+1,0); + if i = -1 then + i := high(arr)+1; + end + else + i := high(arr)+1; + SetLength(fpc_WideCharArray_To_WideStr,i); + Move(arr[0], Pointer(fpc_WideCharArray_To_WideStr)^,i*sizeof(WideChar)); +end; + +{$ifndef FPC_STRTOCHARARRAYPROC} + +{ inside the compiler, the resulttype is modified to that of the actual } +{ chararray we're converting to (JM) } +function fpc_widestr_to_chararray(arraysize: SizeInt; const src: WideString): fpc_big_chararray;[public,alias: 'FPC_WIDESTR_TO_CHARARRAY']; compilerproc; +var + len: SizeInt; + temp: ansistring; +begin + len := length(src); + { make sure we don't dereference src if it can be nil (JM) } + if len > 0 then + widestringmanager.wide2ansimoveproc(pwidechar(@src[1]),temp,len); + len := length(temp); + if len > arraysize then + len := arraysize; +{$r-} + move(temp[1],fpc_widestr_to_chararray[0],len); + fillchar(fpc_widestr_to_chararray[len],arraysize-len,0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + + +{ inside the compiler, the resulttype is modified to that of the actual } +{ widechararray we're converting to (JM) } +function fpc_widestr_to_widechararray(arraysize: SizeInt; const src: WideString): fpc_big_widechararray;[public,alias: 'FPC_WIDESTR_TO_WIDECHARARRAY']; compilerproc; +var + len: SizeInt; +begin + len := length(src); + if len > arraysize then + len := arraysize; +{$r-} + { make sure we don't try to access element 1 of the ansistring if it's nil } + if len > 0 then + move(src[1],fpc_widestr_to_widechararray[0],len*SizeOf(WideChar)); + fillchar(fpc_widestr_to_widechararray[len],(arraysize-len)*SizeOf(WideChar),0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + + +{ inside the compiler, the resulttype is modified to that of the actual } +{ chararray we're converting to (JM) } +function fpc_ansistr_to_widechararray(arraysize: SizeInt; const src: AnsiString): fpc_big_widechararray;[public,alias: 'FPC_ANSISTR_TO_WIDECHARARRAY']; compilerproc; +var + len: SizeInt; + temp: widestring; +begin + len := length(src); + { make sure we don't dereference src if it can be nil (JM) } + if len > 0 then + widestringmanager.ansi2widemoveproc(pchar(@src[1]),temp,len); + len := length(temp); + if len > arraysize then + len := arraysize; + +{$r-} + move(temp[1],fpc_ansistr_to_widechararray[0],len*sizeof(widechar)); + fillchar(fpc_ansistr_to_widechararray[len],(arraysize-len)*SizeOf(WideChar),0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + +function fpc_shortstr_to_widechararray(arraysize: SizeInt; const src: ShortString): fpc_big_widechararray;[public,alias: 'FPC_SHORTSTR_TO_WIDECHARARRAY']; compilerproc; +var + len: longint; + temp : widestring; +begin + len := length(src); + { make sure we don't access char 1 if length is 0 (JM) } + if len > 0 then + widestringmanager.ansi2widemoveproc(pchar(@src[1]),temp,len); + len := length(temp); + if len > arraysize then + len := arraysize; +{$r-} + move(temp[1],fpc_shortstr_to_widechararray[0],len*sizeof(widechar)); + fillchar(fpc_shortstr_to_widechararray[len],(arraysize-len)*SizeOf(WideChar),0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + +{$else ndef FPC_STRTOCHARARRAYPROC} + +procedure fpc_widestr_to_chararray(out res: array of char; const src: WideString); compilerproc; +var + len: SizeInt; + temp: ansistring; +begin + len := length(src); + { make sure we don't dereference src if it can be nil (JM) } + if len > 0 then + widestringmanager.wide2ansimoveproc(pwidechar(@src[1]),temp,len); + len := length(temp); + if len > length(res) then + len := length(res); +{$r-} + move(temp[1],res[0],len); + fillchar(res[len],length(res)-len,0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + + +procedure fpc_widestr_to_widechararray(out res: array of widechar; const src: WideString); compilerproc; +var + len: SizeInt; +begin + len := length(src); + if len > length(res) then + len := length(res); +{$r-} + { make sure we don't try to access element 1 of the ansistring if it's nil } + if len > 0 then + move(src[1],res[0],len*SizeOf(WideChar)); + fillchar(res[len],(length(res)-len)*SizeOf(WideChar),0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + + +procedure fpc_ansistr_to_widechararray(out res: array of widechar; const src: AnsiString); compilerproc; +var + len: SizeInt; + temp: widestring; +begin + len := length(src); + { make sure we don't dereference src if it can be nil (JM) } + if len > 0 then + widestringmanager.ansi2widemoveproc(pchar(@src[1]),temp,len); + len := length(temp); + if len > length(res) then + len := length(res); + +{$r-} + move(temp[1],res[0],len*sizeof(widechar)); + fillchar(res[len],(length(res)-len)*SizeOf(WideChar),0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + +procedure fpc_shortstr_to_widechararray(out res: array of widechar; const src: ShortString); compilerproc; +var + len: longint; + temp : widestring; +begin + len := length(src); + { make sure we don't access char 1 if length is 0 (JM) } + if len > 0 then + widestringmanager.ansi2widemoveproc(pchar(@src[1]),temp,len); + len := length(temp); + if len > length(res) then + len := length(res); +{$r-} + move(temp[1],res[0],len*sizeof(widechar)); + fillchar(res[len],(length(res)-len)*SizeOf(WideChar),0); +{$ifdef RangeCheckWasOn} +{$r+} +{$endif} +end; + +{$endif ndef FPC_STRTOCHARARRAYPROC} + +Function fpc_WideStr_Compare(const S1,S2 : WideString): SizeInt;[Public,Alias : 'FPC_WIDESTR_COMPARE']; compilerproc; +{ + Compares 2 WideStrings; + The result is + <0 if S1<S2 + 0 if S1=S2 + >0 if S1>S2 +} +Var + MaxI,Temp : SizeInt; +begin + if pointer(S1)=pointer(S2) then + begin + fpc_WideStr_Compare:=0; + exit; + end; + Maxi:=Length(S1); + temp:=Length(S2); + If MaxI>Temp then + MaxI:=Temp; + Temp:=CompareWord(S1[1],S2[1],MaxI); + if temp=0 then + temp:=Length(S1)-Length(S2); + fpc_WideStr_Compare:=Temp; +end; + +Function fpc_WideStr_Compare_Equal(const S1,S2 : WideString): SizeInt;[Public,Alias : 'FPC_WIDESTR_COMPARE_EQUAL']; compilerproc; +{ + Compares 2 WideStrings for equality only; + The result is + 0 if S1=S2 + <>0 if S1<>S2 +} +Var + MaxI : SizeInt; +begin + if pointer(S1)=pointer(S2) then + exit(0); + Maxi:=Length(S1); + If MaxI<>Length(S2) then + exit(-1) + else + exit(CompareWord(S1[1],S2[1],MaxI)); +end; + +Procedure fpc_WideStr_CheckZero(p : pointer);[Public,Alias : 'FPC_WIDESTR_CHECKZERO']; compilerproc; +begin + if p=nil then + HandleErrorFrame(201,get_frame); +end; + + +Procedure fpc_WideStr_CheckRange(len,index : SizeInt);[Public,Alias : 'FPC_WIDESTR_RANGECHECK']; compilerproc; +begin + if (index>len div 2) or (Index<1) then + HandleErrorFrame(201,get_frame); +end; + +Procedure fpc_WideStr_SetLength(Var S : WideString; l : SizeInt);[Public,Alias : 'FPC_WIDESTR_SETLENGTH']; compilerproc; +{ + Sets The length of string S to L. + Makes sure S is unique, and contains enough room. +} +Var + Temp : Pointer; + movelen: SizeInt; +begin + if (l>0) then + begin + if Pointer(S)=nil then + begin + { Need a complete new string...} + Pointer(s):=NewWideString(l); + end + { windows doesn't support reallocing widestrings, this code + is anyways subject to be removed because widestrings shouldn't be + ref. counted anymore (FK) } + else + if +{$ifdef MSWINDOWS} + not winwidestringalloc and +{$endif MSWINDOWS} +{$ifdef FPC_WINLIKEWIDESTRING} + not IsWideStringConstant(pointer(S)) +{$else} + (PWideRec(Pointer(S)-WideFirstOff)^.Ref = 1) +{$endif FPC_WINLIKEWIDESTRING} + then + begin + Dec(Pointer(S),WideFirstOff); + if SizeUInt(L*sizeof(WideChar)+WideRecLen)>MemSize(Pointer(S)) then + reallocmem(pointer(S), L*sizeof(WideChar)+WideRecLen); + Inc(Pointer(S), WideFirstOff); + end + else + begin + { Reallocation is needed... } + Temp:=Pointer(NewWideString(L)); + if Length(S)>0 then + begin + if l < succ(length(s)) then + movelen := l + { also move terminating null } + else + movelen := succ(length(s)); + Move(Pointer(S)^,Temp^,movelen * Sizeof(WideChar)); + end; + fpc_widestr_decr_ref(Pointer(S)); + Pointer(S):=Temp; + end; + { Force nil termination in case it gets shorter } + PWord(Pointer(S)+l*sizeof(WideChar))^:=0; +{$ifdef MSWINDOWS} + if not winwidestringalloc then +{$endif MSWINDOWS} + PWideRec(Pointer(S)-WideFirstOff)^.Len:=l*sizeof(WideChar); + end + else + begin + { Length=0 } + if Pointer(S)<>nil then + fpc_widestr_decr_ref (Pointer(S)); + Pointer(S):=Nil; + end; +end; + +{***************************************************************************** + Public functions, In interface. +*****************************************************************************} + +function WideCharToString(S : PWideChar) : AnsiString; + begin + result:=WideCharLenToString(s,Length(WideString(s))); + end; + +function StringToWideChar(const Src : AnsiString;Dest : PWideChar;DestSize : SizeInt) : PWideChar; + var + temp:widestring; + begin + widestringmanager.Ansi2WideMoveProc(PChar(Src),temp,Length(Src)); + if Length(temp)<DestSize then + move(temp[1],Dest^,Length(temp)*SizeOf(WideChar)) + else + move(temp[1],Dest^,(DestSize-1)*SizeOf(WideChar)); + + Dest[DestSize-1]:=#0; + + result:=Dest; + + end; + +function WideCharLenToString(S : PWideChar;Len : SizeInt) : AnsiString; + begin + //SetLength(result,Len); + widestringmanager.Wide2AnsiMoveproc(S,result,Len); + end; + +procedure WideCharLenToStrVar(Src : PWideChar;Len : SizeInt;out Dest : AnsiString); + begin + Dest:=WideCharLenToString(Src,Len); + end; + +procedure WideCharToStrVar(S : PWideChar;out Dest : AnsiString); + begin + Dest:=WideCharToString(S); + end; + + +Function fpc_widestr_Unique(Var S : Pointer): Pointer; [Public,Alias : 'FPC_WIDESTR_UNIQUE']; compilerproc; +{$ifdef FPC_WINLIKEWIDESTRING} + begin + pointer(result) := pointer(s); + end; +{$else FPC_WINLIKEWIDESTRING} +{ + Make sure reference count of S is 1, + using copy-on-write semantics. +} +Var + SNew : Pointer; + L : SizeInt; +begin + pointer(result) := pointer(s); + If Pointer(S)=Nil then + exit; + if PWideRec(Pointer(S)-WideFirstOff)^.Ref<>1 then + begin + L:=PWideRec(Pointer(S)-WideFirstOff)^.len div sizeof(WideChar); + SNew:=NewWideString (L); + Move (PWideChar(S)^,SNew^,(L+1)*sizeof(WideChar)); + PWideRec(SNew-WideFirstOff)^.len:=L * sizeof(WideChar); + fpc_widestr_decr_ref (Pointer(S)); { Thread safe } + pointer(S):=SNew; + pointer(result):=SNew; + end; +end; +{$endif FPC_WINLIKEWIDESTRING} + + +Function Fpc_WideStr_Copy (Const S : WideString; Index,Size : SizeInt) : WideString;compilerproc; +var + ResultAddress : Pointer; +begin + ResultAddress:=Nil; + dec(index); + if Index < 0 then + Index := 0; + { Check Size. Accounts for Zero-length S, the double check is needed because + Size can be maxint and will get <0 when adding index } + if (Size>Length(S)) or + (Index+Size>Length(S)) then + Size:=Length(S)-Index; + If Size>0 then + begin + If Index<0 Then + Index:=0; + ResultAddress:=Pointer(NewWideString (Size)); + if ResultAddress<>Nil then + begin + Move (PWideChar(S)[Index],ResultAddress^,Size*sizeof(WideChar)); + PWideRec(ResultAddress-WideFirstOff)^.Len:=Size*sizeof(WideChar); + PWideChar(ResultAddress+Size*sizeof(WideChar))^:=#0; + end; + end; + fpc_widestr_decr_ref(Pointer(fpc_widestr_copy)); + Pointer(fpc_widestr_Copy):=ResultAddress; +end; + + +Function Pos (Const Substr : WideString; Const Source : WideString) : SizeInt; +var + i,MaxLen : SizeInt; + pc : pwidechar; +begin + Pos:=0; + if Length(SubStr)>0 then + begin + MaxLen:=Length(source)-Length(SubStr); + i:=0; + pc:=@source[1]; + while (i<=MaxLen) do + begin + inc(i); + if (SubStr[1]=pc^) and + (CompareWord(Substr[1],pc^,Length(SubStr))=0) then + begin + Pos:=i; + exit; + end; + inc(pc); + end; + end; +end; + + +{ Faster version for a widechar alone } +Function Pos (c : WideChar; Const s : WideString) : SizeInt; +var + i: SizeInt; + pc : pwidechar; +begin + pc:=@s[1]; + for i:=1 to length(s) do + begin + if pc^=c then + begin + pos:=i; + exit; + end; + inc(pc); + end; + pos:=0; +end; + + +Function Pos (c : WideChar; Const s : AnsiString) : SizeInt; + begin + result:=Pos(c,WideString(s)); + end; + + +Function Pos (c : AnsiString; Const s : WideString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + result:=Pos(WideString(c),s); + end; + + +Function Pos (c : ShortString; Const s : WideString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + result:=Pos(WideString(c),s); + end; + + +Function Pos (c : WideString; Const s : AnsiString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + result:=Pos(c,WideString(s)); + end; + +{ Faster version for a char alone. Must be implemented because } +{ pos(c: char; const s: shortstring) also exists, so otherwise } +{ using pos(char,pchar) will always call the shortstring version } +{ (exact match for first argument), also with $h+ (JM) } +Function Pos (c : Char; Const s : WideString) : SizeInt; +var + i: SizeInt; + wc : widechar; + pc : pwidechar; +begin + wc:=c; + pc:=@s[1]; + for i:=1 to length(s) do + begin + if pc^=wc then + begin + pos:=i; + exit; + end; + inc(pc); + end; + pos:=0; +end; + + + +Procedure Delete (Var S : WideString; Index,Size: SizeInt); +Var + LS : SizeInt; +begin + If Length(S)=0 then + exit; + if index<=0 then + exit; + LS:=PWideRec(Pointer(S)-WideFirstOff)^.Len div sizeof(WideChar); + if (Index<=LS) and (Size>0) then + begin + UniqueString (S); + if Size+Index>LS then + Size:=LS-Index+1; + if Index+Size<=LS then + begin + Dec(Index); + Move(PWideChar(S)[Index+Size],PWideChar(S)[Index],(LS-Index-Size+1)*sizeof(WideChar)); + end; + Setlength(s,LS-Size); + end; +end; + + +Procedure Insert (Const Source : WideString; Var S : WideString; Index : SizeInt); +var + Temp : WideString; + LS : SizeInt; +begin + If Length(Source)=0 then + exit; + if index <= 0 then + index := 1; + Ls:=Length(S); + if index > LS then + index := LS+1; + Dec(Index); + Pointer(Temp) := NewWideString(Length(Source)+LS); + SetLength(Temp,Length(Source)+LS); + If Index>0 then + move (PWideChar(S)^,PWideChar(Temp)^,Index*sizeof(WideChar)); + Move (PWideChar(Source)^,PWideChar(Temp)[Index],Length(Source)*sizeof(WideChar)); + If (LS-Index)>0 then + Move(PWideChar(S)[Index],PWideChar(temp)[Length(Source)+index],(LS-Index)*sizeof(WideChar)); + S:=Temp; +end; + + +function UpCase(const s : WideString) : WideString; +begin + result:=widestringmanager.UpperWideStringProc(s); +end; + + +Procedure SetString (Out S : WideString; Buf : PWideChar; Len : SizeInt); +var + BufLen: SizeInt; +begin + SetLength(S,Len); + If (Buf<>Nil) and (Len>0) then + begin + BufLen := IndexWord(Buf^, Len+1, 0); + If (BufLen>0) and (BufLen < Len) then + Len := BufLen; + Move (Buf[0],S[1],Len*sizeof(WideChar)); + PWideChar(Pointer(S)+Len*sizeof(WideChar))^:=#0; + end; +end; + + +Procedure SetString (Out S : WideString; Buf : PChar; Len : SizeInt); +var + BufLen: SizeInt; +begin + SetLength(S,Len); + If (Buf<>Nil) and (Len>0) then + begin + BufLen := IndexByte(Buf^, Len+1, 0); + If (BufLen>0) and (BufLen < Len) then + Len := BufLen; + widestringmanager.Ansi2WideMoveProc(Buf,S,Len); + //PWideChar(Pointer(S)+Len*sizeof(WideChar))^:=#0; + end; +end; + + +{$ifndef FPUNONE} +Function fpc_Val_Real_WideStr(Const S : WideString; out Code : ValSInt): ValReal; [public, alias:'FPC_VAL_REAL_WIDESTR']; compilerproc; +Var + SS : String; +begin + fpc_Val_Real_WideStr := 0; + if length(S) > 255 then + code := 256 + else + begin + SS := S; + Val(SS,fpc_Val_Real_WideStr,code); + end; +end; +{$endif} + +function fpc_val_enum_widestr(str2ordindex:pointer;const s:widestring;out code:valsint):longint;compilerproc; + +var ss:shortstring; + +begin + if length(s)>255 then + code:=256 + else + begin + ss:=s; + val(ss,fpc_val_enum_widestr,code); + end; +end; + +Function fpc_Val_Currency_WideStr(Const S : WideString; out Code : ValSInt): Currency; [public, alias:'FPC_VAL_CURRENCY_WIDESTR']; compilerproc; +Var + SS : String; +begin + if length(S) > 255 then + begin + fpc_Val_Currency_WideStr:=0; + code := 256; + end + else + begin + SS := S; + Val(SS,fpc_Val_Currency_WideStr,code); + end; +end; + + +Function fpc_Val_UInt_WideStr (Const S : WideString; out Code : ValSInt): ValUInt; [public, alias:'FPC_VAL_UINT_WIDESTR']; compilerproc; +Var + SS : ShortString; +begin + fpc_Val_UInt_WideStr := 0; + if length(S) > 255 then + code := 256 + else + begin + SS := S; + Val(SS,fpc_Val_UInt_WideStr,code); + end; +end; + + +Function fpc_Val_SInt_WideStr (DestSize: SizeInt; Const S : WideString; out Code : ValSInt): ValSInt; [public, alias:'FPC_VAL_SINT_WIDESTR']; compilerproc; +Var + SS : ShortString; +begin + fpc_Val_SInt_WideStr:=0; + if length(S)>255 then + code:=256 + else + begin + SS := S; + fpc_Val_SInt_WideStr := int_Val_SInt_ShortStr(DestSize,SS,Code); + end; +end; + + +{$ifndef CPU64} + +Function fpc_Val_qword_WideStr (Const S : WideString; out Code : ValSInt): qword; [public, alias:'FPC_VAL_QWORD_WIDESTR']; compilerproc; +Var + SS : ShortString; +begin + fpc_Val_qword_WideStr:=0; + if length(S)>255 then + code:=256 + else + begin + SS := S; + Val(SS,fpc_Val_qword_WideStr,Code); + end; +end; + + +Function fpc_Val_int64_WideStr (Const S : WideString; out Code : ValSInt): Int64; [public, alias:'FPC_VAL_INT64_WIDESTR']; compilerproc; +Var + SS : ShortString; +begin + fpc_Val_int64_WideStr:=0; + if length(S)>255 then + code:=256 + else + begin + SS := S; + Val(SS,fpc_Val_int64_WideStr,Code); + end; +end; + +{$endif CPU64} + + +{$ifndef FPUNONE} +procedure fpc_WideStr_Float(d : ValReal;len,fr,rt : SizeInt;out s : WideString);compilerproc; +var + ss : shortstring; +begin + str_real(len,fr,d,treal_type(rt),ss); + s:=ss; +end; +{$endif} + +procedure fpc_widestr_enum(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out s:widestring);compilerproc; + +var ss:shortstring; + +begin + fpc_shortstr_enum(ordinal,len,typinfo,ord2strindex,ss); + s:=ss; +end; + +{$ifdef FPC_HAS_STR_CURRENCY} +procedure fpc_WideStr_Currency(c : Currency;len,fr : SizeInt;out s : WideString);compilerproc; +var + ss : shortstring; +begin + str(c:len:fr,ss); + s:=ss; +end; +{$endif FPC_HAS_STR_CURRENCY} + +Procedure fpc_WideStr_SInt(v : ValSint; Len : SizeInt; out S : WideString);compilerproc; +Var + SS : ShortString; +begin + Str (v:Len,SS); + S:=SS; +end; + + +Procedure fpc_WideStr_UInt(v : ValUInt;Len : SizeInt; out S : WideString);compilerproc; +Var + SS : ShortString; +begin + str(v:Len,SS); + S:=SS; +end; + + +{$ifndef CPU64} + +Procedure fpc_WideStr_Int64(v : Int64; Len : SizeInt; out S : WideString);compilerproc; +Var + SS : ShortString; +begin + Str (v:Len,SS); + S:=SS; +end; + + +Procedure fpc_WideStr_Qword(v : Qword;Len : SizeInt; out S : WideString);compilerproc; +Var + SS : ShortString; +begin + str(v:Len,SS); + S:=SS; +end; + +{$endif CPU64} + +function UnicodeToUtf8(Dest: PChar; Source: PWideChar; MaxBytes: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + if assigned(Source) then + Result:=UnicodeToUtf8(Dest,MaxBytes,Source,IndexWord(Source^,-1,0)) + else + Result:=0; + end; + + +function UnicodeToUtf8(Dest: PChar; MaxDestBytes: SizeUInt; Source: PWideChar; SourceChars: SizeUInt): SizeUInt; + var + i,j : SizeUInt; + w : word; + begin + result:=0; + if source=nil then + exit; + i:=0; + j:=0; + if assigned(Dest) then + begin + while (i<SourceChars) and (j<MaxDestBytes) do + begin + w:=word(Source[i]); + case w of + 0..$7f: + begin + Dest[j]:=char(w); + inc(j); + end; + $80..$7ff: + begin + if j+1>=MaxDestBytes then + break; + Dest[j]:=char($c0 or (w shr 6)); + Dest[j+1]:=char($80 or (w and $3f)); + inc(j,2); + end; + else + begin + if j+2>=MaxDestBytes then + break; + Dest[j]:=char($e0 or (w shr 12)); + Dest[j+1]:=char($80 or ((w shr 6)and $3f)); + Dest[j+2]:=char($80 or (w and $3f)); + inc(j,3); + end; + end; + inc(i); + end; + + if j>SizeUInt(MaxDestBytes-1) then + j:=MaxDestBytes-1; + + Dest[j]:=#0; + end + else + begin + while i<SourceChars do + begin + case word(Source[i]) of + $0..$7f: + inc(j); + $80..$7ff: + inc(j,2); + else + inc(j,3); + end; + inc(i); + end; + end; + result:=j+1; + end; + + +function Utf8ToUnicode(Dest: PWideChar; Source: PChar; MaxChars: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + if assigned(Source) then + Result:=Utf8ToUnicode(Dest,MaxChars,Source,strlen(Source)) + else + Result:=0; + end; + + +function Utf8ToUnicode(Dest: PWideChar; MaxDestChars: SizeUInt; Source: PChar; SourceBytes: SizeUInt): SizeUInt; + +var + i,j : SizeUInt; + w: SizeUInt; + b : byte; +begin + if not assigned(Source) then + begin + result:=0; + exit; + end; + result:=SizeUInt(-1); + i:=0; + j:=0; + if assigned(Dest) then + begin + while (j<MaxDestChars) and (i<SourceBytes) do + begin + b:=byte(Source[i]); + w:=b; + inc(i); + // 2 or 3 bytes? + if b>=$80 then + begin + w:=b and $3f; + if i>=SourceBytes then + exit; + // 3 bytes? + if (b and $20)<>0 then + begin + b:=byte(Source[i]); + inc(i); + if i>=SourceBytes then + exit; + if (b and $c0)<>$80 then + exit; + w:=(w shl 6) or (b and $3f); + end; + b:=byte(Source[i]); + w:=(w shl 6) or (b and $3f); + if (b and $c0)<>$80 then + exit; + inc(i); + end; + Dest[j]:=WideChar(w); + inc(j); + end; + if j>=MaxDestChars then j:=MaxDestChars-1; + Dest[j]:=#0; + end + else + begin + while i<SourceBytes do + begin + b:=byte(Source[i]); + inc(i); + // 2 or 3 bytes? + if b>=$80 then + begin + if i>=SourceBytes then + exit; + // 3 bytes? + b := b and $3f; + if (b and $20)<>0 then + begin + b:=byte(Source[i]); + inc(i); + if i>=SourceBytes then + exit; + if (b and $c0)<>$80 then + exit; + end; + if (byte(Source[i]) and $c0)<>$80 then + exit; + inc(i); + end; + inc(j); + end; + end; + result:=j+1; +end; + + +function UTF8Encode(const s : WideString) : UTF8String; + var + i : SizeInt; + hs : UTF8String; + begin + result:=''; + if s='' then + exit; + SetLength(hs,length(s)*3); + i:=UnicodeToUtf8(pchar(hs),length(hs)+1,PWideChar(s),length(s)); + if i>0 then + begin + SetLength(hs,i-1); + result:=hs; + end; + end; + + +function UTF8Decode(const s : UTF8String): WideString; + var + i : SizeInt; + hs : WideString; + begin + result:=''; + if s='' then + exit; + SetLength(hs,length(s)); + i:=Utf8ToUnicode(PWideChar(hs),length(hs)+1,pchar(s),length(s)); + if i>0 then + begin + SetLength(hs,i-1); + result:=hs; + end; + end; + + +function AnsiToUtf8(const s : ansistring): UTF8String;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + Result:=Utf8Encode(s); + end; + + +function Utf8ToAnsi(const s : UTF8String) : ansistring;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + Result:=Utf8Decode(s); + end; + + +{ converts an utf-16 code point or surrogate pair to utf-32 } +function utf16toutf32(const S: WideString; const index: SizeInt; out len: longint): UCS4Char; [public, alias: 'FPC_UTF16TOUTF32']; +var + w: widechar; +begin + { UTF-16 points in the range #$0-#$D7FF and #$E000-#$FFFF } + { are the same in UTF-32 } + w:=s[index]; + if (w<=#$d7ff) or + (w>=#$e000) then + begin + result:=UCS4Char(w); + len:=1; + end + { valid surrogate pair? } + else if (w<=#$dbff) and + { w>=#$d7ff check not needed, checked above } + (index<length(s)) and + (s[index+1]>=#$dc00) and + (s[index+1]<=#$dfff) then + { convert the surrogate pair to UTF-32 } + begin + result:=(UCS4Char(w)-$d800) shl 10 + (UCS4Char(s[index+1])-$dc00) + $10000; + len:=2; + end + else + { invalid surrogate -> do nothing } + begin + result:=UCS4Char(w); + len:=1; + end; +end; + + +function WideStringToUCS4String(const s : WideString) : UCS4String; + var + i, slen, + destindex : SizeInt; + len : longint; + begin + slen:=length(s); + setlength(result,slen+1); + i:=1; + destindex:=0; + while (i<=slen) do + begin + result[destindex]:=utf16toutf32(s,i,len); + inc(destindex); + inc(i,len); + end; + { destindex <= slen (surrogate pairs may have been merged) } + { destindex+1 for terminating #0 (dynamic arrays are } + { implicitely filled with zero) } + setlength(result,destindex+1); + end; + + +{ concatenates an utf-32 char to a widestring. S *must* be unique when entering. } +procedure ConcatUTF32ToWideStr(const nc: UCS4Char; var S: WideString; var index: SizeInt); +var + p : PWideChar; +begin + { if nc > $ffff, we need two places } + if (index+ord(nc > $ffff)>length(s)) then + if (length(s) < 10*256) then + setlength(s,length(s)+10) + else + setlength(s,length(s)+length(s) shr 8); + { we know that s is unique -> avoid uniquestring calls} + p:=@s[index]; + if (nc<$ffff) then + begin + p^:=widechar(nc); + inc(index); + end + else if (dword(nc)<=$10ffff) then + begin + p^:=widechar((nc - $10000) shr 10 + $d800); + (p+1)^:=widechar((nc - $10000) and $3ff + $dc00); + inc(index,2); + end + else + { invalid code point } + begin + p^:='?'; + inc(index); + end; +end; + + +function UCS4StringToWideString(const s : UCS4String) : WideString; + var + i : SizeInt; + resindex : SizeInt; + begin + { skip terminating #0 } + SetLength(result,length(s)-1); + resindex:=1; + for i:=0 to high(s)-1 do + ConcatUTF32ToWideStr(s[i],result,resindex); + { adjust result length (may be too big due to growing } + { for surrogate pairs) } + setlength(result,resindex-1); + end; + +const + SNoWidestrings = 'This binary has no widestrings support compiled in.'; + SRecompileWithWidestrings = 'Recompile the application with a widestrings-manager in the program uses clause.'; + +procedure unimplementedwidestring; + begin +{$ifdef FPC_HAS_FEATURE_CONSOLEIO} + If IsConsole then + begin + Writeln(StdErr,SNoWidestrings); + Writeln(StdErr,SRecompileWithWidestrings); + end; +{$endif FPC_HAS_FEATURE_CONSOLEIO} + HandleErrorFrame(233,get_frame); + end; + +{$warnings off} +function GenericWideCase(const s : WideString) : WideString; + begin + unimplementedwidestring; + end; + + +function CompareWideString(const s1, s2 : WideString) : PtrInt; + begin + unimplementedwidestring; + end; + + +function CompareTextWideString(const s1, s2 : WideString): PtrInt; + begin + unimplementedwidestring; + end; + + +function CharLengthPChar(const Str: PChar): PtrInt; + begin + unimplementedwidestring; + end; +{$warnings on} + +procedure initwidestringmanager; + begin + fillchar(widestringmanager,sizeof(widestringmanager),0); +{$ifndef HAS_WIDESTRINGMANAGER} + widestringmanager.Wide2AnsiMoveProc:=@defaultWide2AnsiMove; + widestringmanager.Ansi2WideMoveProc:=@defaultAnsi2WideMove; + widestringmanager.UpperWideStringProc:=@GenericWideCase; + widestringmanager.LowerWideStringProc:=@GenericWideCase; +{$endif HAS_WIDESTRINGMANAGER} + widestringmanager.CompareWideStringProc:=@CompareWideString; + widestringmanager.CompareTextWideStringProc:=@CompareTextWideString; + widestringmanager.CharLengthPCharProc:=@CharLengthPChar; + end; diff --git a/rtl/inc/wustrings.inc b/rtl/inc/wustrings.inc index e521e6156a..0e383565da 100644 --- a/rtl/inc/wustrings.inc +++ b/rtl/inc/wustrings.inc @@ -14,1989 +14,3 @@ **********************************************************************} -{ - This file contains the implementation of the WideString type, - and all things that are needed for it. - WideString is defined as a 'silent' pwidechar : - a pwidechar that points to : - - @-8 : SizeInt for reference count; - @-4 : SizeInt for size; size=number of bytes, not the number of chars. Divide or multiply - with sizeof(WideChar) to convert. This is needed to be compatible with Delphi and - Windows COM BSTR. - @ : String + Terminating #0; - Pwidechar(Widestring) is a valid typecast. - So WS[i] is converted to the address @WS+i-1. - - Constants should be assigned a reference count of -1 - Meaning that they can't be disposed of. -} - -Type - PWideRec = ^TWideRec; - TWideRec = Packed Record -{$ifdef FPC_WINLIKEWIDESTRING} - Len : DWord; -{$else FPC_WINLIKEWIDESTRING} - Ref : SizeInt; - Len : SizeInt; -{$endif FPC_WINLIKEWIDESTRING} - First : WideChar; - end; - -Const - WideRecLen = SizeOf(TWideRec); - WideFirstOff = SizeOf(TWideRec)-sizeof(WideChar); - -{ - Default WideChar <-> Char conversion is to only convert the - lower 127 chars, all others are translated to spaces. - - These routines can be overwritten for the Current Locale -} - -procedure DefaultWide2AnsiMove(source:pwidechar;var dest:ansistring;len:SizeInt); -var - i : SizeInt; -begin - setlength(dest,len); - for i:=1 to len do - begin - if word(source^)<256 then - dest[i]:=char(word(source^)) - else - dest[i]:='?'; - inc(source); - end; -end; - - -procedure DefaultAnsi2WideMove(source:pchar;var dest:widestring;len:SizeInt); -var - i : SizeInt; -begin - setlength(dest,len); - for i:=1 to len do - begin - dest[i]:=widechar(byte(source^)); - inc(source); - end; -end; - - -Procedure GetWideStringManager (Var Manager : TWideStringManager); -begin - manager:=widestringmanager; -end; - - -Procedure SetWideStringManager (Const New : TWideStringManager; Var Old: TWideStringManager); -begin - Old:=widestringmanager; - widestringmanager:=New; -end; - - -Procedure SetWideStringManager (Const New : TWideStringManager); -begin - widestringmanager:=New; -end; - -(* -Procedure UniqueWideString(Var S : WideString); [Public,Alias : 'FPC_WIDESTR_UNIQUE']; -{ - Make sure reference count of S is 1, - using copy-on-write semantics. -} - -begin -end; -*) - - -{**************************************************************************** - Internal functions, not in interface. -****************************************************************************} - - -procedure WideStringError; - begin - HandleErrorFrame(204,get_frame); - end; - - -{$ifdef WideStrDebug} -Procedure DumpWideRec(S : Pointer); -begin - If S=Nil then - Writeln ('String is nil') - Else - Begin - With PWideRec(S-WideFirstOff)^ do - begin - Write ('(Len:',len); - Writeln (' Ref: ',ref,')'); - end; - end; -end; -{$endif} - - -Function NewWideString(Len : SizeInt) : Pointer; -{ - Allocate a new WideString on the heap. - initialize it to zero length and reference count 1. -} -Var - P : Pointer; -begin -{$ifdef MSWINDOWS} - if winwidestringalloc then - begin - P:=SysAllocStringLen(nil,Len); - if P=nil then - WideStringError; - end - else -{$endif MSWINDOWS} - begin - GetMem(P,Len*sizeof(WideChar)+WideRecLen); - If P<>Nil then - begin - PWideRec(P)^.Len:=Len*2; { Initial length } -{$ifndef FPC_WINLIKEWIDESTRING} - PWideRec(P)^.Ref:=1; { Initial Refcount } -{$endif FPC_WINLIKEWIDESTRING} - PWideRec(P)^.First:=#0; { Terminating #0 } - inc(p,WideFirstOff); { Points to string now } - end - else - WideStringError; - end; - NewWideString:=P; -end; - - -Procedure DisposeWideString(Var S : Pointer); -{ - Deallocates a WideString From the heap. -} -begin - If S=Nil then - exit; -{$ifndef MSWINDOWS} - Dec (S,WideFirstOff); - Freemem(S); -{$else MSWINDOWS} - if winwidestringalloc then - SysFreeString(S) - else - begin - Dec (S,WideFirstOff); - Freemem(S); - end; -{$endif MSWINDOWS} - S:=Nil; -end; - -{$ifdef FPC_WINLIKEWIDESTRING} -var - __data_start: byte; external name '__data_start__'; - __data_end: byte; external name '__data_end__'; - -function IsWideStringConstant(S: pointer): boolean;{$ifdef SYSTEMINLINE}inline;{$endif} -{ - Returns True if widestring is constant (located in .data section); -} -begin - Result:=(S>=@__data_start) and (S<@__data_end); -end; -{$endif FPC_WINLIKEWIDESTRING} - -Procedure fpc_WideStr_Decr_Ref (Var S : Pointer);[Public,Alias:'FPC_WIDESTR_DECR_REF']; compilerproc; -{ - Decreases the ReferenceCount of a non constant widestring; - If the reference count is zero, deallocate the string; -} -Type - pSizeInt = ^SizeInt; -{$ifndef FPC_WINLIKEWIDESTRING} -Var - l : pSizeInt; -{$endif FPC_WINLIKEWIDESTRING} -Begin - { Zero string } - if S=Nil then - exit; -{$ifndef FPC_WINLIKEWIDESTRING} - { check for constant strings ...} - l:=@PWideRec(S-WideFirstOff)^.Ref; - if l^<0 then - exit; - - { declocked does a MT safe dec and returns true, if the counter is 0 } - if declocked(l^) then - { Ref count dropped to zero ... - ... remove } -{$else} - if not IsWideStringConstant(S) then -{$endif FPC_WINLIKEWIDESTRING} - DisposeWideString(S); -end; - -{ alias for internal use } -Procedure fpc_WideStr_Decr_Ref (Var S : Pointer);[external name 'FPC_WIDESTR_DECR_REF']; - -Procedure fpc_WideStr_Incr_Ref(Var S : Pointer);[Public,Alias:'FPC_WIDESTR_INCR_REF']; compilerproc; -{$ifdef FPC_WINLIKEWIDESTRING} - var - p : pointer; -{$endif FPC_WINLIKEWIDESTRING} - Begin - If S=Nil then - exit; -{$ifdef FPC_WINLIKEWIDESTRING} - p:=NewWidestring(length(WideString(S))); - move(s^,p^,(length(WideString(s))+1)*sizeof(widechar)); // double #0 too - s:=p; -{$else FPC_WINLIKEWIDESTRING} - { Let's be paranoid : Constant string ??} - If PWideRec(S-WideFirstOff)^.Ref<0 then - exit; - inclocked(PWideRec(S-WideFirstOff)^.Ref); -{$endif FPC_WINLIKEWIDESTRING} - end; - -{ alias for internal use } -Procedure fpc_WideStr_Incr_Ref (Var S : Pointer);[external name 'FPC_WIDESTR_INCR_REF']; - -{$ifndef FPC_STRTOSHORTSTRINGPROC} -function fpc_WideStr_To_ShortStr (high_of_res: SizeInt;const S2 : WideString): shortstring;[Public, alias: 'FPC_WIDESTR_TO_SHORTSTR']; compilerproc; -{ - Converts a WideString to a ShortString; -} -Var - Size : SizeInt; - temp : ansistring; -begin - result:=''; - Size:=Length(S2); - if Size>0 then - begin - If Size>high_of_res then - Size:=high_of_res; - widestringmanager.Wide2AnsiMoveProc(PWideChar(S2),temp,Size); - result:=temp; - end; -end; -{$else FPC_STRTOSHORTSTRINGPROC} -procedure fpc_WideStr_To_ShortStr (out res: ShortString;const S2 : WideString); [Public, alias: 'FPC_WIDESTR_TO_SHORTSTR'];compilerproc; -{ - Converts a WideString to a ShortString; -} -Var - Size : SizeInt; - temp : ansistring; -begin - res:=''; - Size:=Length(S2); - if Size>0 then - begin - If Size>high(res) then - Size:=high(res); - widestringmanager.Wide2AnsiMoveProc(PWideChar(S2),temp,Size); - res:=temp; - end; -end; -{$endif FPC_STRTOSHORTSTRINGPROC} - - -Function fpc_ShortStr_To_WideStr (Const S2 : ShortString): WideString;compilerproc; -{ - Converts a ShortString to a WideString; -} -Var - Size : SizeInt; -begin - result:=''; - Size:=Length(S2); - if Size>0 then - begin - widestringmanager.Ansi2WideMoveProc(PChar(@S2[1]),result,Size); - { Terminating Zero } - PWideChar(Pointer(fpc_ShortStr_To_WideStr)+Size*sizeof(WideChar))^:=#0; - end; -end; - - -Function fpc_WideStr_To_AnsiStr (const S2 : WideString): AnsiString; compilerproc; -{ - Converts a WideString to an AnsiString -} -Var - Size : SizeInt; -begin - result:=''; - Size:=Length(S2); - if Size>0 then - widestringmanager.Wide2AnsiMoveProc(PWideChar(Pointer(S2)),result,Size); -end; - - -Function fpc_AnsiStr_To_WideStr (Const S2 : AnsiString): WideString; compilerproc; -{ - Converts an AnsiString to a WideString; -} -Var - Size : SizeInt; -begin - result:=''; - Size:=Length(S2); - if Size>0 then - widestringmanager.Ansi2WideMoveProc(PChar(S2),result,Size); -end; - - -Function fpc_PWideChar_To_AnsiStr(const p : pwidechar): ansistring; compilerproc; -var - Size : SizeInt; -begin - result:=''; - if p=nil then - exit; - Size := IndexWord(p^, -1, 0); - if Size>0 then - widestringmanager.Wide2AnsiMoveProc(P,result,Size); -end; - - -Function fpc_PWideChar_To_WideStr(const p : pwidechar): widestring; compilerproc; -var - Size : SizeInt; -begin - result:=''; - if p=nil then - exit; - Size := IndexWord(p^, -1, 0); - Setlength(result,Size); - if Size>0 then - begin - Move(p^,PWideChar(Pointer(result))^,Size*sizeof(WideChar)); - { Terminating Zero } - PWideChar(Pointer(result)+Size*sizeof(WideChar))^:=#0; - end; -end; - - -{$ifndef FPC_STRTOSHORTSTRINGPROC} -Function fpc_PWideChar_To_ShortStr(const p : pwidechar): shortstring; compilerproc; -var - Size : SizeInt; - temp: ansistring; -begin - result:=''; - if p=nil then - exit; - Size := IndexWord(p^, $7fffffff, 0); - if Size>0 then - begin - widestringmanager.Wide2AnsiMoveProc(p,temp,Size); - result:=temp; - end; -end; -{$else FPC_STRTOSHORTSTRINGPROC} -procedure fpc_PWideChar_To_ShortStr(out res : shortstring;const p : pwidechar); compilerproc; -var - Size : SizeInt; - temp: ansistring; -begin - res:=''; - if p=nil then - exit; - Size:=IndexWord(p^, high(PtrInt), 0); - if Size>0 then - begin - widestringmanager.Wide2AnsiMoveProc(p,temp,Size); - res:=temp; - end; -end; -{$endif FPC_STRTOSHORTSTRINGPROC} - - -{ checked against the ansistring routine, 2001-05-27 (FK) } -Procedure fpc_WideStr_Assign (Var S1 : Pointer;S2 : Pointer);[Public,Alias:'FPC_WIDESTR_ASSIGN']; compilerproc; -{ - Assigns S2 to S1 (S1:=S2), taking in account reference counts. -} -begin -{$ifdef FPC_WINLIKEWIDESTRING} - if S1=S2 then exit; - if S2<>nil then - begin - if IsWideStringConstant(S1) then - begin - S1:=NewWidestring(length(WideString(S2))); - move(s2^,s1^,(length(WideString(s1))+1)*sizeof(widechar)); - end - else -{$ifdef MSWINDOWS} - if winwidestringalloc then - begin - if SysReAllocStringLen(S1, S2, Length(WideString(S2))) = 0 then - WideStringError; - end - else -{$endif MSWINDOWS} - begin - SetLength(WideString(S1),length(WideString(S2))); - move(s2^,s1^,(length(WideString(s1))+1)*sizeof(widechar)); - end; - end - else - begin - { Free S1 } - fpc_widestr_decr_ref (S1); - S1:=nil; - end; -{$else FPC_WINLIKEWIDESTRING} - If S2<>nil then - If PWideRec(S2-WideFirstOff)^.Ref>0 then - inclocked(PWideRec(S2-WideFirstOff)^.ref); - { Decrease the reference count on the old S1 } - fpc_widestr_decr_ref (S1); - s1:=s2; -{$endif FPC_WINLIKEWIDESTRING} -end; - - -{ alias for internal use } -Procedure fpc_WideStr_Assign (Var S1 : Pointer;S2 : Pointer);[external name 'FPC_WIDESTR_ASSIGN']; - -{$ifndef STR_CONCAT_PROCS} - -function fpc_WideStr_Concat (const S1,S2 : WideString): WideString; compilerproc; -Var - Size,Location : SizeInt; - pc : pwidechar; -begin - { only assign if s1 or s2 is empty } - if (S1='') then - begin - result:=s2; - exit; - end; - if (S2='') then - begin - result:=s1; - exit; - end; - Location:=Length(S1); - Size:=length(S2); - SetLength(result,Size+Location); - pc:=pwidechar(result); - Move(S1[1],pc^,Location*sizeof(WideChar)); - inc(pc,location); - Move(S2[1],pc^,(Size+1)*sizeof(WideChar)); -end; - - -function fpc_WideStr_Concat_multi (const sarr:array of Widestring): widestring; compilerproc; -Var - i : Longint; - p : pointer; - pc : pwidechar; - Size,NewSize : SizeInt; -begin - { First calculate size of the result so we can do - a single call to SetLength() } - NewSize:=0; - for i:=low(sarr) to high(sarr) do - inc(Newsize,length(sarr[i])); - SetLength(result,NewSize); - pc:=pwidechar(result); - for i:=low(sarr) to high(sarr) do - begin - p:=pointer(sarr[i]); - if assigned(p) then - begin - Size:=length(widestring(p)); - Move(pwidechar(p)^,pc^,(Size+1)*sizeof(WideChar)); - inc(pc,size); - end; - end; -end; - -{$else STR_CONCAT_PROCS} - -procedure fpc_WideStr_Concat (var DestS:Widestring;const S1,S2 : WideString); compilerproc; -Var - Size,Location : SizeInt; - same : boolean; -begin - { only assign if s1 or s2 is empty } - if (S1='') then - begin - DestS:=s2; - exit; - end; - if (S2='') then - begin - DestS:=s1; - exit; - end; - Location:=Length(S1); - Size:=length(S2); - { Use Pointer() typecasts to prevent extra conversion code } - if Pointer(DestS)=Pointer(S1) then - begin - same:=Pointer(S1)=Pointer(S2); - SetLength(DestS,Size+Location); - if same then - Move(Pointer(DestS)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size)*sizeof(WideChar)) - else - Move(Pointer(S2)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size+1)*sizeof(WideChar)); - end - else if Pointer(DestS)=Pointer(S2) then - begin - SetLength(DestS,Size+Location); - Move(Pointer(DestS)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size+1)*sizeof(WideChar)); - Move(Pointer(S1)^,Pointer(DestS)^,Location*sizeof(WideChar)); - end - else - begin - DestS:=''; - SetLength(DestS,Size+Location); - Move(Pointer(S1)^,Pointer(DestS)^,Location*sizeof(WideChar)); - Move(Pointer(S2)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size+1)*sizeof(WideChar)); - end; -end; - - -procedure fpc_WideStr_Concat_multi (var DestS:Widestring;const sarr:array of Widestring); compilerproc; -Var - i : Longint; - p,pc : pointer; - Size,NewLen : SizeInt; -{$ifndef FPC_WINLIKEWIDESTRING} - lowstart : longint; - destcopy : pointer; - OldDestLen : SizeInt; -{$else FPC_WINLIKEWIDESTRING} - DestTmp : Widestring; -{$endif FPC_WINLIKEWIDESTRING} -begin - if high(sarr)=0 then - begin - DestS:=''; - exit; - end; -{$ifndef FPC_WINLIKEWIDESTRING} - destcopy:=nil; - lowstart:=low(sarr); - if Pointer(DestS)=Pointer(sarr[lowstart]) then - inc(lowstart); - { Check for another reuse, then we can't use - the append optimization } - for i:=lowstart to high(sarr) do - begin - if Pointer(DestS)=Pointer(sarr[i]) then - begin - { if DestS is used somewhere in the middle of the expression, - we need to make sure the original string still exists after - we empty/modify DestS. - This trick only works with reference counted strings. Therefor - this optimization is disabled for WINLIKEWIDESTRING } - destcopy:=pointer(dests); - fpc_WideStr_Incr_Ref(destcopy); - lowstart:=low(sarr); - break; - end; - end; - { Start with empty DestS if we start with concatting - the first array element } - if lowstart=low(sarr) then - DestS:=''; - OldDestLen:=length(DestS); - { Calculate size of the result so we can do - a single call to SetLength() } - NewLen:=0; - for i:=low(sarr) to high(sarr) do - inc(NewLen,length(sarr[i])); - SetLength(DestS,NewLen); - { Concat all strings, except the string we already - copied in DestS } - pc:=Pointer(DestS)+OldDestLen*sizeof(WideChar); - for i:=lowstart to high(sarr) do - begin - p:=pointer(sarr[i]); - if assigned(p) then - begin - Size:=length(widestring(p)); - Move(p^,pc^,(Size+1)*sizeof(WideChar)); - inc(pc,size*sizeof(WideChar)); - end; - end; - fpc_WideStr_Decr_Ref(destcopy); -{$else FPC_WINLIKEWIDESTRING} - { First calculate size of the result so we can do - a single call to SetLength() } - NewLen:=0; - for i:=low(sarr) to high(sarr) do - inc(NewLen,length(sarr[i])); - SetLength(DestTmp,NewLen); - pc:=pwidechar(DestTmp); - for i:=low(sarr) to high(sarr) do - begin - p:=pointer(sarr[i]); - if assigned(p) then - begin - Size:=length(widestring(p)); - Move(p^,pc^,(Size+1)*sizeof(WideChar)); - inc(pc,size*sizeof(WideChar)); - end; - end; - DestS:=DestTmp; -{$endif FPC_WINLIKEWIDESTRING} -end; - -{$endif STR_CONCAT_PROCS} - -Function fpc_Char_To_WChar(const c : Char): WideChar; compilerproc; -var - w: widestring; -begin - widestringmanager.Ansi2WideMoveProc(@c, w, 1); - fpc_Char_To_WChar:= w[1]; -end; - - - -Function fpc_Char_To_WideStr(const c : Char): WideString; compilerproc; -{ - Converts a Char to a WideString; -} -begin - Setlength(fpc_Char_To_WideStr,1); - fpc_Char_To_WideStr[1]:=c; - { Terminating Zero } - PWideChar(Pointer(fpc_Char_To_WideStr)+sizeof(WideChar))^:=#0; -end; - - -Function fpc_WChar_To_Char(const c : WideChar): Char; compilerproc; -{ - Converts a WideChar to a Char; -} -var - s: ansistring; -begin - widestringmanager.Wide2AnsiMoveProc(@c, s, 1); - if length(s)=1 then - fpc_WChar_To_Char:= s[1] - else - fpc_WChar_To_Char:='?'; -end; - - -Function fpc_WChar_To_WideStr(const c : WideChar): WideString; compilerproc; -{ - Converts a WideChar to a WideString; -} -begin - Setlength (fpc_WChar_To_WideStr,1); - fpc_WChar_To_WideStr[1]:= c; -end; - - -Function fpc_WChar_To_AnsiStr(const c : WideChar): AnsiString; compilerproc; -{ - Converts a WideChar to a AnsiString; -} -begin - widestringmanager.Wide2AnsiMoveProc(@c, fpc_WChar_To_AnsiStr, 1); -end; - - -{$ifndef FPC_STRTOSHORTSTRINGPROC} -Function fpc_WChar_To_ShortStr(const c : WideChar): ShortString; compilerproc; -{ - Converts a WideChar to a ShortString; -} -var - s: ansistring; -begin - widestringmanager.Wide2AnsiMoveProc(@c, s, 1); - fpc_WChar_To_ShortStr:= s; -end; -{$else FPC_STRTOSHORTSTRINGPROC} -procedure fpc_WChar_To_ShortStr(out res : shortstring;const c : WideChar) compilerproc; -{ - Converts a WideChar to a ShortString; -} -var - s: ansistring; -begin - widestringmanager.Wide2AnsiMoveProc(@c,s,1); - res:=s; -end; -{$endif FPC_STRTOSHORTSTRINGPROC} - - -Function fpc_PChar_To_WideStr(const p : pchar): WideString; compilerproc; -Var - L : SizeInt; -begin - if (not assigned(p)) or (p[0]=#0) Then - begin - fpc_pchar_to_widestr := ''; - exit; - end; - l:=IndexChar(p^,-1,#0); - widestringmanager.Ansi2WideMoveProc(P,fpc_PChar_To_WideStr,l); -end; - - -Function fpc_CharArray_To_WideStr(const arr: array of char; zerobased: boolean = true): WideString; compilerproc; -var - i : SizeInt; -begin - if (zerobased) then - begin - if (arr[0]=#0) Then - begin - fpc_chararray_to_widestr := ''; - exit; - end; - i:=IndexChar(arr,high(arr)+1,#0); - if i = -1 then - i := high(arr)+1; - end - else - i := high(arr)+1; - SetLength(fpc_CharArray_To_WideStr,i); - widestringmanager.Ansi2WideMoveProc (pchar(@arr),fpc_CharArray_To_WideStr,i); -end; - - -{$ifndef FPC_STRTOSHORTSTRINGPROC} -function fpc_WideCharArray_To_ShortStr(const arr: array of widechar; zerobased: boolean = true): shortstring;[public,alias:'FPC_WIDECHARARRAY_TO_SHORTSTR']; compilerproc; -var - l: longint; - index: longint; - len: byte; - temp: ansistring; -begin - l := high(arr)+1; - if l>=256 then - l:=255 - else if l<0 then - l:=0; - if zerobased then - begin - index:=IndexWord(arr[0],l,0); - if (index < 0) then - len := l - else - len := index; - end - else - len := l; - widestringmanager.Wide2AnsiMoveProc (pwidechar(@arr),temp,len); - fpc_WideCharArray_To_ShortStr := temp; -end; -{$else FPC_STRTOSHORTSTRINGPROC} -procedure fpc_WideCharArray_To_ShortStr(out res : shortstring;const arr: array of widechar; zerobased: boolean = true);[public,alias:'FPC_WIDECHARARRAY_TO_SHORTSTR']; compilerproc; -var - l: longint; - index: ptrint; - len: byte; - temp: ansistring; -begin - l := high(arr)+1; - if l>=high(res)+1 then - l:=high(res) - else if l<0 then - l:=0; - if zerobased then - begin - index:=IndexWord(arr[0],l,0); - if index<0 then - len:=l - else - len:=index; - end - else - len:=l; - widestringmanager.Wide2AnsiMoveProc (pwidechar(@arr),temp,len); - res:=temp; -end; -{$endif FPC_STRTOSHORTSTRINGPROC} - -Function fpc_WideCharArray_To_AnsiStr(const arr: array of widechar; zerobased: boolean = true): AnsiString; compilerproc; -var - i : SizeInt; -begin - if (zerobased) then - begin - i:=IndexWord(arr,high(arr)+1,0); - if i = -1 then - i := high(arr)+1; - end - else - i := high(arr)+1; - SetLength(fpc_WideCharArray_To_AnsiStr,i); - widestringmanager.Wide2AnsiMoveProc (pwidechar(@arr),fpc_WideCharArray_To_AnsiStr,i); -end; - -Function fpc_WideCharArray_To_WideStr(const arr: array of widechar; zerobased: boolean = true): WideString; compilerproc; -var - i : SizeInt; -begin - if (zerobased) then - begin - i:=IndexWord(arr,high(arr)+1,0); - if i = -1 then - i := high(arr)+1; - end - else - i := high(arr)+1; - SetLength(fpc_WideCharArray_To_WideStr,i); - Move(arr[0], Pointer(fpc_WideCharArray_To_WideStr)^,i*sizeof(WideChar)); -end; - -{$ifndef FPC_STRTOCHARARRAYPROC} - -{ inside the compiler, the resulttype is modified to that of the actual } -{ chararray we're converting to (JM) } -function fpc_widestr_to_chararray(arraysize: SizeInt; const src: WideString): fpc_big_chararray;[public,alias: 'FPC_WIDESTR_TO_CHARARRAY']; compilerproc; -var - len: SizeInt; - temp: ansistring; -begin - len := length(src); - { make sure we don't dereference src if it can be nil (JM) } - if len > 0 then - widestringmanager.wide2ansimoveproc(pwidechar(@src[1]),temp,len); - len := length(temp); - if len > arraysize then - len := arraysize; -{$r-} - move(temp[1],fpc_widestr_to_chararray[0],len); - fillchar(fpc_widestr_to_chararray[len],arraysize-len,0); -{$ifdef RangeCheckWasOn} -{$r+} -{$endif} -end; - - -{ inside the compiler, the resulttype is modified to that of the actual } -{ widechararray we're converting to (JM) } -function fpc_widestr_to_widechararray(arraysize: SizeInt; const src: WideString): fpc_big_widechararray;[public,alias: 'FPC_WIDESTR_TO_WIDECHARARRAY']; compilerproc; -var - len: SizeInt; -begin - len := length(src); - if len > arraysize then - len := arraysize; -{$r-} - { make sure we don't try to access element 1 of the ansistring if it's nil } - if len > 0 then - move(src[1],fpc_widestr_to_widechararray[0],len*SizeOf(WideChar)); - fillchar(fpc_widestr_to_widechararray[len],(arraysize-len)*SizeOf(WideChar),0); -{$ifdef RangeCheckWasOn} -{$r+} -{$endif} -end; - - -{ inside the compiler, the resulttype is modified to that of the actual } -{ chararray we're converting to (JM) } -function fpc_ansistr_to_widechararray(arraysize: SizeInt; const src: AnsiString): fpc_big_widechararray;[public,alias: 'FPC_ANSISTR_TO_WIDECHARARRAY']; compilerproc; -var - len: SizeInt; - temp: widestring; -begin - len := length(src); - { make sure we don't dereference src if it can be nil (JM) } - if len > 0 then - widestringmanager.ansi2widemoveproc(pchar(@src[1]),temp,len); - len := length(temp); - if len > arraysize then - len := arraysize; - -{$r-} - move(temp[1],fpc_ansistr_to_widechararray[0],len*sizeof(widechar)); - fillchar(fpc_ansistr_to_widechararray[len],(arraysize-len)*SizeOf(WideChar),0); -{$ifdef RangeCheckWasOn} -{$r+} -{$endif} -end; - -function fpc_shortstr_to_widechararray(arraysize: SizeInt; const src: ShortString): fpc_big_widechararray;[public,alias: 'FPC_SHORTSTR_TO_WIDECHARARRAY']; compilerproc; -var - len: longint; - temp : widestring; -begin - len := length(src); - { make sure we don't access char 1 if length is 0 (JM) } - if len > 0 then - widestringmanager.ansi2widemoveproc(pchar(@src[1]),temp,len); - len := length(temp); - if len > arraysize then - len := arraysize; -{$r-} - move(temp[1],fpc_shortstr_to_widechararray[0],len*sizeof(widechar)); - fillchar(fpc_shortstr_to_widechararray[len],(arraysize-len)*SizeOf(WideChar),0); -{$ifdef RangeCheckWasOn} -{$r+} -{$endif} -end; - -{$else ndef FPC_STRTOCHARARRAYPROC} - -procedure fpc_widestr_to_chararray(out res: array of char; const src: WideString); compilerproc; -var - len: SizeInt; - temp: ansistring; -begin - len := length(src); - { make sure we don't dereference src if it can be nil (JM) } - if len > 0 then - widestringmanager.wide2ansimoveproc(pwidechar(@src[1]),temp,len); - len := length(temp); - if len > length(res) then - len := length(res); -{$r-} - move(temp[1],res[0],len); - fillchar(res[len],length(res)-len,0); -{$ifdef RangeCheckWasOn} -{$r+} -{$endif} -end; - - -procedure fpc_widestr_to_widechararray(out res: array of widechar; const src: WideString); compilerproc; -var - len: SizeInt; -begin - len := length(src); - if len > length(res) then - len := length(res); -{$r-} - { make sure we don't try to access element 1 of the ansistring if it's nil } - if len > 0 then - move(src[1],res[0],len*SizeOf(WideChar)); - fillchar(res[len],(length(res)-len)*SizeOf(WideChar),0); -{$ifdef RangeCheckWasOn} -{$r+} -{$endif} -end; - - -procedure fpc_ansistr_to_widechararray(out res: array of widechar; const src: AnsiString); compilerproc; -var - len: SizeInt; - temp: widestring; -begin - len := length(src); - { make sure we don't dereference src if it can be nil (JM) } - if len > 0 then - widestringmanager.ansi2widemoveproc(pchar(@src[1]),temp,len); - len := length(temp); - if len > length(res) then - len := length(res); - -{$r-} - move(temp[1],res[0],len*sizeof(widechar)); - fillchar(res[len],(length(res)-len)*SizeOf(WideChar),0); -{$ifdef RangeCheckWasOn} -{$r+} -{$endif} -end; - -procedure fpc_shortstr_to_widechararray(out res: array of widechar; const src: ShortString); compilerproc; -var - len: longint; - temp : widestring; -begin - len := length(src); - { make sure we don't access char 1 if length is 0 (JM) } - if len > 0 then - widestringmanager.ansi2widemoveproc(pchar(@src[1]),temp,len); - len := length(temp); - if len > length(res) then - len := length(res); -{$r-} - move(temp[1],res[0],len*sizeof(widechar)); - fillchar(res[len],(length(res)-len)*SizeOf(WideChar),0); -{$ifdef RangeCheckWasOn} -{$r+} -{$endif} -end; - -{$endif ndef FPC_STRTOCHARARRAYPROC} - -Function fpc_WideStr_Compare(const S1,S2 : WideString): SizeInt;[Public,Alias : 'FPC_WIDESTR_COMPARE']; compilerproc; -{ - Compares 2 WideStrings; - The result is - <0 if S1<S2 - 0 if S1=S2 - >0 if S1>S2 -} -Var - MaxI,Temp : SizeInt; -begin - if pointer(S1)=pointer(S2) then - begin - fpc_WideStr_Compare:=0; - exit; - end; - Maxi:=Length(S1); - temp:=Length(S2); - If MaxI>Temp then - MaxI:=Temp; - Temp:=CompareWord(S1[1],S2[1],MaxI); - if temp=0 then - temp:=Length(S1)-Length(S2); - fpc_WideStr_Compare:=Temp; -end; - -Function fpc_WideStr_Compare_Equal(const S1,S2 : WideString): SizeInt;[Public,Alias : 'FPC_WIDESTR_COMPARE_EQUAL']; compilerproc; -{ - Compares 2 WideStrings for equality only; - The result is - 0 if S1=S2 - <>0 if S1<>S2 -} -Var - MaxI : SizeInt; -begin - if pointer(S1)=pointer(S2) then - exit(0); - Maxi:=Length(S1); - If MaxI<>Length(S2) then - exit(-1) - else - exit(CompareWord(S1[1],S2[1],MaxI)); -end; - -Procedure fpc_WideStr_CheckZero(p : pointer);[Public,Alias : 'FPC_WIDESTR_CHECKZERO']; compilerproc; -begin - if p=nil then - HandleErrorFrame(201,get_frame); -end; - - -Procedure fpc_WideStr_CheckRange(len,index : SizeInt);[Public,Alias : 'FPC_WIDESTR_RANGECHECK']; compilerproc; -begin - if (index>len div 2) or (Index<1) then - HandleErrorFrame(201,get_frame); -end; - -Procedure fpc_WideStr_SetLength(Var S : WideString; l : SizeInt);[Public,Alias : 'FPC_WIDESTR_SETLENGTH']; compilerproc; -{ - Sets The length of string S to L. - Makes sure S is unique, and contains enough room. -} -Var - Temp : Pointer; - movelen: SizeInt; -begin - if (l>0) then - begin - if Pointer(S)=nil then - begin - { Need a complete new string...} - Pointer(s):=NewWideString(l); - end - { windows doesn't support reallocing widestrings, this code - is anyways subject to be removed because widestrings shouldn't be - ref. counted anymore (FK) } - else - if -{$ifdef MSWINDOWS} - not winwidestringalloc and -{$endif MSWINDOWS} -{$ifdef FPC_WINLIKEWIDESTRING} - not IsWideStringConstant(pointer(S)) -{$else} - (PWideRec(Pointer(S)-WideFirstOff)^.Ref = 1) -{$endif FPC_WINLIKEWIDESTRING} - then - begin - Dec(Pointer(S),WideFirstOff); - if SizeUInt(L*sizeof(WideChar)+WideRecLen)>MemSize(Pointer(S)) then - reallocmem(pointer(S), L*sizeof(WideChar)+WideRecLen); - Inc(Pointer(S), WideFirstOff); - end - else - begin - { Reallocation is needed... } - Temp:=Pointer(NewWideString(L)); - if Length(S)>0 then - begin - if l < succ(length(s)) then - movelen := l - { also move terminating null } - else - movelen := succ(length(s)); - Move(Pointer(S)^,Temp^,movelen * Sizeof(WideChar)); - end; - fpc_widestr_decr_ref(Pointer(S)); - Pointer(S):=Temp; - end; - { Force nil termination in case it gets shorter } - PWord(Pointer(S)+l*sizeof(WideChar))^:=0; -{$ifdef MSWINDOWS} - if not winwidestringalloc then -{$endif MSWINDOWS} - PWideRec(Pointer(S)-WideFirstOff)^.Len:=l*sizeof(WideChar); - end - else - begin - { Length=0 } - if Pointer(S)<>nil then - fpc_widestr_decr_ref (Pointer(S)); - Pointer(S):=Nil; - end; -end; - -{***************************************************************************** - Public functions, In interface. -*****************************************************************************} - -function WideCharToString(S : PWideChar) : AnsiString; - begin - result:=WideCharLenToString(s,Length(WideString(s))); - end; - -function StringToWideChar(const Src : AnsiString;Dest : PWideChar;DestSize : SizeInt) : PWideChar; - var - temp:widestring; - begin - widestringmanager.Ansi2WideMoveProc(PChar(Src),temp,Length(Src)); - if Length(temp)<DestSize then - move(temp[1],Dest^,Length(temp)*SizeOf(WideChar)) - else - move(temp[1],Dest^,(DestSize-1)*SizeOf(WideChar)); - - Dest[DestSize-1]:=#0; - - result:=Dest; - - end; - -function WideCharLenToString(S : PWideChar;Len : SizeInt) : AnsiString; - begin - //SetLength(result,Len); - widestringmanager.Wide2AnsiMoveproc(S,result,Len); - end; - -procedure WideCharLenToStrVar(Src : PWideChar;Len : SizeInt;out Dest : AnsiString); - begin - Dest:=WideCharLenToString(Src,Len); - end; - -procedure WideCharToStrVar(S : PWideChar;out Dest : AnsiString); - begin - Dest:=WideCharToString(S); - end; - - -Function fpc_widestr_Unique(Var S : Pointer): Pointer; [Public,Alias : 'FPC_WIDESTR_UNIQUE']; compilerproc; -{$ifdef FPC_WINLIKEWIDESTRING} - begin - pointer(result) := pointer(s); - end; -{$else FPC_WINLIKEWIDESTRING} -{ - Make sure reference count of S is 1, - using copy-on-write semantics. -} -Var - SNew : Pointer; - L : SizeInt; -begin - pointer(result) := pointer(s); - If Pointer(S)=Nil then - exit; - if PWideRec(Pointer(S)-WideFirstOff)^.Ref<>1 then - begin - L:=PWideRec(Pointer(S)-WideFirstOff)^.len div sizeof(WideChar); - SNew:=NewWideString (L); - Move (PWideChar(S)^,SNew^,(L+1)*sizeof(WideChar)); - PWideRec(SNew-WideFirstOff)^.len:=L * sizeof(WideChar); - fpc_widestr_decr_ref (Pointer(S)); { Thread safe } - pointer(S):=SNew; - pointer(result):=SNew; - end; -end; -{$endif FPC_WINLIKEWIDESTRING} - - -Function Fpc_WideStr_Copy (Const S : WideString; Index,Size : SizeInt) : WideString;compilerproc; -var - ResultAddress : Pointer; -begin - ResultAddress:=Nil; - dec(index); - if Index < 0 then - Index := 0; - { Check Size. Accounts for Zero-length S, the double check is needed because - Size can be maxint and will get <0 when adding index } - if (Size>Length(S)) or - (Index+Size>Length(S)) then - Size:=Length(S)-Index; - If Size>0 then - begin - If Index<0 Then - Index:=0; - ResultAddress:=Pointer(NewWideString (Size)); - if ResultAddress<>Nil then - begin - Move (PWideChar(S)[Index],ResultAddress^,Size*sizeof(WideChar)); - PWideRec(ResultAddress-WideFirstOff)^.Len:=Size*sizeof(WideChar); - PWideChar(ResultAddress+Size*sizeof(WideChar))^:=#0; - end; - end; - fpc_widestr_decr_ref(Pointer(fpc_widestr_copy)); - Pointer(fpc_widestr_Copy):=ResultAddress; -end; - - -Function Pos (Const Substr : WideString; Const Source : WideString) : SizeInt; -var - i,MaxLen : SizeInt; - pc : pwidechar; -begin - Pos:=0; - if Length(SubStr)>0 then - begin - MaxLen:=Length(source)-Length(SubStr); - i:=0; - pc:=@source[1]; - while (i<=MaxLen) do - begin - inc(i); - if (SubStr[1]=pc^) and - (CompareWord(Substr[1],pc^,Length(SubStr))=0) then - begin - Pos:=i; - exit; - end; - inc(pc); - end; - end; -end; - - -{ Faster version for a widechar alone } -Function Pos (c : WideChar; Const s : WideString) : SizeInt; -var - i: SizeInt; - pc : pwidechar; -begin - pc:=@s[1]; - for i:=1 to length(s) do - begin - if pc^=c then - begin - pos:=i; - exit; - end; - inc(pc); - end; - pos:=0; -end; - - -Function Pos (c : WideChar; Const s : AnsiString) : SizeInt; - begin - result:=Pos(c,WideString(s)); - end; - - -Function Pos (c : AnsiString; Const s : WideString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} - begin - result:=Pos(WideString(c),s); - end; - - -Function Pos (c : ShortString; Const s : WideString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} - begin - result:=Pos(WideString(c),s); - end; - - -Function Pos (c : WideString; Const s : AnsiString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} - begin - result:=Pos(c,WideString(s)); - end; - -{ Faster version for a char alone. Must be implemented because } -{ pos(c: char; const s: shortstring) also exists, so otherwise } -{ using pos(char,pchar) will always call the shortstring version } -{ (exact match for first argument), also with $h+ (JM) } -Function Pos (c : Char; Const s : WideString) : SizeInt; -var - i: SizeInt; - wc : widechar; - pc : pwidechar; -begin - wc:=c; - pc:=@s[1]; - for i:=1 to length(s) do - begin - if pc^=wc then - begin - pos:=i; - exit; - end; - inc(pc); - end; - pos:=0; -end; - - - -Procedure Delete (Var S : WideString; Index,Size: SizeInt); -Var - LS : SizeInt; -begin - If Length(S)=0 then - exit; - if index<=0 then - exit; - LS:=PWideRec(Pointer(S)-WideFirstOff)^.Len div sizeof(WideChar); - if (Index<=LS) and (Size>0) then - begin - UniqueString (S); - if Size+Index>LS then - Size:=LS-Index+1; - if Index+Size<=LS then - begin - Dec(Index); - Move(PWideChar(S)[Index+Size],PWideChar(S)[Index],(LS-Index-Size+1)*sizeof(WideChar)); - end; - Setlength(s,LS-Size); - end; -end; - - -Procedure Insert (Const Source : WideString; Var S : WideString; Index : SizeInt); -var - Temp : WideString; - LS : SizeInt; -begin - If Length(Source)=0 then - exit; - if index <= 0 then - index := 1; - Ls:=Length(S); - if index > LS then - index := LS+1; - Dec(Index); - Pointer(Temp) := NewWideString(Length(Source)+LS); - SetLength(Temp,Length(Source)+LS); - If Index>0 then - move (PWideChar(S)^,PWideChar(Temp)^,Index*sizeof(WideChar)); - Move (PWideChar(Source)^,PWideChar(Temp)[Index],Length(Source)*sizeof(WideChar)); - If (LS-Index)>0 then - Move(PWideChar(S)[Index],PWideChar(temp)[Length(Source)+index],(LS-Index)*sizeof(WideChar)); - S:=Temp; -end; - - -function UpCase(const s : WideString) : WideString; -begin - result:=widestringmanager.UpperWideStringProc(s); -end; - - -Procedure SetString (Out S : WideString; Buf : PWideChar; Len : SizeInt); -var - BufLen: SizeInt; -begin - SetLength(S,Len); - If (Buf<>Nil) and (Len>0) then - begin - BufLen := IndexWord(Buf^, Len+1, 0); - If (BufLen>0) and (BufLen < Len) then - Len := BufLen; - Move (Buf[0],S[1],Len*sizeof(WideChar)); - PWideChar(Pointer(S)+Len*sizeof(WideChar))^:=#0; - end; -end; - - -Procedure SetString (Out S : WideString; Buf : PChar; Len : SizeInt); -var - BufLen: SizeInt; -begin - SetLength(S,Len); - If (Buf<>Nil) and (Len>0) then - begin - BufLen := IndexByte(Buf^, Len+1, 0); - If (BufLen>0) and (BufLen < Len) then - Len := BufLen; - widestringmanager.Ansi2WideMoveProc(Buf,S,Len); - //PWideChar(Pointer(S)+Len*sizeof(WideChar))^:=#0; - end; -end; - - -{$ifndef FPUNONE} -Function fpc_Val_Real_WideStr(Const S : WideString; out Code : ValSInt): ValReal; [public, alias:'FPC_VAL_REAL_WIDESTR']; compilerproc; -Var - SS : String; -begin - fpc_Val_Real_WideStr := 0; - if length(S) > 255 then - code := 256 - else - begin - SS := S; - Val(SS,fpc_Val_Real_WideStr,code); - end; -end; -{$endif} - -function fpc_val_enum_widestr(str2ordindex:pointer;const s:widestring;out code:valsint):longint;compilerproc; - -var ss:shortstring; - -begin - if length(s)>255 then - code:=256 - else - begin - ss:=s; - val(ss,fpc_val_enum_widestr,code); - end; -end; - -Function fpc_Val_Currency_WideStr(Const S : WideString; out Code : ValSInt): Currency; [public, alias:'FPC_VAL_CURRENCY_WIDESTR']; compilerproc; -Var - SS : String; -begin - if length(S) > 255 then - begin - fpc_Val_Currency_WideStr:=0; - code := 256; - end - else - begin - SS := S; - Val(SS,fpc_Val_Currency_WideStr,code); - end; -end; - - -Function fpc_Val_UInt_WideStr (Const S : WideString; out Code : ValSInt): ValUInt; [public, alias:'FPC_VAL_UINT_WIDESTR']; compilerproc; -Var - SS : ShortString; -begin - fpc_Val_UInt_WideStr := 0; - if length(S) > 255 then - code := 256 - else - begin - SS := S; - Val(SS,fpc_Val_UInt_WideStr,code); - end; -end; - - -Function fpc_Val_SInt_WideStr (DestSize: SizeInt; Const S : WideString; out Code : ValSInt): ValSInt; [public, alias:'FPC_VAL_SINT_WIDESTR']; compilerproc; -Var - SS : ShortString; -begin - fpc_Val_SInt_WideStr:=0; - if length(S)>255 then - code:=256 - else - begin - SS := S; - fpc_Val_SInt_WideStr := int_Val_SInt_ShortStr(DestSize,SS,Code); - end; -end; - - -{$ifndef CPU64} - -Function fpc_Val_qword_WideStr (Const S : WideString; out Code : ValSInt): qword; [public, alias:'FPC_VAL_QWORD_WIDESTR']; compilerproc; -Var - SS : ShortString; -begin - fpc_Val_qword_WideStr:=0; - if length(S)>255 then - code:=256 - else - begin - SS := S; - Val(SS,fpc_Val_qword_WideStr,Code); - end; -end; - - -Function fpc_Val_int64_WideStr (Const S : WideString; out Code : ValSInt): Int64; [public, alias:'FPC_VAL_INT64_WIDESTR']; compilerproc; -Var - SS : ShortString; -begin - fpc_Val_int64_WideStr:=0; - if length(S)>255 then - code:=256 - else - begin - SS := S; - Val(SS,fpc_Val_int64_WideStr,Code); - end; -end; - -{$endif CPU64} - - -{$ifndef FPUNONE} -procedure fpc_WideStr_Float(d : ValReal;len,fr,rt : SizeInt;out s : WideString);compilerproc; -var - ss : shortstring; -begin - str_real(len,fr,d,treal_type(rt),ss); - s:=ss; -end; -{$endif} - -procedure fpc_widestr_enum(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out s:widestring);compilerproc; - -var ss:shortstring; - -begin - fpc_shortstr_enum(ordinal,len,typinfo,ord2strindex,ss); - s:=ss; -end; - -{$ifdef FPC_HAS_STR_CURRENCY} -procedure fpc_WideStr_Currency(c : Currency;len,fr : SizeInt;out s : WideString);compilerproc; -var - ss : shortstring; -begin - str(c:len:fr,ss); - s:=ss; -end; -{$endif FPC_HAS_STR_CURRENCY} - -Procedure fpc_WideStr_SInt(v : ValSint; Len : SizeInt; out S : WideString);compilerproc; -Var - SS : ShortString; -begin - Str (v:Len,SS); - S:=SS; -end; - - -Procedure fpc_WideStr_UInt(v : ValUInt;Len : SizeInt; out S : WideString);compilerproc; -Var - SS : ShortString; -begin - str(v:Len,SS); - S:=SS; -end; - - -{$ifndef CPU64} - -Procedure fpc_WideStr_Int64(v : Int64; Len : SizeInt; out S : WideString);compilerproc; -Var - SS : ShortString; -begin - Str (v:Len,SS); - S:=SS; -end; - - -Procedure fpc_WideStr_Qword(v : Qword;Len : SizeInt; out S : WideString);compilerproc; -Var - SS : ShortString; -begin - str(v:Len,SS); - S:=SS; -end; - -{$endif CPU64} - -function UnicodeToUtf8(Dest: PChar; Source: PWideChar; MaxBytes: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} - begin - if assigned(Source) then - Result:=UnicodeToUtf8(Dest,MaxBytes,Source,IndexWord(Source^,-1,0)) - else - Result:=0; - end; - - -function UnicodeToUtf8(Dest: PChar; MaxDestBytes: SizeUInt; Source: PWideChar; SourceChars: SizeUInt): SizeUInt; - var - i,j : SizeUInt; - w : word; - begin - result:=0; - if source=nil then - exit; - i:=0; - j:=0; - if assigned(Dest) then - begin - while (i<SourceChars) and (j<MaxDestBytes) do - begin - w:=word(Source[i]); - case w of - 0..$7f: - begin - Dest[j]:=char(w); - inc(j); - end; - $80..$7ff: - begin - if j+1>=MaxDestBytes then - break; - Dest[j]:=char($c0 or (w shr 6)); - Dest[j+1]:=char($80 or (w and $3f)); - inc(j,2); - end; - else - begin - if j+2>=MaxDestBytes then - break; - Dest[j]:=char($e0 or (w shr 12)); - Dest[j+1]:=char($80 or ((w shr 6)and $3f)); - Dest[j+2]:=char($80 or (w and $3f)); - inc(j,3); - end; - end; - inc(i); - end; - - if j>SizeUInt(MaxDestBytes-1) then - j:=MaxDestBytes-1; - - Dest[j]:=#0; - end - else - begin - while i<SourceChars do - begin - case word(Source[i]) of - $0..$7f: - inc(j); - $80..$7ff: - inc(j,2); - else - inc(j,3); - end; - inc(i); - end; - end; - result:=j+1; - end; - - -function Utf8ToUnicode(Dest: PWideChar; Source: PChar; MaxChars: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif} - begin - if assigned(Source) then - Result:=Utf8ToUnicode(Dest,MaxChars,Source,strlen(Source)) - else - Result:=0; - end; - - -function Utf8ToUnicode(Dest: PWideChar; MaxDestChars: SizeUInt; Source: PChar; SourceBytes: SizeUInt): SizeUInt; - -var - i,j : SizeUInt; - w: SizeUInt; - b : byte; -begin - if not assigned(Source) then - begin - result:=0; - exit; - end; - result:=SizeUInt(-1); - i:=0; - j:=0; - if assigned(Dest) then - begin - while (j<MaxDestChars) and (i<SourceBytes) do - begin - b:=byte(Source[i]); - w:=b; - inc(i); - // 2 or 3 bytes? - if b>=$80 then - begin - w:=b and $3f; - if i>=SourceBytes then - exit; - // 3 bytes? - if (b and $20)<>0 then - begin - b:=byte(Source[i]); - inc(i); - if i>=SourceBytes then - exit; - if (b and $c0)<>$80 then - exit; - w:=(w shl 6) or (b and $3f); - end; - b:=byte(Source[i]); - w:=(w shl 6) or (b and $3f); - if (b and $c0)<>$80 then - exit; - inc(i); - end; - Dest[j]:=WideChar(w); - inc(j); - end; - if j>=MaxDestChars then j:=MaxDestChars-1; - Dest[j]:=#0; - end - else - begin - while i<SourceBytes do - begin - b:=byte(Source[i]); - inc(i); - // 2 or 3 bytes? - if b>=$80 then - begin - if i>=SourceBytes then - exit; - // 3 bytes? - b := b and $3f; - if (b and $20)<>0 then - begin - b:=byte(Source[i]); - inc(i); - if i>=SourceBytes then - exit; - if (b and $c0)<>$80 then - exit; - end; - if (byte(Source[i]) and $c0)<>$80 then - exit; - inc(i); - end; - inc(j); - end; - end; - result:=j+1; -end; - - -function UTF8Encode(const s : WideString) : UTF8String; - var - i : SizeInt; - hs : UTF8String; - begin - result:=''; - if s='' then - exit; - SetLength(hs,length(s)*3); - i:=UnicodeToUtf8(pchar(hs),length(hs)+1,PWideChar(s),length(s)); - if i>0 then - begin - SetLength(hs,i-1); - result:=hs; - end; - end; - - -function UTF8Decode(const s : UTF8String): WideString; - var - i : SizeInt; - hs : WideString; - begin - result:=''; - if s='' then - exit; - SetLength(hs,length(s)); - i:=Utf8ToUnicode(PWideChar(hs),length(hs)+1,pchar(s),length(s)); - if i>0 then - begin - SetLength(hs,i-1); - result:=hs; - end; - end; - - -function AnsiToUtf8(const s : ansistring): UTF8String;{$ifdef SYSTEMINLINE}inline;{$endif} - begin - Result:=Utf8Encode(s); - end; - - -function Utf8ToAnsi(const s : UTF8String) : ansistring;{$ifdef SYSTEMINLINE}inline;{$endif} - begin - Result:=Utf8Decode(s); - end; - - -{ converts an utf-16 code point or surrogate pair to utf-32 } -function utf16toutf32(const S: WideString; const index: SizeInt; out len: longint): UCS4Char; [public, alias: 'FPC_UTF16TOUTF32']; -var - w: widechar; -begin - { UTF-16 points in the range #$0-#$D7FF and #$E000-#$FFFF } - { are the same in UTF-32 } - w:=s[index]; - if (w<=#$d7ff) or - (w>=#$e000) then - begin - result:=UCS4Char(w); - len:=1; - end - { valid surrogate pair? } - else if (w<=#$dbff) and - { w>=#$d7ff check not needed, checked above } - (index<length(s)) and - (s[index+1]>=#$dc00) and - (s[index+1]<=#$dfff) then - { convert the surrogate pair to UTF-32 } - begin - result:=(UCS4Char(w)-$d800) shl 10 + (UCS4Char(s[index+1])-$dc00) + $10000; - len:=2; - end - else - { invalid surrogate -> do nothing } - begin - result:=UCS4Char(w); - len:=1; - end; -end; - - -function WideStringToUCS4String(const s : WideString) : UCS4String; - var - i, slen, - destindex : SizeInt; - len : longint; - begin - slen:=length(s); - setlength(result,slen+1); - i:=1; - destindex:=0; - while (i<=slen) do - begin - result[destindex]:=utf16toutf32(s,i,len); - inc(destindex); - inc(i,len); - end; - { destindex <= slen (surrogate pairs may have been merged) } - { destindex+1 for terminating #0 (dynamic arrays are } - { implicitely filled with zero) } - setlength(result,destindex+1); - end; - - -{ concatenates an utf-32 char to a widestring. S *must* be unique when entering. } -procedure ConcatUTF32ToWideStr(const nc: UCS4Char; var S: WideString; var index: SizeInt); -var - p : PWideChar; -begin - { if nc > $ffff, we need two places } - if (index+ord(nc > $ffff)>length(s)) then - if (length(s) < 10*256) then - setlength(s,length(s)+10) - else - setlength(s,length(s)+length(s) shr 8); - { we know that s is unique -> avoid uniquestring calls} - p:=@s[index]; - if (nc<$ffff) then - begin - p^:=widechar(nc); - inc(index); - end - else if (dword(nc)<=$10ffff) then - begin - p^:=widechar((nc - $10000) shr 10 + $d800); - (p+1)^:=widechar((nc - $10000) and $3ff + $dc00); - inc(index,2); - end - else - { invalid code point } - begin - p^:='?'; - inc(index); - end; -end; - - -function UCS4StringToWideString(const s : UCS4String) : WideString; - var - i : SizeInt; - resindex : SizeInt; - begin - { skip terminating #0 } - SetLength(result,length(s)-1); - resindex:=1; - for i:=0 to high(s)-1 do - ConcatUTF32ToWideStr(s[i],result,resindex); - { adjust result length (may be too big due to growing } - { for surrogate pairs) } - setlength(result,resindex-1); - end; - -const - SNoWidestrings = 'This binary has no widestrings support compiled in.'; - SRecompileWithWidestrings = 'Recompile the application with a widestrings-manager in the program uses clause.'; - -procedure unimplementedwidestring; - begin -{$ifdef FPC_HAS_FEATURE_CONSOLEIO} - If IsConsole then - begin - Writeln(StdErr,SNoWidestrings); - Writeln(StdErr,SRecompileWithWidestrings); - end; -{$endif FPC_HAS_FEATURE_CONSOLEIO} - HandleErrorFrame(233,get_frame); - end; - -{$warnings off} -function GenericWideCase(const s : WideString) : WideString; - begin - unimplementedwidestring; - end; - - -function CompareWideString(const s1, s2 : WideString) : PtrInt; - begin - unimplementedwidestring; - end; - - -function CompareTextWideString(const s1, s2 : WideString): PtrInt; - begin - unimplementedwidestring; - end; - - -function CharLengthPChar(const Str: PChar): PtrInt; - begin - unimplementedwidestring; - end; -{$warnings on} - -procedure initwidestringmanager; - begin - fillchar(widestringmanager,sizeof(widestringmanager),0); -{$ifndef HAS_WIDESTRINGMANAGER} - widestringmanager.Wide2AnsiMoveProc:=@defaultWide2AnsiMove; - widestringmanager.Ansi2WideMoveProc:=@defaultAnsi2WideMove; - widestringmanager.UpperWideStringProc:=@GenericWideCase; - widestringmanager.LowerWideStringProc:=@GenericWideCase; -{$endif HAS_WIDESTRINGMANAGER} - widestringmanager.CompareWideStringProc:=@CompareWideString; - widestringmanager.CompareTextWideStringProc:=@CompareTextWideString; - widestringmanager.CharLengthPCharProc:=@CharLengthPChar; - end; diff --git a/rtl/linux/buildrtl.lpi b/rtl/linux/buildrtl.lpi new file mode 100644 index 0000000000..b8bf886f03 --- /dev/null +++ b/rtl/linux/buildrtl.lpi @@ -0,0 +1,64 @@ +<?xml version="1.0"?> +<CONFIG> + <ProjectOptions> + <PathDelim Value="/"/> + <Version Value="6"/> + <General> + <Flags> + <MainUnitHasUsesSectionForAllUnits Value="False"/> + <MainUnitHasCreateFormStatements Value="False"/> + <MainUnitHasTitleStatement Value="False"/> + <Runnable Value="False"/> + </Flags> + <SessionStorage Value="InProjectDir"/> + <MainUnit Value="0"/> + <IconPath Value="./"/> + <TargetFileExt Value=".exe"/> + <Title Value="buildrtl"/> + </General> + <VersionInfo> + <ProjectVersion Value=""/> + </VersionInfo> + <PublishOptions> + <Version Value="2"/> + <IgnoreBinaries Value="False"/> + <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/> + <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/> + </PublishOptions> + <RunParams> + <local> + <FormatVersion Value="1"/> + <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/> + </local> + </RunParams> + <Units Count="1"> + <Unit0> + <Filename Value="buildrtl.pp"/> + <IsPartOfProject Value="True"/> + <UnitName Value="buildrtl"/> + </Unit0> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="8"/> + <SearchPaths> + <IncludeFiles Value="../inc/;../$(TargetCPU)/;../unix/;../objpas/classes/;../objpas/sysutils/;../objpas/"/> + <OtherUnitFiles Value="../objpas/;../objpas/classes/;../objpas/sysutils/;../inc/;../unix/;../$(TargetCPU)/"/> + <UnitOutputDirectory Value="../units/$(TargetCPU)-linux"/> + </SearchPaths> + <Parsing> + <Style Value="2"/> + </Parsing> + <Other> + <Verbosity> + <ShowNotes Value="False"/> + <ShowHints Value="False"/> + </Verbosity> + <CompilerPath Value="$(CompPath)"/> + <ExecuteBefore> + <Command Value="cmd.exe /c "if not exist ../units/$(TargetCPU)-linux mkdir ../units/$(TargetCPU)-linux""/> + <ShowAllMessages Value="True"/> + </ExecuteBefore> + </Other> + </CompilerOptions> +</CONFIG> diff --git a/rtl/linux/buildrtl.pp b/rtl/linux/buildrtl.pp new file mode 100644 index 0000000000..80cae4c112 --- /dev/null +++ b/rtl/linux/buildrtl.pp @@ -0,0 +1,20 @@ +{ This unit is only used to edit the rtl with lazarus } +unit buildrtl; + + interface + + uses + system, unixtype, ctypes, baseunix, strings, objpas,b macpas, syscall, unixutil, + fpintres, heaptrc, lineinfo, lnfodwrf, + termio, unix, linux, initc, cmem, mmx, + crt, printer, linuxvcs, + sysutils, typinfo, math, matrix, varutils, + charset, ucomplex, getopts, + errors, sockets, gpm, ipc, serial, terminfo, dl, dynlibs, + video, mouse, keyboard, variants, types, dateutils, sysconst, fmtbcd, + cthreads, classes, fgl, convutils, stdconvs, strutils, rtlconsts, dos, objects, cwstring, fpcylix, clocale, + exeinfo; + + implementation + +end. diff --git a/rtl/linux/system.pp b/rtl/linux/system.pp index f472c44b2b..1532b8cb28 100644 --- a/rtl/linux/system.pp +++ b/rtl/linux/system.pp @@ -329,5 +329,9 @@ begin { threading } InitSystemThreads; initvariantmanager; +{$ifdef VER2_2} initwidestringmanager; +{$else VER2_2} + initunicodestringmanager; +{$endif VER2_2} end. diff --git a/rtl/objpas/classes/classes.inc b/rtl/objpas/classes/classes.inc index 1a77ef75ff..7629204210 100644 --- a/rtl/objpas/classes/classes.inc +++ b/rtl/objpas/classes/classes.inc @@ -897,13 +897,16 @@ procedure ObjectBinaryToText(Input, Output: TStream); end; procedure OutString(s: String); - begin OutChars(Pointer(S),PChar(S)+Length(S),@CharToOrd); end; procedure OutWString(W: WideString); + begin + OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd); + end; + procedure OutUString(W: UnicodeString); begin OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd); end; @@ -1047,6 +1050,25 @@ procedure ObjectBinaryToText(Input, Output: TStream); end; end; + function ReadUStr: UnicodeString; + var + len: DWord; + {$IFDEF ENDIAN_BIG} + i : integer; + {$ENDIF} + begin + len := ReadDWord; + SetLength(Result, len); + if (len > 0) then + begin + Input.ReadBuffer(Pointer(@Result[1])^, len*2); + {$IFDEF ENDIAN_BIG} + for i:=1 to len do + Result[i]:=widechar(SwapEndian(word(Result[i]))); + {$ENDIF} + end; + end; + procedure ReadPropList(indent: String); procedure ProcessValue(ValueType: TValueType; Indent: String); @@ -1138,6 +1160,11 @@ procedure ObjectBinaryToText(Input, Output: TStream); OutWString(ReadWStr); OutLn(''); end; + vaUString: + begin + OutWString(ReadWStr); + OutLn(''); + end; vaNil: OutLn('nil'); vaCollection: begin diff --git a/rtl/objpas/classes/classesh.inc b/rtl/objpas/classes/classesh.inc index 999d4065fd..2e2aa84d6f 100644 --- a/rtl/objpas/classes/classesh.inc +++ b/rtl/objpas/classes/classesh.inc @@ -901,7 +901,8 @@ type TValueType = (vaNull, vaList, vaInt8, vaInt16, vaInt32, vaExtended, vaString, vaIdent, vaFalse, vaTrue, vaBinary, vaSet, vaLString, - vaNil, vaCollection, vaSingle, vaCurrency, vaDate, vaWString, vaInt64, vaUTF8String); + vaNil, vaCollection, vaSingle, vaCurrency, vaDate, vaWString, vaInt64, + vaUTF8String, vaUString); TFilerFlag = (ffInherited, ffChildPos, ffInline); TFilerFlags = set of TFilerFlag; @@ -967,6 +968,7 @@ type function ReadStr: String; virtual; abstract; function ReadString(StringType: TValueType): String; virtual; abstract; function ReadWideString: WideString;virtual;abstract; + function ReadUnicodeString: UnicodeString;virtual;abstract; procedure SkipComponent(SkipComponentInfos: Boolean); virtual; abstract; procedure SkipValue; virtual; abstract; end; @@ -1018,6 +1020,7 @@ type function ReadStr: String; override; function ReadString(StringType: TValueType): String; override; function ReadWideString: WideString;override; + function ReadUnicodeString: UnicodeString;override; procedure SkipComponent(SkipComponentInfos: Boolean); override; procedure SkipValue; override; end; @@ -1103,6 +1106,7 @@ type function ReadBoolean: Boolean; function ReadChar: Char; function ReadWideChar: WideChar; + function ReadUnicodeChar: UnicodeChar; procedure ReadCollection(Collection: TCollection); function ReadComponent(Component: TComponent): TComponent; procedure ReadComponents(AOwner, AParent: TComponent; @@ -1121,6 +1125,7 @@ type function ReadRootComponent(ARoot: TComponent): TComponent; function ReadString: string; function ReadWideString: WideString; + function ReadUnicodeString: UnicodeString; function ReadValue: TValueType; procedure CopyValue(Writer: TWriter); property Driver: TAbstractObjectReader read FDriver; @@ -1172,6 +1177,7 @@ type procedure WriteSet(Value: LongInt; SetType: Pointer); virtual; abstract; procedure WriteString(const Value: String); virtual; abstract; procedure WriteWideString(const Value: WideString);virtual;abstract; + procedure WriteUnicodeString(const Value: UnicodeString);virtual;abstract; end; { TBinaryObjectWriter } @@ -1222,6 +1228,7 @@ type procedure WriteSet(Value: LongInt; SetType: Pointer); override; procedure WriteString(const Value: String); override; procedure WriteWideString(const Value: WideString); override; + procedure WriteUnicodeString(const Value: UnicodeString); override; end; TTextObjectWriter = class(TAbstractObjectWriter) @@ -1291,6 +1298,7 @@ type procedure WriteRootComponent(ARoot: TComponent); procedure WriteString(const Value: string); procedure WriteWideString(const Value: WideString); + procedure WriteUnicodeString(const Value: UnicodeString); property RootAncestor: TComponent read FRootAncestor write FRootAncestor; property OnFindAncestor: TFindAncestorEvent read FOnFindAncestor write FOnFindAncestor; property OnWriteMethodProperty: TWriteMethodPropertyEvent read FOnWriteMethodProperty write FOnWriteMethodProperty; diff --git a/rtl/objpas/classes/reader.inc b/rtl/objpas/classes/reader.inc index e33c2f7154..57f54cedda 100644 --- a/rtl/objpas/classes/reader.inc +++ b/rtl/objpas/classes/reader.inc @@ -339,6 +339,25 @@ begin end; end; +function TBinaryObjectReader.ReadUnicodeString: UnicodeString; +var + len: DWord; +{$IFDEF ENDIAN_BIG} + i : integer; +{$ENDIF} +begin + len := ReadDWord; + SetLength(Result, len); + if (len > 0) then + begin + Read(Pointer(@Result[1])^, len*2); + {$IFDEF ENDIAN_BIG} + for i:=1 to len do + Result[i]:=UnicodeChar(SwapEndian(word(Result[i]))); + {$ENDIF} + end; +end; + procedure TBinaryObjectReader.SkipComponent(SkipComponentInfos: Boolean); var Flags: TFilerFlags; @@ -409,6 +428,11 @@ begin Count:=LongInt(ReadDWord); SkipBytes(Count*sizeof(widechar)); end; + vaUString: + begin + Count:=LongInt(ReadDWord); + SkipBytes(Count*sizeof(widechar)); + end; vaSet: SkipSetBody; vaCollection: @@ -749,6 +773,19 @@ begin raise EReadError.Create(SInvalidPropertyValue); end; +function TReader.ReadUnicodeChar: UnicodeChar; + +var + U: UnicodeString; + +begin + U := ReadUnicodeString; + if Length(U) = 1 then + Result := U[1] + else + raise EReadError.Create(SInvalidPropertyValue); +end; + procedure TReader.ReadCollection(Collection: TCollection); var Item: TCollectionItem; @@ -1172,7 +1209,7 @@ begin SetOrdProp(Instance, PropInfo, Ord(ReadBoolean)); tkChar: SetOrdProp(Instance, PropInfo, Ord(ReadChar)); - tkWChar: + tkWChar,tkUChar: SetOrdProp(Instance, PropInfo, Ord(ReadWideChar)); tkEnumeration: begin @@ -1211,13 +1248,15 @@ begin end; end; tkSString, tkLString, tkAString: - begin - TmpStr:=ReadString; - if Assigned(FOnReadStringProperty) then - FOnReadStringProperty(Self,Instance,PropInfo,TmpStr); - SetStrProp(Instance, PropInfo, TmpStr); - end; - tkWstring: + begin + TmpStr:=ReadString; + if Assigned(FOnReadStringProperty) then + FOnReadStringProperty(Self,Instance,PropInfo,TmpStr); + SetStrProp(Instance, PropInfo, TmpStr); + end; + tkUstring: + SetUnicodeStrProp(Instance,PropInfo,ReadUnicodeString); + tkWString: SetWideStrProp(Instance,PropInfo,ReadWideString); {!!!: tkVariant} tkClass: @@ -1365,6 +1404,8 @@ begin end else if StringType in [vaWString] then Result:= FDriver.ReadWidestring + else if StringType in [vaUString] then + Result:= FDriver.ReadUnicodeString else raise EReadError.Create(SInvalidPropertyValue); end; @@ -1375,21 +1416,47 @@ var s: String; i: Integer; begin - if NextValue in [vaWString,vaUTF8String] then - begin - ReadValue; - Result := FDriver.ReadWideString - end - else begin - //data probable from ObjectTextToBinary - s := ReadString; - setlength(result,length(s)); - for i:= 1 to length(s) do begin - result[i]:= widechar(ord(s[i])); //no code conversion + if NextValue in [vaWString,vaUString,vaUTF8String] then + //vaUTF8String needs conversion? 2008-09-06 mse + begin + ReadValue; + Result := FDriver.ReadWideString + end + else + begin + //data probable from ObjectTextToBinary + s := ReadString; + setlength(result,length(s)); + for i:= 1 to length(s) do begin + result[i]:= widechar(ord(s[i])); //no code conversion end; end; end; + +function TReader.ReadUnicodeString: UnicodeString; +var + s: String; + i: Integer; +begin + if NextValue in [vaWString,vaUString,vaUTF8String] then + //vaUTF8String needs conversion? 2008-09-06 mse + begin + ReadValue; + Result := FDriver.ReadUnicodeString + end + else + begin + //data probable from ObjectTextToBinary + s := ReadString; + setlength(result,length(s)); + for i:= 1 to length(s) do begin + result[i]:= UnicodeChar(ord(s[i])); //no code conversion + end; + end; +end; + + function TReader.ReadValue: TValueType; begin Result := FDriver.ReadValue; diff --git a/rtl/objpas/classes/writer.inc b/rtl/objpas/classes/writer.inc index a55648cea1..5d09756cf9 100644 --- a/rtl/objpas/classes/writer.inc +++ b/rtl/objpas/classes/writer.inc @@ -319,6 +319,29 @@ begin {$ENDIF} end; end; + +procedure TBinaryObjectWriter.WriteUnicodeString(const Value: UnicodeString); +var len : longword; +{$IFDEF ENDIAN_BIG} + i : integer; + us : UnicodeString; +{$ENDIF} +begin + WriteValue(vaUString); + len:=Length(Value); + WriteDWord(len); + if len > 0 then + begin + {$IFDEF ENDIAN_BIG} + setlength(us,len); + for i:=1 to len do + us[i]:=widechar(SwapEndian(word(Value[i]))); + Write(us[1], len*sizeof(UnicodeChar)); + {$ELSE} + Write(Value[1], len*sizeof(UnicodeChar)); + {$ENDIF} + end; +end; procedure TBinaryObjectWriter.FlushBuffer; begin @@ -737,6 +760,7 @@ var DefMethodValue: TMethod; WStrValue, WDefStrValue: WideString; StrValue, DefStrValue: String; + UStrValue, UDefStrValue: UnicodeString; AncestorObj: TObject; Component: TComponent; ObjValue: TObject; @@ -876,6 +900,21 @@ begin Driver.EndProperty; end; end; + tkUString: + begin + UStrValue := GetUnicodeStrProp(Instance, PropInfo); + if HasAncestor then + UDefStrValue := GetUnicodeStrProp(Ancestor, PropInfo) + else + SetLength(UDefStrValue, 0); + + if UStrValue <> UDefStrValue then + begin + Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name); + WriteUnicodeString(UStrValue); + Driver.EndProperty; + end; + end; {!!!: tkVariant:} tkClass: begin @@ -1013,3 +1052,8 @@ begin Driver.WriteWideString(Value); end; +procedure TWriter.WriteUnicodeString(const Value: UnicodeString); +begin + Driver.WriteUnicodeString(Value); +end; + diff --git a/rtl/objpas/sysutils/sysformt.inc b/rtl/objpas/sysutils/sysformt.inc index fd75384312..e45f4f4779 100644 --- a/rtl/objpas/sysutils/sysformt.inc +++ b/rtl/objpas/sysutils/sysformt.inc @@ -143,7 +143,11 @@ Var ChPos,OldPos,ArgPos,DoArg,Len : SizeInt; ReadWidth; ReadPrec; {$ifdef INWIDEFORMAT} +{$ifdef VER2_2} FormatChar:=UpCase(Fmt[ChPos])[1]; +{$else VER2_2} + FormatChar:=UpCase(UnicodeChar(Fmt[ChPos])); +{$endif VER2_2} if word(FormatChar)>255 then ReadFormat:=#255 else diff --git a/rtl/objpas/typinfo.pp b/rtl/objpas/typinfo.pp index 30688766df..85d823b7ce 100644 --- a/rtl/objpas/typinfo.pp +++ b/rtl/objpas/typinfo.pp @@ -38,7 +38,7 @@ unit typinfo; tkSet,tkMethod,tkSString,tkLString,tkAString, tkWString,tkVariant,tkArray,tkRecord,tkInterface, tkClass,tkObject,tkWChar,tkBool,tkInt64,tkQWord, - tkDynArray,tkInterfaceRaw); + tkDynArray,tkInterfaceRaw,tkProcVar,tkUString,tkUChar); TOrdType = (otSByte,otUByte,otSWord,otUWord,otSLong,otULong); @@ -85,7 +85,7 @@ unit typinfo; {$endif FPC_REQUIRES_PROPER_ALIGNMENT} record case TTypeKind of - tkUnKnown,tkLString,tkWString,tkAString,tkVariant: + tkUnKnown,tkLString,tkWString,tkAString,tkVariant,tkUString: (); tkInteger,tkChar,tkEnumeration,tkWChar,tkSet: (OrdType : TOrdType; @@ -252,6 +252,11 @@ Function GetWideStrProp(Instance: TObject; const PropName: string): WideString; Procedure SetWideStrProp(Instance: TObject; const PropName: string; const Value: WideString); Procedure SetWideStrProp(Instance: TObject; PropInfo: PPropInfo; const Value: WideString); +Function GetUnicodeStrProp(Instance: TObject; PropInfo: PPropInfo): UnicodeString; +Function GetUnicodeStrProp(Instance: TObject; const PropName: string): UnicodeString; +Procedure SetUnicodeStrProp(Instance: TObject; const PropName: string; const Value: UnicodeString); +Procedure SetUnicodeStrProp(Instance: TObject; PropInfo: PPropInfo; const Value: UnicodeString); + {$ifndef FPUNONE} Function GetFloatProp(Instance: TObject; PropInfo : PPropInfo) : Extended; Function GetFloatProp(Instance: TObject; const PropName: string): Extended; @@ -1397,6 +1402,91 @@ begin end; end; +Function GetUnicodeStrProp(Instance: TObject; const PropName: string): UnicodeString; +begin + Result:=GetUnicodeStrProp(Instance, FindPropInfo(Instance, PropName)); +end; + + +procedure SetUnicodeStrProp(Instance: TObject; const PropName: string; const Value: UnicodeString); +begin + SetUnicodeStrProp(Instance,FindPropInfo(Instance,PropName),Value); +end; + + +Function GetUnicodeStrProp(Instance: TObject; PropInfo: PPropInfo): UnicodeString; +type + TGetUnicodeStrProcIndex=function(index:longint):UnicodeString of object; + TGetUnicodeStrProc=function():UnicodeString of object; +var + AMethod : TMethod; +begin + Result:=''; + case Propinfo^.PropType^.Kind of + tkSString,tkAString: + Result:=GetStrProp(Instance,PropInfo); + tkWString: + Result:=GetWideStrProp(Instance,PropInfo); + tkUString: + begin + case (PropInfo^.PropProcs) and 3 of + ptField: + Result := PUnicodeString(Pointer(Instance)+PtrUInt(PropInfo^.GetProc))^; + ptstatic, + ptvirtual : + begin + if (PropInfo^.PropProcs and 3)=ptStatic then + AMethod.Code:=PropInfo^.GetProc + else + AMethod.Code:=PPointer(Pointer(Instance.ClassType)+PtrUInt(PropInfo^.GetProc))^; + AMethod.Data:=Instance; + if ((PropInfo^.PropProcs shr 6) and 1)<>0 then + Result:=TGetUnicodeStrProcIndex(AMethod)(PropInfo^.Index) + else + Result:=TGetUnicodeStrProc(AMethod)(); + end; + end; + end; + end; +end; + + +Procedure SetUnicodeStrProp(Instance: TObject; PropInfo: PPropInfo; const Value: UnicodeString); +type + TSetUnicodeStrProcIndex=procedure(index:longint;s:UnicodeString) of object; + TSetUnicodeStrProc=procedure(s:UnicodeString) of object; +var + AMethod : TMethod; +begin + case Propinfo^.PropType^.Kind of + tkSString,tkAString: + SetStrProp(Instance,PropInfo,Value); + tkWString: + SetWideStrProp(Instance,PropInfo,Value); + tkUString: + begin + case (PropInfo^.PropProcs shr 2) and 3 of + ptField: + PUnicodeString(Pointer(Instance)+PtrUInt(PropInfo^.SetProc))^:=Value; + ptstatic, + ptvirtual : + begin + if ((PropInfo^.PropProcs shr 2) and 3)=ptStatic then + AMethod.Code:=PropInfo^.SetProc + else + AMethod.Code:=PPointer(Pointer(Instance.ClassType)+PtrUInt(PropInfo^.SetProc))^; + AMethod.Data:=Instance; + if ((PropInfo^.PropProcs shr 6) and 1)<>0 then + TSetUnicodeStrProcIndex(AMethod)(PropInfo^.Index,Value) + else + TSetUnicodeStrProc(AMethod)(Value); + end; + end; + end; + end; +end; + + {$ifndef FPUNONE} diff --git a/rtl/unix/cwstring.pp b/rtl/unix/cwstring.pp index e4108af2d1..860613b9f8 100644 --- a/rtl/unix/cwstring.pp +++ b/rtl/unix/cwstring.pp @@ -705,7 +705,7 @@ end; Procedure SetCWideStringManager; Var - CWideStringManager : TWideStringManager; + CWideStringManager : TUnicodeStringManager; begin CWideStringManager:=widestringmanager; With CWideStringManager do @@ -733,8 +733,15 @@ begin StrUpperAnsiStringProc:=@AnsiStrUpper; ThreadInitProc:=@InitThread; ThreadFiniProc:=@FiniThread; +{$ifndef VER2_2} + { Unicode } + Unicode2AnsiMoveProc:=@Wide2AnsiMove; + Ansi2UnicodeMoveProc:=@Ansi2WideMove; + UpperUnicodeStringProc:=@UpperWideString; + LowerUnicodeStringProc:=@LowerWideString; +{$endif VER2_2} end; - SetWideStringManager(CWideStringManager); + SetUnicodeStringManager(CWideStringManager); end; @@ -752,3 +759,4 @@ finalization { fini conversion tables for main program } FiniThread; end. + diff --git a/rtl/win32/buildrtl.lpi b/rtl/win32/buildrtl.lpi index 8c72981d5a..55c3f36caa 100644 --- a/rtl/win32/buildrtl.lpi +++ b/rtl/win32/buildrtl.lpi @@ -12,6 +12,7 @@ </Flags> <SessionStorage Value="InProjectDir"/> <MainUnit Value="0"/> + <IconPath Value="./"/> <TargetFileExt Value=".exe"/> <Title Value="buildrtl"/> </General> diff --git a/rtl/win32/system.pp b/rtl/win32/system.pp index 9d0a1197ec..e1fad07a70 100644 --- a/rtl/win32/system.pp +++ b/rtl/win32/system.pp @@ -899,10 +899,6 @@ end; {$endif Set_i386_Exception_handler} -{**************************************************************************** - OS dependend widestrings -****************************************************************************} - const { MultiByteToWideChar } MB_PRECOMPOSED = 1; @@ -918,6 +914,9 @@ function CharUpperBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD; function CharLowerBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD; stdcall; external 'user32' name 'CharLowerBuffW'; +{****************************************************************************** + Widestring + ******************************************************************************} procedure Win32Wide2AnsiMove(source:pwidechar;var dest:ansistring;len:SizeInt); var @@ -947,13 +946,57 @@ procedure Win32Ansi2WideMove(source:pchar;var dest:widestring;len:SizeInt); function Win32WideUpper(const s : WideString) : WideString; begin result:=s; - UniqueString(result); if length(result)>0 then CharUpperBuff(LPWSTR(result),length(result)); end; function Win32WideLower(const s : WideString) : WideString; + begin + result:=s; + if length(result)>0 then + CharLowerBuff(LPWSTR(result),length(result)); + end; + +{****************************************************************************** + Unicode + ******************************************************************************} + +procedure Win32Unicode2AnsiMove(source:punicodechar;var dest:ansistring;len:SizeInt); + var + destlen: SizeInt; + begin + // retrieve length including trailing #0 + // not anymore, because this must also be usable for single characters + destlen:=WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, source, len, nil, 0, nil, nil); + // this will null-terminate + setlength(dest, destlen); + WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, source, len, @dest[1], destlen, nil, nil); + end; + +procedure Win32Ansi2UnicodeMove(source:pchar;var dest:UnicodeString;len:SizeInt); + var + destlen: SizeInt; + begin + // retrieve length including trailing #0 + // not anymore, because this must also be usable for single characters + destlen:=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len, nil, 0); + // this will null-terminate + setlength(dest, destlen); + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len, @dest[1], destlen); + end; + + +function Win32UnicodeUpper(const s : UnicodeString) : UnicodeString; + begin + result:=s; + UniqueString(result); + if length(result)>0 then + CharUpperBuff(LPWSTR(result),length(result)); + end; + + +function Win32UnicodeLower(const s : UnicodeString) : UnicodeString; begin result:=s; UniqueString(result); @@ -966,10 +1009,18 @@ function Win32WideLower(const s : WideString) : WideString; are only relevant for the sysutils units } procedure InitWin32Widestrings; begin + { Widestring } widestringmanager.Wide2AnsiMoveProc:=@Win32Wide2AnsiMove; widestringmanager.Ansi2WideMoveProc:=@Win32Ansi2WideMove; widestringmanager.UpperWideStringProc:=@Win32WideUpper; widestringmanager.LowerWideStringProc:=@Win32WideLower; +{$ifndef VER2_2} + { Unicode } + widestringmanager.Unicode2AnsiMoveProc:=@Win32Unicode2AnsiMove; + widestringmanager.Ansi2UnicodeMoveProc:=@Win32Ansi2UnicodeMove; + widestringmanager.UpperUnicodeStringProc:=@Win32UnicodeUpper; + widestringmanager.LowerUnicodeStringProc:=@Win32UnicodeLower; +{$endif VER2_2} end; @@ -1192,6 +1243,10 @@ begin errno:=0; initvariantmanager; initwidestringmanager; +{$ifndef VER2_2} + initunicodestringmanager; +{$endif VER2_2} InitWin32Widestrings; DispCallByIDProc:=@DoDispCallByIDError; end. + diff --git a/tests/test/trtti1.pp b/tests/test/trtti1.pp index d484bcaf32..ce454e6e6e 100644 --- a/tests/test/trtti1.pp +++ b/tests/test/trtti1.pp @@ -11,7 +11,7 @@ Const TypeNames : Array [TTYpeKind] of string[15] = 'Float','Set','Method','ShortString','LongString', 'AnsiString','WideString','Variant','Array','Record', 'Interface','Class','Object','WideChar','Bool','Int64','QWord', - 'DynamicArray','RawInterface'); + 'DynamicArray','RawInterface','ProcVar','UnicodeString','UnicodeChar'); Const OrdinalTypes = [tkInteger,tkChar,tkENumeration,tkbool]; diff --git a/tests/test/tstring10.pp b/tests/test/tstring10.pp new file mode 100644 index 0000000000..905a7dda53 --- /dev/null +++ b/tests/test/tstring10.pp @@ -0,0 +1,27 @@ +program punicodechartest; +{$ifdef FPC}{$mode objfpc}{$h+}{$endif} +{$ifdef mswindows}{$apptype console}{$endif} +uses + {$ifdef FPC}{$ifdef linux}cthreads,{$endif}{$endif} + sysutils; +var + astr: ansistring; + wstr: widestring; + ustr: unicodestring; +begin + astr:= ''; + wstr:= ''; + ustr:= ''; + writeln(ptrint(pansichar(astr))); + flush(output); + writeln(ptrint(pwidechar(wstr))); + flush(output); + writeln(ptrint(punicodechar(ustr))); + flush(output); + writeln(ord(pansichar(astr)^)); + flush(output); + writeln(ord(pwidechar(wstr)^)); + flush(output); + writeln(ord(punicodechar(ustr)^)); + flush(output); +end. diff --git a/tests/test/tunistr1.pp b/tests/test/tunistr1.pp new file mode 100644 index 0000000000..c4cb0d7da1 --- /dev/null +++ b/tests/test/tunistr1.pp @@ -0,0 +1,19 @@ +{$ifdef unix} +uses + cwstring; +{$endif unix} + +var + w : unicodestring; + a : ansistring; + +begin + a:='A'; + w:=a; + if w[1]<>#65 then + halt(1); + a:=w; + if a[1]<>'A' then + halt(1); + writeln('ok'); +end. diff --git a/tests/test/tunistr2.pp b/tests/test/tunistr2.pp new file mode 100644 index 0000000000..8e9c1824c3 --- /dev/null +++ b/tests/test/tunistr2.pp @@ -0,0 +1,21 @@ +{$ifdef UNIX} +uses + cwstring; +{$endif UNIX} + +var + i : longint; + w,w2 : unicodestring; + a : ansistring; + +begin + setlength(w,1000); + for i:=1 to 1000 do + w[i]:=widechar(i); + for i:=1 to 10 do + begin + a:=w; + w2:=a; + end; + writeln('ok'); +end. diff --git a/tests/test/tunistr4.pp b/tests/test/tunistr4.pp new file mode 100644 index 0000000000..0ca80e047f --- /dev/null +++ b/tests/test/tunistr4.pp @@ -0,0 +1,92 @@ + +{$ifdef fpc} +{$mode objfpc} +{$endif fpc} + +uses +{$ifdef unix} + cthreads, cwstring, +{$endif} + Classes, SysUtils; + +type + tc = class(tthread) + orgstr: ansistring; + cnvstr: unicodestring; + constructor create(const s: ansistring; const w: unicodestring); + procedure execute; override; + end; + +const + // string with an invalid utf-8 code sequence + str1 = #$c1#$34'Życie'#$c1#$34' jest jak papier '#$c1#$34'toaletowy'#$c1#$34' : długie, szare i '#$c1#$34'do'#$c1#$34' dupy'; + str2 = 'Życie '#$c1#$34'jest'#$c1#$34' jak papier toaletowy : '#$c1#$34'długie'#$c1#$34', szare i do '#$c1#$34'dupy'#$c1#$34'222222222222222222222222222222222222222222222222'; + str3 = 'Życie jest '#$c1#$34'jak'#$c1#$34' papier 333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333 toaletowy : długie, '#$c1#$34'szare'#$c1#$34' i do dupy'; + str4 = 'Życie jest 4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444 jak '#$c1#$34'papier'#$c1#$34' toaletowy : długie, szare '#$c1#$34'i'#$c1#$34' do dupy'; + count = 20000; + +var + wstr: unicodestring; +// cnvstr: ansistring; + error: boolean; + + +constructor tc.create(const s: ansistring; const w: unicodestring); +begin + orgstr:=s; + cnvstr:=w; + inherited create(true); +end; + + +procedure tc.execute; +var + i: longint; + w: unicodestring; +begin + for i := 1 to count do + begin + w:=orgstr; + if (w<>cnvstr) then + error:=true; + end; +end; + +var + a: array[1..4] of tc; + w1,w2,w3,w4: unicodestring; + cnvstr: ansistring; +begin + error:=false; + cnvstr:=str1; + w1:=cnvstr; + cnvstr:=str2; + w2:=cnvstr; + cnvstr:=str3; + w3:=cnvstr; + cnvstr:=str4; + w4:=cnvstr; + writeln(w1); + writeln(w2); + writeln(w3); + writeln(w4); + a[1]:=tc.create(str1,w1); + a[2]:=tc.create(str2,w2); + a[3]:=tc.create(str3,w3); + a[4]:=tc.create(str4,w4); + a[1].resume; + a[2].resume; + a[3].resume; + a[4].resume; + a[1].waitfor; + a[2].waitfor; + a[3].waitfor; + a[4].waitfor; + a[1].free; + a[2].free; + a[3].free; + a[4].free; + + if error then + halt(1); +end. diff --git a/tests/test/tunistr5.pp b/tests/test/tunistr5.pp new file mode 100644 index 0000000000..b09a333a54 --- /dev/null +++ b/tests/test/tunistr5.pp @@ -0,0 +1,45 @@ +{$codepage utf-8} + +var + ws: unicodestring; + us: UCS4String; +begin +// the compiler does not yet support characters which require +// a surrogate pair in utf-16 +// ws:='鳣ćçŹ你'; +// so write the last character directly using a utf-16 surrogate pair + ws:='鳣ćçŹ'#$d87e#$dc04; + + if (length(ws)<>8) or + (ws[1]<>'é') or + (ws[2]<>'ł') or + (ws[3]<>'Ł') or + (ws[4]<>'ć') or + (ws[5]<>'ç') or + (ws[6]<>'Ź') or + (ws[7]<>#$d87e) or + (ws[8]<>#$dc04) then + halt(1); + us:=UnicodeStringToUCS4String(ws); + if (length(us)<>8) or + (us[0]<>UCS4Char(unicodechar('é'))) or + (us[1]<>UCS4Char(unicodechar('ł'))) or + (us[2]<>UCS4Char(unicodechar('Ł'))) or + (us[3]<>UCS4Char(unicodechar('ć'))) or + (us[4]<>UCS4Char(unicodechar('ç'))) or + (us[5]<>UCS4Char(unicodechar('Ź'))) or + (us[6]<>UCS4Char($2F804)) or + (us[7]<>UCS4Char(0)) then + halt(2); + ws:=UCS4StringToUnicodeString(us); + if (length(ws)<>8) or + (ws[1]<>'é') or + (ws[2]<>'ł') or + (ws[3]<>'Ł') or + (ws[4]<>'ć') or + (ws[5]<>'ç') or + (ws[6]<>'Ź') or + (ws[7]<>#$d87e) or + (ws[8]<>#$dc04) then + halt(3); +end. diff --git a/tests/test/tunistr6.pp b/tests/test/tunistr6.pp new file mode 100644 index 0000000000..033892d172 --- /dev/null +++ b/tests/test/tunistr6.pp @@ -0,0 +1,397 @@ +{%skiptarget=wince} +{$codepage utf-8} +uses + {$ifdef unix} + cwstring, + {$endif} + sysutils; + +procedure doerror(i : integer); + begin + writeln('Error: ',i); + halt(i); + end; + + +{ normal upper case testing } +procedure testupper; +var + s: ansistring; + w1,w2,w3,w4: unicodestring; + i: longint; +begin + w1:='aé'#0'èàł'#$d87e#$dc04; + w2:='AÉ'#0'ÈÀŁ'#$d87e#$dc04; +{$ifdef print} +// the utf-8 output can confuse the testsuite parser + writeln('original: ',w1); + writeln('original upper: ',w2); +{$endif print} + s:=w1; +{$ifdef print} + writeln('ansi: ',s); +{$endif print} + w3:=s; + w4:=AnsiUpperCase(s); + { filter out unsupported characters } + for i:=1 to length(w3) do + if w3[i]='?' then + begin + w2[i]:='?'; + w1[i]:='?'; + end; + w1:=UnicodeUpperCase(w1); +{$ifdef print} + writeln('unicodeupper: ',w1); + writeln('original upper: ',w2); + writeln('ansiupper: ',w4); +{$endif print} + if (w1 <> w2) then + doerror(1); + if (w4 <> w2) then + doerror(2); + + w1:='aéèàł'#$d87e#$dc04; + w2:='AÉÈÀŁ'#$d87e#$dc04; + s:=w1; + w3:=s; + w4:=AnsiStrUpper(pchar(s)); + { filter out unsupported characters } + for i:=1 to length(w3) do + if w3[i]='?' then + begin + w2[i]:='?'; + w1[i]:='?'; + end; + w1:=UnicodeUpperCase(w1); +{$ifdef print} + writeln('unicodeupper: ',w1); + writeln('ansistrupper: ',w4); +{$endif print} + if (w1 <> w2) then + doerror(21); + if (w4 <> w2) then + doerror(22); + +end; + + +{ normal lower case testing } +procedure testlower; +var + s: ansistring; + w1,w2,w3,w4: unicodestring; + i: longint; +begin + w1:='AÉ'#0'ÈÀŁ'#$d87e#$dc04; + w2:='aé'#0'èàł'#$d87e#$dc04; +{$ifdef print} +// the utf-8 output can confuse the testsuite parser + writeln('original: ',w1); + writeln('original lower: ',w2); +{$endif print} + s:=w1; + w3:=s; + w4:=AnsiLowerCase(s); + { filter out unsupported characters } + for i:=1 to length(w3) do + if w3[i]='?' then + begin + w2[i]:='?'; + w1[i]:='?'; + end; + w1:=UnicodeLowerCase(w1); +{$ifdef print} + writeln('unicodelower: ',w1); + writeln('ansilower: ',w4); +{$endif print} + if (w1 <> w2) then + doerror(3); + if (w4 <> w2) then + doerror(4); + + + w1:='AÉÈÀŁ'#$d87e#$dc04; + w2:='aéèàł'#$d87e#$dc04; + s:=w1; + w3:=s; + w4:=AnsiStrLower(pchar(s)); + { filter out unsupported characters } + for i:=1 to length(w3) do + if w3[i]='?' then + begin + w2[i]:='?'; + w1[i]:='?'; + end; + w1:=UnicodeLowerCase(w1); +{$ifdef print} + writeln('unicodelower: ',w1); + writeln('ansistrlower: ',w4); +{$endif print} + if (w1 <> w2) then + doerror(3); + if (w4 <> w2) then + doerror(4); +end; + + + +{ upper case testing with a missing utf-16 pair at the end } +procedure testupperinvalid; +var + s: ansistring; + w1,w2,w3,w4: unicodestring; + i: longint; +begin + { missing utf-16 pair at end } + w1:='aé'#0'èàł'#$d87e; + w2:='AÉ'#0'ÈÀŁ'#$d87e; +{$ifdef print} +// the utf-8 output can confuse the testsuite parser + writeln('original: ',w1); + writeln('original upper: ',w2); +{$endif print} + s:=w1; + w3:=s; + w4:=AnsiUpperCase(s); + { filter out unsupported characters } + for i:=1 to length(w3) do + if w3[i]='?' then + begin + w2[i]:='?'; + w1[i]:='?'; + end; + w1:=UnicodeUpperCase(w1); +{$ifdef print} + writeln('unicodeupper: ',w1); + writeln('ansiupper: ',w4); +{$endif print} + if (w1 <> w2) then + doerror(5); + if (w4 <> w2) then + doerror(6); +end; + + +{ lower case testing with a missing utf-16 pair at the end } +procedure testlowerinvalid; +var + s: ansistring; + w1,w2,w3,w4: unicodestring; + i: longint; +begin + { missing utf-16 pair at end} + w1:='AÉ'#0'ÈÀŁ'#$d87e; + w2:='aé'#0'èàł'#$d87e; +{$ifdef print} +// the utf-8 output can confuse the testsuite parser + writeln('original: ',w1); + writeln('original lower: ',w2); +{$endif print} + s:=w1; + w3:=s; + w4:=AnsiLowerCase(s); + { filter out unsupported characters } + for i:=1 to length(w3) do + if w3[i]='?' then + begin + w2[i]:='?'; + w1[i]:='?'; + end; + w1:=UnicodeLowerCase(w1); +{$ifdef print} + writeln('unicodelower: ',w1); + writeln('ansilower: ',w4); +{$endif print} + if (w1 <> w2) then + doerror(7); + if (w4 <> w2) then + doerror(8); +end; + + + +{ upper case testing with a missing utf-16 pair at the end, followed by a normal char } +procedure testupperinvalid1; +var + s: ansistring; + w1,w2,w3,w4: unicodestring; + i: longint; +begin + { missing utf-16 pair at end with char after it} + w1:='aé'#0'èàł'#$d87e'j'; + w2:='AÉ'#0'ÈÀŁ'#$d87e'J'; +{$ifdef print} +// the utf-8 output can confuse the testsuite parser + writeln('original: ',w1); + writeln('original upper: ',w2); +{$endif print} + s:=w1; + w3:=s; + w4:=AnsiUpperCase(s); + { filter out unsupported characters } + for i:=1 to length(w3) do + if w3[i]='?' then + begin + w2[i]:='?'; + w1[i]:='?'; + end; + w1:=UnicodeUpperCase(w1); +{$ifdef print} + writeln('unicodeupper: ',w1); + writeln('ansiupper: ',w4); +{$endif print} + if (w1 <> w2) then + doerror(9); + if (w4 <> w2) then + doerror(10); +end; + + +{ lower case testing with a missing utf-16 pair at the end, followed by a normal char } +procedure testlowerinvalid1; +var + s: ansistring; + w1,w2,w3,w4: unicodestring; + i: longint; +begin + { missing utf-16 pair at end with char after it} + w1:='AÉ'#0'ÈÀŁ'#$d87e'J'; + w2:='aé'#0'èàł'#$d87e'j'; +{$ifdef print} +// the utf-8 output can confuse the testsuite parser + writeln('original: ',w1); + writeln('original lower: ',w2); +{$endif print} + s:=w1; + w3:=s; + w4:=AnsiLowerCase(s); + { filter out unsupported characters } + for i:=1 to length(w3) do + if w3[i]='?' then + begin + w2[i]:='?'; + w1[i]:='?'; + end; + w1:=UnicodeLowerCase(w1); +{$ifdef print} + writeln('unicodelower: ',w1); + writeln('ansilower: ',w4); +{$endif print} + if (w1 <> w2) then + doerror(11); + if (w4 <> w2) then + doerror(12); +end; + + +{ upper case testing with corrupting the utf-8 string after conversion } +procedure testupperinvalid2; +var + s: ansistring; + w1,w2,w3,w4: unicodestring; + i: longint; +begin + w1:='aé'#0'èàł'#$d87e#$dc04'ö'; + w2:='AÉ'#0'ÈÀŁ'#$d87e#$dc04'Ö'; +{$ifdef print} +// the utf-8 output can confuse the testsuite parser + writeln('original: ',w1); + writeln('original upper: ',w2); +{$endif print} + s:=w1; + { truncate the last utf-8 character } + setlength(s,length(s)-1); + w3:=s; + { adjust checking values for new length due to corruption } + if length(w3)<>length(w2) then + begin + setlength(w2,length(w3)); + setlength(w1,length(w3)); + end; + w4:=AnsiUpperCase(s); + { filter out unsupported characters } + for i:=1 to length(w3) do + if w3[i]='?' then + begin + w2[i]:='?'; + w1[i]:='?'; + end; + w1:=UnicodeUpperCase(w1); +{$ifdef print} + writeln('unicodeupper: ',w1); + writeln('ansiupper: ',w4); +{$endif print} + if (w1 <> w2) then + doerror(13); + if (w4 <> w2) then + doerror(14); +end; + + +{ lower case testing with corrupting the utf-8 string after conversion } +procedure testlowerinvalid2; +var + s: ansistring; + w1,w2,w3,w4: unicodestring; + i: longint; +begin + w1:='AÉ'#0'ÈÀŁ'#$d87e#$dc04'Ö'; + w2:='aé'#0'èàł'#$d87e#$dc04'ö'; +{$ifdef print} +// the utf-8 output can confuse the testsuite parser + writeln('original: ',w1); + writeln('original lower: ',w2); +{$endif print} + s:=w1; + { truncate the last utf-8 character } + setlength(s,length(s)-1); + w3:=s; + { adjust checking values for new length due to corruption } + if length(w3)<>length(w2) then + begin + setlength(w2,length(w3)); + setlength(w1,length(w3)); + end; + w4:=AnsiLowerCase(s); + { filter out unsupported characters } + for i:=1 to length(w3) do + if w3[i]='?' then + begin + w2[i]:='?'; + w1[i]:='?'; + end; + w1:=UnicodeLowerCase(w1); +{$ifdef print} + writeln('unicodelower: ',w1); + writeln('ansilower: ',w4); +{$endif print} + if (w1 <> w2) then + doerror(15); + if (w4 <> w2) then + doerror(16); +end; + + + +begin + testupper; + writeln; + testlower; + writeln; + writeln; + testupperinvalid; + writeln; + testlowerinvalid; + writeln; + writeln; + testupperinvalid1; + writeln; + testlowerinvalid1; + writeln; + writeln; + testupperinvalid2; + writeln; + testlowerinvalid2; + writeln('ok'); +end. diff --git a/tests/test/tunistr7.pp b/tests/test/tunistr7.pp new file mode 100644 index 0000000000..c7623793d8 --- /dev/null +++ b/tests/test/tunistr7.pp @@ -0,0 +1,47 @@ +{$codepage utf-8} + +uses +{$ifdef unix} + cwstring, +{$endif unix} + sysutils; + +procedure testwcmp; +var + w1,w2: unicodestring; + s: ansistring; +begin + w1:='aécde'; + { filter unsupported characters } + s:=w1; + w1:=s; + w2:=w1; + + if (w1<>w2) then + halt(1); + w1[2]:='f'; + if (w1=w2) or + WideSameStr(w1,w2) or + (WideCompareText(w1,w2)=0) or + (WideCompareStr(w1,w2)<0) or + (WideCompareStr(w2,w1)>0) then + halt(2); + w1[2]:=#0; + w2[2]:=#0; + if (w1<>w2) or + not WideSameStr(w1,w2) or + (WideCompareStr(w1,w2)<>0) or + (WideCompareText(w1,w2)<>0) then + halt(3); + w1[3]:='m'; + if WideSameStr(w1,w2) or + (WideCompareText(w1,w2)=0) or + (WideCompareStr(w1,w2)<0) or + (WideCompareStr(w2,w1)>0) then + halt(4); +end; + + +begin + testwcmp; +end.