FEAT: warning comment added to predefined typesets.

Red [
	Title:   "Red base environment definitions"
	Author:  "Nenad Rakocevic"
	File: 	 %scalars.red
	Tabs:	 4
	Rights:  "Copyright (C) 2011-2013 Nenad Rakocevic. All rights reserved."
	License: {
		Distributed under the Boost Software License, Version 1.0.
		See https://github.com/dockimbel/Red/blob/master/BSL-License.txt
	}
]

yes: on: true
no: off: false

tab:		 #"^-"
cr: 		 #"^M"
newline: lf: #"^/"
escape:      #"^["
slash: 		 #"/"
sp: space: 	 #" "
null: 		 #"^@"
crlf:		 "^M^/"
dot:		 #"."
comma:		 #","

pi: 3.141592653589793

;-- warning: following typeset definitions are processed by the compiler, do not change them
;-- unless you know what you are doing!

internal!:		make typeset! [unset!]
number!:		make typeset! [integer! float! percent!]
scalar!:		union number! make typeset! [char! pair! tuple!]
any-word!:		make typeset! [word! set-word! get-word! lit-word! refinement! issue!]
any-path!:		make typeset! [path! set-path! get-path! lit-path!]
any-block!:		union any-path! make typeset! [block! paren! hash!]
any-function!:	make typeset! [native! action! op! function! routine!]
any-object!:	make typeset! [object! error!]
any-string!:	make typeset! [string! file! url!]
series!:		union make typeset! [vector!] union any-block! any-string!
immediate!:		union scalar! union any-word! make typeset! [none! logic! datatype! typeset!]
default!:		union series! union immediate! union any-object! union any-function! make typeset! [bitset!]
any-type!:		union default! internal!

;-- color definitions (from CSS4 standard) --

AliceBlue:            240.248.255
AntiqueWhite:         250.235.215
Aqua:                 0.255.255
Aquamarine:           127.255.212
Azure:                240.255.255
Beige:                245.245.220
Bisque:               255.228.196
Black:                0.0.0
BlanchedAlmond:       255.235.205
Blue:                 0.0.255
BlueViolet:           138.43.226
Brown:                165.42.42
BurlyWood:            222.184.135
CadetBlue:            95.158.160
Chartreuse:           127.255.0
Chocolate:            210.105.30
Coral:                255.127.80
CornflowerBlue:       100.149.237
Cornsilk:             255.248.220
Crimson:              220.20.60
Cyan:                 0.255.255
DarkBlue:             0.0.139
DarkCyan:             0.139.139
DarkGoldenrod:        184.134.11
DarkGray:             169.169.169
DarkGreen:            0.100.0
DarkKhaki:            189.183.107
DarkMagenta:          139.0.139
DarkOliveGreen:       85.107.47
DarkOrange:           255.140.0
DarkOrchid:           153.50.204
DarkRed:              139.0.0
DarkSalmon:           233.150.122
DarkSeaGreen:         143.188.143
DarkSlateBlue:        72.61.139
DarkSlateGray:        47.79.79
DarkTurquoise:        0.206.209
DarkViolet:           148.0.211
DeepPink:             255.20.147
DeepSkyBlue:          0.191.255
DimGray:              105.105.105
DodgerBlue:           30.144.255
FireBrick:            178.34.34
FloralWhite:          255.250.240
ForestGreen:          34.139.34
Fuchsia:              255.0.255
Gainsboro:            220.220.220
GhostWhite:           248.248.255
Gold:                 255.215.0
Goldenrod:            218.165.32
Gray:                 128.128.128
Green:                0.128.0
GreenYellow:          173.255.47
Honeydew:             240.255.240
HotPink:              255.105.180
IndianRed:            205.92.92
Indigo:               75.0.130
Ivory:                255.255.240
Khaki:                240.230.140
Lavender:             230.230.250
LavenderBlush:        255.240.245
LawnGreen:            124.252.0
LemonChiffon:         255.250.205
LightBlue:            173.216.230
LightCoral:           240.128.128
LightCyan:            224.255.255
LightGoldenrodYellow: 250.250.210
LightGreen:           144.238.144
LightGrey:            211.211.211
LightPink:            255.182.193
LightSalmon:          255.160.122
LightSeaGreen:        32.178.170
LightSkyBlue:         135.206.250
LightSlateGray:       119.136.153
LightSteelBlue:       176.196.222
LightYellow:          255.255.224
Lime:                 0.255.0
LimeGreen:            50.205.50
Linen:                250.240.230
Magenta:              255.0.255
Maroon:               128.0.0
MediumAquamarine:     102.205.170
MediumBlue:           0.0.205
MediumOrchid:         186.85.211
MediumPurple:         147.112.219
MediumSeaGreen:       60.179.113
MediumSlateBlue:      123.104.238
MediumSpringGreen:    0.250.154
MediumTurquoise:      72.209.204
MediumVioletRed:      199.21.133
MidnightBlue:         25.25.112
MintCream:            245.255.250
MistyRose:            255.228.225
Moccasin:             255.228.181
NavajoWhite:          255.222.173
Navy:                 0.0.128
OldLace:              253.245.230
Olive:                128.128.0
OliveDrab:            107.142.35
Orange:               255.165.0
OrangeRed:            255.69.0
Orchid:               218.112.214
PaleGoldenrod:        238.232.170
PaleGreen:            152.251.152
PaleTurquoise:        175.238.238
PaleVioletRed:        219.112.147
PapayaWhip:           255.239.213
PeachPuff:            255.218.185
Peru:                 205.133.63
Pink:                 255.192.203
Plum:                 221.160.221
PowderBlue:           176.224.230
Purple:               128.0.128
RebeccaPurple:        102.51.153
Red:                  255.0.0
RosyBrown:            188.143.143
RoyalBlue:            65.105.225
SaddleBrown:          139.69.19
Salmon:               250.128.114
SandyBrown:           244.164.96
SeaGreen:             46.139.87
Seashell:             255.245.238
Sienna:               160.82.45
Silver:               192.192.192
SkyBlue:              135.206.235
SlateBlue:            106.90.205
SlateGray:            112.128.144
Snow:                 255.250.250
SpringGreen:          0.255.127
SteelBlue:            70.130.180
Tan:                  210.180.140
Teal:                 0.128.128
Thistle:              216.191.216
Tomato:               255.99.71
Turquoise:            64.224.208
Violet:               238.130.238
Wheat:                245.222.179
White:                255.255.255
WhiteSmoke:           245.245.245
Yellow:               255.255.0
YellowGreen:          154.205.50

Red [
	Title:   "Red base environment definitions"
	Author:  "Nenad Rakocevic"
	File: 	 %scalars.red
	Tabs:	 4
	Rights:  "Copyright (C) 2011-2013 Nenad Rakocevic. All rights reserved."
	License: {
		Distributed under the Boost Software License, Version 1.0.
		See https://github.com/dockimbel/Red/blob/master/BSL-License.txt
	}
]

yes: on: true
no: off: false

tab:		 #"^-"
cr: 		 #"^M"
newline: lf: #"^/"
escape:      #"^["
slash: 		 #"/"
sp: space: 	 #" "
null: 		 #"^@"
crlf:		 "^M^/"
dot:		 #"."
comma:		 #","

pi: 3.141592653589793

internal!:		make typeset! [unset!]
number!:		make typeset! [integer! float! percent!]
scalar!:		union number! make typeset! [char! pair! tuple!]
any-word!:		make typeset! [word! set-word! get-word! lit-word! refinement! issue!]
any-path!:		make typeset! [path! set-path! get-path! lit-path!]
any-block!:		union any-path! make typeset! [block! paren! hash!]
any-function!:	make typeset! [native! action! op! function! routine!]
any-object!:	make typeset! [object! error!]
any-string!:	make typeset! [string! file! url!]
series!:		union make typeset! [vector!] union any-block! any-string!
immediate!:		union scalar! union any-word! make typeset! [none! logic! datatype! typeset!]
default!:		union series! union immediate! union any-object! union any-function! make typeset! [bitset!]
any-type!:		union default! internal!

;-- color definitions (from CSS4 standard) --

AliceBlue:            240.248.255
AntiqueWhite:         250.235.215
Aqua:                 0.255.255
Aquamarine:           127.255.212
Azure:                240.255.255
Beige:                245.245.220
Bisque:               255.228.196
Black:                0.0.0
BlanchedAlmond:       255.235.205
Blue:                 0.0.255
BlueViolet:           138.43.226
Brown:                165.42.42
BurlyWood:            222.184.135
CadetBlue:            95.158.160
Chartreuse:           127.255.0
Chocolate:            210.105.30
Coral:                255.127.80
CornflowerBlue:       100.149.237
Cornsilk:             255.248.220
Crimson:              220.20.60
Cyan:                 0.255.255
DarkBlue:             0.0.139
DarkCyan:             0.139.139
DarkGoldenrod:        184.134.11
DarkGray:             169.169.169
DarkGreen:            0.100.0
DarkKhaki:            189.183.107
DarkMagenta:          139.0.139
DarkOliveGreen:       85.107.47
DarkOrange:           255.140.0
DarkOrchid:           153.50.204
DarkRed:              139.0.0
DarkSalmon:           233.150.122
DarkSeaGreen:         143.188.143
DarkSlateBlue:        72.61.139
DarkSlateGray:        47.79.79
DarkTurquoise:        0.206.209
DarkViolet:           148.0.211
DeepPink:             255.20.147
DeepSkyBlue:          0.191.255
DimGray:              105.105.105
DodgerBlue:           30.144.255
FireBrick:            178.34.34
FloralWhite:          255.250.240
ForestGreen:          34.139.34
Fuchsia:              255.0.255
Gainsboro:            220.220.220
GhostWhite:           248.248.255
Gold:                 255.215.0
Goldenrod:            218.165.32
Gray:                 128.128.128
Green:                0.128.0
GreenYellow:          173.255.47
Honeydew:             240.255.240
HotPink:              255.105.180
IndianRed:            205.92.92
Indigo:               75.0.130
Ivory:                255.255.240
Khaki:                240.230.140
Lavender:             230.230.250
LavenderBlush:        255.240.245
LawnGreen:            124.252.0
LemonChiffon:         255.250.205
LightBlue:            173.216.230
LightCoral:           240.128.128
LightCyan:            224.255.255
LightGoldenrodYellow: 250.250.210
LightGreen:           144.238.144
LightGrey:            211.211.211
LightPink:            255.182.193
LightSalmon:          255.160.122
LightSeaGreen:        32.178.170
LightSkyBlue:         135.206.250
LightSlateGray:       119.136.153
LightSteelBlue:       176.196.222
LightYellow:          255.255.224
Lime:                 0.255.0
LimeGreen:            50.205.50
Linen:                250.240.230
Magenta:              255.0.255
Maroon:               128.0.0
MediumAquamarine:     102.205.170
MediumBlue:           0.0.205
MediumOrchid:         186.85.211
MediumPurple:         147.112.219
MediumSeaGreen:       60.179.113
MediumSlateBlue:      123.104.238
MediumSpringGreen:    0.250.154
MediumTurquoise:      72.209.204
MediumVioletRed:      199.21.133
MidnightBlue:         25.25.112
MintCream:            245.255.250
MistyRose:            255.228.225
Moccasin:             255.228.181
NavajoWhite:          255.222.173
Navy:                 0.0.128
OldLace:              253.245.230
Olive:                128.128.0
OliveDrab:            107.142.35
Orange:               255.165.0
OrangeRed:            255.69.0
Orchid:               218.112.214
PaleGoldenrod:        238.232.170
PaleGreen:            152.251.152
PaleTurquoise:        175.238.238
PaleVioletRed:        219.112.147
PapayaWhip:           255.239.213
PeachPuff:            255.218.185
Peru:                 205.133.63
Pink:                 255.192.203
Plum:                 221.160.221
PowderBlue:           176.224.230
Purple:               128.0.128
RebeccaPurple:        102.51.153
Red:                  255.0.0
RosyBrown:            188.143.143
RoyalBlue:            65.105.225
SaddleBrown:          139.69.19
Salmon:               250.128.114
SandyBrown:           244.164.96
SeaGreen:             46.139.87
Seashell:             255.245.238
Sienna:               160.82.45
Silver:               192.192.192
SkyBlue:              135.206.235
SlateBlue:            106.90.205
SlateGray:            112.128.144
Snow:                 255.250.250
SpringGreen:          0.255.127
SteelBlue:            70.130.180
Tan:                  210.180.140
Teal:                 0.128.128
Thistle:              216.191.216
Tomato:               255.99.71
Turquoise:            64.224.208
Violet:               238.130.238
Wheat:                245.222.179
White:                255.255.255
WhiteSmoke:           245.245.245
Yellow:               255.255.0
YellowGreen:          154.205.50


FEAT: removed macro-defs.reds, no longer needed.

Red/System [
	Title:   "Red runtime global macro definitions"
	Author:  "Nenad Rakocevic"
	File: 	 %macro-defs.reds
	Rights:  "Copyright (C) 2011 Nenad Rakocevic. All rights reserved."
	License: {
		Distributed under the Boost Software License, Version 1.0.
		See https://github.com/dockimbel/Red/blob/master/red-system/runtime/BSL-License.txt
	}
]

#enum datatypes! [
	RED_TYPE_DATATYPE
	RED_TYPE_UNSET
	RED_TYPE_NONE
	RED_TYPE_LOGIC
	RED_TYPE_BLOCK
	RED_TYPE_PAREN
	RED_TYPE_INTEGER
	RED_TYPE_CONTEXT
	RED_TYPE_WORD
	RED_TYPE_SET_WORD
	RED_TYPE_GET_WORD
	RED_TYPE_LIT_WORD
	RED_TYPE_REFINEMENT
	RED_TYPE_BINARY
	RED_TYPE_STRING
	RED_TYPE_CHAR
	RED_TYPE_ISSUE
	RED_TYPE_PATH
	RED_TYPE_SET_PATH
	RED_TYPE_LIT_PATH
	RED_TYPE_NATIVE
	RED_TYPE_ACTION
	RED_TYPE_FUNCTION
	RED_TYPE_OBJECT
	RED_TYPE_PORT
	RED_TYPE_BITSET
	RED_TYPE_FLOAT
]


FEAT: added missing UCS-2 to UCS-4 conversion routine.

Red/System [
	Title:   "Unicode codecs"
	Author:  "Nenad Rakocevic, Rudolf W. Meijer"
	File: 	 %unicode.reds
	Rights:  "Copyright (C) 2011 Nenad Rakocevic. All rights reserved."
	License: {
		Distributed under the Boost Software License, Version 1.0.
		See https://github.com/dockimbel/Red/blob/master/red-system/runtime/BSL-License.txt
	}
]

#enum encoding! [
	Latin1: 1
	UCS-2:  2
	UCS-4:  4
]

unicode: context [
	verbose: 0

	#define U_REPLACEMENT 	FFFDh
	;	choose one of the following options
	;	FFFDh			; U+FFFD = replacement character
	;	1Ah				; U+001A = control SUB (substitute)
	;	241Ah			; U+241A = symbol for substitute
	;	2426h			; U+2426 = symbol for substitute form two
	;	3Fh				; U+003F = question mark
	;	BFh				; U+00BF = inverted question mark
	;	DC00h + b1		; U+DCxx where xx = b1 (never a Unicode codepoint)

	latin1-to-UCS2: func [
		s		 [series!]
		return:	 [series!]
		/local
			used [integer!]
			base [byte-ptr!]
			src  [byte-ptr!]
			dst  [byte-ptr!]
	][
		#if debug? = yes [if verbose > 0 [print-line "unicode/latin1-to-UCS2"]]

		used: as-integer s/tail - s/offset
		if used * 2 >= s/size [							;-- ensure we have enough space
			s: expand-series s used * 2 + 1
		]
		base: as byte-ptr! s/offset
		src:  as byte-ptr! s/tail						;-- start from end
		dst:  (as byte-ptr! s/offset) + (used * 2)
		s/tail: as cell! dst							;-- adjust to new tail

		while [src > base][								;-- in-place conversion
			src: src - 1
			dst: dst - 2
			dst/1: src/1
			dst/2: null-byte
		]
		s/flags: s/flags and flag-unit-mask or UCS-2	;-- s/unit: UCS-2
		s
	]

	UCS2-to-UCS4: func [
		s		 [series!]
		return:	 [series!]
		/local
			used [integer!]
			base [byte-ptr!]
			src  [byte-ptr!]
			dst  [int-ptr!]
	][
		#if debug? = yes [if verbose > 0 [print-line "unicode/UCS2-to-UCS4"]]

		used: as-integer s/tail - s/offset
		if used * 2 >= s/size [							;-- ensure we have enough space
			s: expand-series s used * 2 + 1
		]
		base: as byte-ptr! s/offset
		src:  as byte-ptr! s/tail						;-- start from end
		dst:  as int-ptr! (as byte-ptr! s/offset) + (used * 2)
		s/tail: as cell! dst							;-- adjust to new tail

		while [src > base][								;-- in-place conversion
			src: src - 2
			dst: dst - 1
			dst/value: (as-integer src/2) << 8 + src/1
		]
		s/flags: s/flags and flag-unit-mask or UCS-4	;-- s/unit: UCS-4
		s
	]

	load-utf8: func [
		src		   [c-string!]							;-- UTF-8 input buffer (zero-terminated)
		size	   [integer!]							;-- size of src in bytes
		return:	   [node!]
		/local
			node   [node!]
			s 	   [series!]
			buf1   [byte-ptr!]
			buf4   [int-ptr!]
			end    [byte-ptr!]
			unit   [integer!]
			b1 	   [integer!]							;-- up to four bytes in a UTF-8 sequence
			b2	   [integer!]							;-- for computing purposes they are of integer! type
			b3     [integer!]
			b4     [integer!]
			cp	   [integer!]							; computed codepoint
	][
		#if debug? = yes [if verbose > 0 [print-line "unicode/load-utf8"]]

		assert positive? size
		node: alloc-series size 1 0

		s:    as series! node/value
		buf1: as byte-ptr! s/offset
		end:  buf1 + s/size
		unit: Latin1									;-- start with 1 byte/codepoint

		assert not zero? as-integer src/1				;@@ ensure input string not empty

		;-- the first part of loop is Rudolf's code with very minor modifications
		;-- (res/value replaced by cp, 'u renamed to 'src)
		;-- original source code: https://gist.github.com/1325840

		until [
			b1: as-integer src/1

			; cycling through res is done at the end; likewise for src
			; to account for this, as soon as a multiple byte sequence is consumed
			; the pointer in src is moved one less than the number of bytes consumed

			either b1 < 80h	[							; single byte (ASCII)
				cp: b1									; and we are done
			][
				cp: U_REPLACEMENT
				; assume error by default - this simplifies code greatly
				; cp is now only set if a correct sequence has been decoded

				unless b1 < C0h [						; 80h - BFh may not start a sequence
					case  [
						b1 < E0h [						; start of two-byte sequence
							b2: as-integer src/2
							if all [
								b2 >= 80h b2 < C0h
							][
								cp:	(b1 - C0h << 6) or
									(b2 - 80h)
	;							if any [
	;								cp > 7Fh			; optional test for overlong
	;								cp = 0				; even so, must allow U+0000
	;							][
									src: src + 1
	;							]
							]
						]
						b1 < F0h [						; start of three-byte sequence
							b2: as-integer src/2
							b3: as-integer src/3
							if all [
								b2 >= 80h b2 < C0h
								b3 >= 80h b3 < C0h
							][
								cp:	(b1 - E0h << 12) or
									(b2 - 80h <<  6) or
									(b3 - 80h)
								if all [
									any [cp < DC00h cp > DCFFh]
	;								cp > 7FFh			; optional test for overlong
								][
									src: src + 2
								]
							]
						]
						b1 < F8h [						; start of four-byte sequence
							b2: as-integer src/2
							b3: as-integer src/3
							b4: as-integer src/4
							if all [
								b2 >= 80h b2 < C0h
								b3 >= 80h b3 < C0h
								b4 >= 80h b4 < C0h
							][
								cp:	(b1 - F0h << 18) or
									(b2 - 80h << 12) or
									(b3 - 80h <<  6) or
									(b4 - 80h)
								if all [
									cp <= 0010FFFFh
	;								cp > FFFFh			; optional test for overlong
								][
									src: src + 3
								]
							]
						]
	;					true [
	;						error case					;@@ throw an error! value
	;					]
					]
				]
			]

			switch unit [
				Latin1 [
					either cp > 255 [
						s/tail: as cell! buf1
						unit: UCS-2
						s:    latin1-to-UCS2 s			;-- upgrade to UCS-2
						buf1: as byte-ptr! s/tail
						end:  (as byte-ptr! s/offset) + s/size

						buf1/1: as-byte cp and FFh
						buf1/2: as-byte cp >> 8
						buf1: buf1 + 2
					][
						buf1/value: as-byte cp
						buf1: buf1 + 1
						assert buf1 <= end				;@@ should not happen if we're good
					]
				]
				UCS-2 [
					either cp > 65535 [
						s/tail: as cell! buf1
						unit: UCS-4
						s:    UCS2-to-UCS4 s			;-- upgrade to UCS-4
						buf4: as int-ptr! s/tail
						end:  (as byte-ptr! s/offset) + s/size

						buf4/value: cp
						buf4: buf4 + 1
					][
						if buf1 >= end [
							s/tail: as cell! buf1
							s: expand-series s s/size + (size >> 2)	;-- increase size by 50%
							buf1: as byte-ptr! s/tail
							end: (as byte-ptr! s/offset) + s/size
						]
						buf1/1: as-byte cp and FFh
						buf1/2: as-byte cp >> 8
						buf1: buf1 + 2
					]
				]
				UCS-4 [
					if buf4 >= (as int-ptr! end) [
						s: expand-series s s/size + size ;-- increase size by 100%
						buf4: as int-ptr! s/tail
						end: (as byte-ptr! s/offset) + s/size
					]
					buf4/value: cp
					buf4: buf4 + 1
				]
			]
			src: src + 1
			zero? b1
		] 												;-- end until

		s/tail: as cell! switch unit [					;-- position s/tail just before the NUL character
			Latin1 [buf1 - 1]
			UCS-2  [buf1 - 2]
			UCS-4  [buf4 - 1]
		]
		assert s/size + GET_UNIT(s) >= as-integer (s/tail - s/offset)

		node
	]

]

Red/System [
	Title:   "Unicode codecs"
	Author:  "Nenad Rakocevic, Rudolf W. Meijer"
	File: 	 %unicode.reds
	Rights:  "Copyright (C) 2011 Nenad Rakocevic. All rights reserved."
	License: {
		Distributed under the Boost Software License, Version 1.0.
		See https://github.com/dockimbel/Red/blob/master/red-system/runtime/BSL-License.txt
	}
]

#enum encoding! [
	Latin1: 1
	UCS-2:  2
	UCS-4:  4
]

unicode: context [
	verbose: 0

	#define U_REPLACEMENT 	FFFDh
	;	choose one of the following options
	;	FFFDh			; U+FFFD = replacement character
	;	1Ah				; U+001A = control SUB (substitute)
	;	241Ah			; U+241A = symbol for substitute
	;	2426h			; U+2426 = symbol for substitute form two
	;	3Fh				; U+003F = question mark
	;	BFh				; U+00BF = inverted question mark
	;	DC00h + b1		; U+DCxx where xx = b1 (never a Unicode codepoint)

	latin1-to-UCS2: func [
		s		 [series!]
		return:	 [series!]
		/local
			used [integer!]
			base [byte-ptr!]
			src  [byte-ptr!]
			dst  [byte-ptr!]
	][
		#if debug? = yes [if verbose > 0 [print-line "unicode/latin1-to-UCS2"]]

		used: as-integer s/tail - s/offset
		if used * 2 >= s/size [							;-- ensure we have enough space
			s: expand-series s used * 2 + 1
		]
		base: as byte-ptr! s/offset
		src:  as byte-ptr! s/tail						;-- start from end
		dst:  (as byte-ptr! s/offset) + (used * 2)
		s/tail: as cell! dst							;-- adjust to new tail

		while [src > base][								;-- in-place conversion
			src: src - 1
			dst: dst - 2
			dst/1: src/1
			dst/2: null-byte
		]
		s/flags: s/flags and flag-unit-mask or UCS-2	;-- s/unit: UCS-2
		s
	]

	UCS2-to-UCS4: func [
		s		 [series!]
		return:	 [series!]
	][
		assert false

		#if debug? = yes [if verbose > 0 [print-line "unicode/UCS2-to-UCS4"]]

		;TBD
		s/flags: s/flags and flag-unit-mask or UCS-4	;-- s/unit: UCS-4
		s
	]

	load-utf8: func [
		src		   [c-string!]							;-- UTF-8 input buffer (zero-terminated)
		size	   [integer!]							;-- size of src in bytes
		return:	   [node!]
		/local
			node   [node!]
			s 	   [series!]
			buf1   [byte-ptr!]
			buf4   [int-ptr!]
			end    [byte-ptr!]
			unit   [integer!]
			b1 	   [integer!]							;-- up to four bytes in a UTF-8 sequence
			b2	   [integer!]							;-- for computing purposes they are of integer! type
			b3     [integer!]
			b4     [integer!]
			cp	   [integer!]							; computed codepoint
	][
		#if debug? = yes [if verbose > 0 [print-line "unicode/load-utf8"]]

		assert positive? size
		node: alloc-series size 1 0

		s:    as series! node/value
		buf1: as byte-ptr! s/offset
		end:  buf1 + s/size
		unit: Latin1									;-- start with 1 byte/codepoint

		assert not zero? as-integer src/1				;@@ ensure input string not empty

		;-- the first part of loop is Rudolf's code with very minor modifications
		;-- (res/value replaced by cp, 'u renamed to 'src)
		;-- original source code: https://gist.github.com/1325840

		until [
			b1: as-integer src/1

			; cycling through res is done at the end; likewise for src
			; to account for this, as soon as a multiple byte sequence is consumed
			; the pointer in src is moved one less than the number of bytes consumed

			either b1 < 80h	[							; single byte (ASCII)
				cp: b1									; and we are done
			][
				cp: U_REPLACEMENT
				; assume error by default - this simplifies code greatly
				; cp is now only set if a correct sequence has been decoded

				unless b1 < C0h [						; 80h - BFh may not start a sequence
					case  [
						b1 < E0h [						; start of two-byte sequence
							b2: as-integer src/2
							if all [
								b2 >= 80h b2 < C0h
							][
								cp:	(b1 - C0h << 6) or
									(b2 - 80h)
	;							if any [
	;								cp > 7Fh			; optional test for overlong
	;								cp = 0				; even so, must allow U+0000
	;							][
									src: src + 1
	;							]
							]
						]
						b1 < F0h [						; start of three-byte sequence
							b2: as-integer src/2
							b3: as-integer src/3
							if all [
								b2 >= 80h b2 < C0h
								b3 >= 80h b3 < C0h
							][
								cp:	(b1 - E0h << 12) or
									(b2 - 80h <<  6) or
									(b3 - 80h)
								if all [
									any [cp < DC00h cp > DCFFh]
	;								cp > 7FFh			; optional test for overlong
								][
									src: src + 2
								]
							]
						]
						b1 < F8h [						; start of four-byte sequence
							b2: as-integer src/2
							b3: as-integer src/3
							b4: as-integer src/4
							if all [
								b2 >= 80h b2 < C0h
								b3 >= 80h b3 < C0h
								b4 >= 80h b4 < C0h
							][
								cp:	(b1 - F0h << 18) or
									(b2 - 80h << 12) or
									(b3 - 80h <<  6) or
									(b4 - 80h)
								if all [
									cp <= 0010FFFFh
	;								cp > FFFFh			; optional test for overlong
								][
									src: src + 3
								]
							]
						]
	;					true [
	;						error case					;@@ throw an error! value
	;					]
					]
				]
			]

			switch unit [
				Latin1 [
					either cp > 255 [
						s/tail: as cell! buf1
						unit: UCS-2
						s:    latin1-to-UCS2 s			;-- upgrade to UCS-2
						buf1: as byte-ptr! s/tail
						end:  (as byte-ptr! s/offset) + s/size

						buf1/1: as-byte cp and FFh
						buf1/2: as-byte cp >> 8
						buf1: buf1 + 2
					][
						buf1/value: as-byte cp
						buf1: buf1 + 1
						assert buf1 <= end				;@@ should not happen if we're good
					]
				]
				UCS-2 [
					either cp > 65535 [
						s/tail: as cell! buf1
						unit: UCS-4
						s:    UCS2-to-UCS4 s			;-- upgrade to UCS-4
						buf4: as int-ptr! s/tail
						end:  (as byte-ptr! s/offset) + s/size

						buf4/value: cp
						buf4: buf4 + 1
					][
						if buf1 >= end [
							s/tail: as cell! buf1
							s: expand-series s s/size + (size >> 2)	;-- increase size by 50%
							buf1: as byte-ptr! s/tail
							end: (as byte-ptr! s/offset) + s/size
						]
						buf1/1: as-byte cp and FFh
						buf1/2: as-byte cp >> 8
						buf1: buf1 + 2
					]
				]
				UCS-4 [
					if buf4 >= (as int-ptr! end) [
						s: expand-series s s/size + size ;-- increase size by 100%
						buf4: as int-ptr! s/tail
						end: (as byte-ptr! s/offset) + s/size
					]
					buf4/value: cp
					buf4: buf4 + 1
				]
			]
			src: src + 1
			zero? b1
		] 												;-- end until

		s/tail: as cell! switch unit [					;-- position s/tail just before the NUL character
			Latin1 [buf1 - 1]
			UCS-2  [buf1 - 2]
			UCS-4  [buf4 - 1]
		]
		assert s/size + GET_UNIT(s) >= as-integer (s/tail - s/offset)

		node
	]

]