FIX: added missing /extern refinement to FUNCTION spec block.

Red [
	Title:   "Red base environment definitions"
	Author:  "Nenad Rakocevic"
	File: 	 %boot.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
	}
]

;-- datatype! is not defined here for obvious circular reference issue

unset!:			make datatype! #get-definition TYPE_UNSET
none!:			make datatype! #get-definition TYPE_NONE
logic!:			make datatype! #get-definition TYPE_LOGIC
block!:			make datatype! #get-definition TYPE_BLOCK
string!:		make datatype! #get-definition TYPE_STRING
integer!:		make datatype! #get-definition TYPE_INTEGER
;symbol!:		make datatype! #get-definition TYPE_SYMBOL
;context!:		make datatype! #get-definition TYPE_CONTEXT
word!:			make datatype! #get-definition TYPE_WORD
error!:			make datatype! #get-definition TYPE_ERROR
typeset!:		make datatype! #get-definition TYPE_TYPESET
file!:			make datatype! #get-definition TYPE_FILE

set-word!:		make datatype! #get-definition TYPE_SET_WORD
get-word!:		make datatype! #get-definition TYPE_GET_WORD
lit-word!:		make datatype! #get-definition TYPE_LIT_WORD
refinement!:	make datatype! #get-definition TYPE_REFINEMENT
binary!:		make datatype! #get-definition TYPE_BINARY
paren!:			make datatype! #get-definition TYPE_PAREN
char!:			make datatype! #get-definition TYPE_CHAR
issue!:			make datatype! #get-definition TYPE_ISSUE
path!:			make datatype! #get-definition TYPE_PATH
set-path!:		make datatype! #get-definition TYPE_SET_PATH
get-path!:		make datatype! #get-definition TYPE_GET_PATH
lit-path!:		make datatype! #get-definition TYPE_LIT_PATH
native!:		make datatype! #get-definition TYPE_NATIVE
action!:		make datatype! #get-definition TYPE_ACTION
op!:			make datatype! #get-definition TYPE_OP
function!:		make datatype! #get-definition TYPE_FUNCTION
closure!:		make datatype! #get-definition TYPE_CLOSURE
routine!:		make datatype! #get-definition TYPE_ROUTINE
object!:		make datatype! #get-definition TYPE_OBJECT
port!:			make datatype! #get-definition TYPE_PORT
bitset!:		make datatype! #get-definition TYPE_BITSET
float!:			make datatype! #get-definition TYPE_FLOAT

none:  			make none! 0
true:  			make logic! 1
false: 			make logic! 0

;------------------------------------------
;-				Actions					  -
;------------------------------------------

make: make action! [[									;--	this one works!	;-)
		"Returns a new value made from a specification for that value's type."
		type	 [any-type!] "The datatype or a prototype value."
		spec	 [any-type!] "The specification	of the new value."
		return:  [any-type!] "Returns the specified datatype."
	]
	#get-definition ACT_MAKE
]

;random

reflect: make action! [[
		"Returns internal details about a value via reflection."
		value	[any-type!]
		field 	[word!] "spec, body, words, etc. Each datatype defines its own reflectors"
	]
	#get-definition ACT_REFLECT
]

;to

form: make action! [[
		"Returns a user-friendly string representation of a value."
		value	  [any-type!]
		/part "Limit the length of the result"
			limit [integer!]
		return:	  [string!]
	]
	#get-definition ACT_FORM
]

mold: make action! [[
		"Returns a source format string representation of a value."
		value	  [any-type!]
		/only "Exclude outer brackets if value is a block"
		/all  "TBD: Return value in loadable format"
		/flat "TBD: Exclude all indentation"
		/part "Limit the length of the result"
			limit [integer!]
		return:	  [string!]
	]
	#get-definition ACT_MOLD
]

;-- Scalar actions --

absolute: make action! [[
		"Returns the non-negative value."
		value	 [number!]
		return:  [number!]
	]
	#get-definition ACT_ABSOLUTE
]

add: make action! [[
		"Returns the sum of the two values."
		value1	 [number!]
		value2	 [number!]
		return:  [number!]
	]
	#get-definition ACT_ADD
]

divide: make action! [[
		"Returns the quotient of two values."
		value1	 [number!] "The dividend (numerator)."
		value2	 [number!] "The divisor (denominator)."
		return:  [number!]
	]
	#get-definition ACT_DIVIDE
]

multiply: make action! [[
		"Returns the product of two values."
		value1	 [number!]
		value2	 [number!]
		return:  [number!]
	]
	#get-definition ACT_MULTIPLY
]

negate: make action! [[
		"Returns the inverse value."
		number 	 [number!]
		return:  [number!]
	]
	#get-definition ACT_NEGATE
]

power: make action! [[
		"Returns a number raised to a given power (exponent)."
		number	 [number!] "Base value."
		exponent [number!] "The power (index) to raise the base value by."
		return:	 [number!]
	]
	#get-definition ACT_POWER
]

remainder: make action! [[
		"Returns what is left over when one value is divided by another."
		value1 	 [number!]
		value2 	 [number!]
		return:  [number!]
	]
	#get-definition ACT_REMAINDER
]

round: make action! [[
		"TBD: Returns the nearest integer. Halves round up (away from zero) by default."
		n		[number!]
		/to		"Return the nearest multiple of the scale parameter"
		scale	[number!] "Must be a non-zero value"
		/even		"Halves round toward even results"
		/down		"Round toward zero, ignoring discarded digits. (truncate)"
		/half-down	"Halves round toward zero"
		/floor		"Round in negative direction"
		/ceiling	"Round in positive direction"
		/half-ceiling "Halves round in positive direction"
	]
	#get-definition ACT_ROUND
]

subtract: make action! [[
		"Returns the difference between two values."
		value1	 [number!]
		value2	 [number!]
		return:  [number!]
	]
	#get-definition ACT_SUBTRACT
]

even?: make action! [[
		"Returns true if the number is evenly divisible by 2."
		number 	 [number!]
		return:  [number!]
	]
	#get-definition ACT_EVEN?
]

odd?: make action! [[
		"Returns true if the number has a remainder of 1 when divided by 2."
		number 	 [number!]
		return:  [number!]
	]
	#get-definition ACT_ODD?
]

;-- Bitwise actions --

;and~
;complement
;or~
;xor~

;-- Series actions --

append: make action! [[
		"Inserts value(s) at series tail; returns series head."
		series	   [series!]
		value	   [any-type!]
		/part "Limit the number of values inserted"
			length [number! series!]
		/only "Insert block types as single values (overrides /part)"
		/dup  "Duplicate the inserted values"
			count  [number!]
		return:    [series!]
	]
	#get-definition ACT_APPEND
]

at: make action! [[
		"Returns a series at a given index."
		series	 [series!]
		index 	 [integer!]
		return:  [series!]
	]
	#get-definition ACT_AT
]

back: make action! [[
		"Returns a series at the previous index."
		series	 [series!]
		return:  [series!]
	]
	#get-definition ACT_BACK
]

;change

clear: make action! [[
		"Removes series values from current index to tail; returns new tail."
		series	 [series!]
		return:  [series!]
	]
	#get-definition ACT_CLEAR
]

copy: make action! [[
		"Returns a copy of a non-scalar value."
		value	 [series!]
		/part	 "Limit the length of the result"
			length [number! series!]
		/deep	 "Copy nested values"
		/types	 "Copy only specific types of non-scalar values"
			kind [datatype!]
		return:  [series!]
	]
	#get-definition ACT_COPY
]

find: make action! [[
		"Returns the series where a value is found; NONE if value is not found."
		series	 [series! none!]
		value 	 [any-type!]
		/part "Limit the length of the search"
			length [number! series!]
		/only "Treat a series search value as a single value"
		/case "Perform a case-sensitive search"
		/any  "TBD: Use * and ? wildcards in string searches"
		/with "TBD: Use custom wildcards in place of * and ?"
			wild [string!]
		/skip "Treat the series as fixed size records"
			size [integer!]
		/last "Find the last occurrence of value, from the tail"
		/reverse "Find the last occurrence of value, from the current index"
		/tail "Return the tail of the match found, rather than the head"
		/match "Match at current index only and return tail of match"
	]
	#get-definition ACT_FIND
]

head: make action! [[
		"Returns a series at its first index."
		series	 [series!]
		return:  [series!]
	]
	#get-definition ACT_HEAD
]

head?: make action! [[
		"Returns true if a series is at its first index."
		series	 [series!]
		return:  [logic!]
	]
	#get-definition ACT_HEAD?
]

index?: make action! [[
		"Returns the current series index, relative to the head."
		series	 [series!]
		return:  [integer!]
	]
	#get-definition ACT_INDEX?
]

;insert

length?: make action! [[
		"Returns the number of values in the series, from the current index to the tail."
		series	 [series!]
		return:  [integer!]
	]
	#get-definition ACT_LENGTH?
]

next: make action! [[
		"Returns a series at the next index."
		series	 [series!]
		return:  [series!]
	]
	#get-definition ACT_NEXT
]

pick: make action! [[
		"Returns the series value at a given index."
		series	 [series!]
		index 	 [integer! logic!]
		return:  [any-type!]
	]
	#get-definition ACT_PICK
]

poke: make action! [[
		"Replaces the series value at a given index, and returns the new value."
		series	 [series!]
		index 	 [integer! logic!]
		value 	 [any-type!]
		return:  [series!]
	]
	#get-definition ACT_POKE
]

remove: make action! [[
		"Removes the value, and returns the series, at the current series index."
		series	 [series! none!]
		/part "Removes multiple values, or values up to the given series index"
			length [number! series!]
		return:  [series! none!]
	]
	#get-definition ACT_REMOVE
]

;reverse

select: make action! [[
		"Find a value in a series and return the next value; NONE if value not found."
		series	 [series! none!]
		value 	 [any-type!]
		/part "Limit the length of the search"
			length [number! series!]
		/only "Treat a series search value as a single value"
		/case "Perform a case-sensitive search"
		/any  "TBD: Use * and ? wildcards in string searches"
		/with "TBD: Use custom wildcards in place of * and ?"
			wild [string!]
		/skip "Treat the series as fixed size records"
			size [integer!]
		/last "Find the last occurrence of value, from the tail"
		/reverse "Find the last occurrence of value, from the current index"
		return:  [any-type!]
	]
	#get-definition ACT_SELECT
]

;sort

skip: make action! [[
		"Returns the series relative to the current index."
		series	 [series!]
		offset 	 [integer!]
		return:  [series!]
	]
	#get-definition ACT_SKIP
]

;swap

tail: make action! [[
		"Returns a series at the index after its last value."
		series	 [series!]
		return:  [series!]
	]
	#get-definition ACT_TAIL
]

tail?: make action! [[
		"Returns true if a series is past its last value."
		series	 [series!]
		return:  [logic!]
	]
	#get-definition ACT_TAIL?
]

;take
;trim

;-- I/O actions --

;create
;close
;delete
;modify
;open
;open?
;query
;read
;rename
;update
;write

;------------------------------------------
;-				Natives					  -
;------------------------------------------

if: make native! [[
		"If condition is true, evaluate block; else return NONE."
		cond  	 [any-type!]
		then-blk [block!]
	]
	#get-definition NAT_IF
]

unless: make native! [[
		"If condition is not true, evaluate block; else return NONE."
		cond  	 [any-type!]
		then-blk [block!]
	]
	#get-definition NAT_UNLESS
]

either: make native! [[
		"If condition is true, eval true-block; else eval false-blk."
		cond  	  [any-type!]
		true-blk  [block!]
		false-blk [block!]
	]
	#get-definition NAT_EITHER
]

any: make native! [[
		"Evaluates conditions, returning at the first that is true."
		conds [block!]
	]
	#get-definition NAT_ANY
]

all: make native! [[
		"Evaluates conditions, returning at the first that is not true."
		conds [block!]
	]
	#get-definition NAT_ALL
]

while: make native! [[
		"Evaluates body until condition is true."
		cond [block!]
		body [block!]
	]
	#get-definition NAT_WHILE
]

until: make native! [[
		"Evaluates body until it is true."
		body [block!]
	]
	#get-definition NAT_UNTIL
]

loop: make native! [[
		"Evaluates body a number of times."
		count [integer!]
		body  [block!]
	]
	#get-definition NAT_LOOP
]

repeat: make native! [[
		"Evaluates body a number of times, tracking iteration count."
		'word [word!]    "Iteration counter; not local to loop"
		value [integer!] "Number of times to evaluate body"
		body  [block!]
	]
	#get-definition NAT_REPEAT
]

foreach: make native! [[
		"Evaluates body for each value in a series."
		'word  [word!]   "Word, or words, to set on each iteration"
		series [series!]
		body   [block!]
	]
	#get-definition NAT_FOREACH
]

forall: make native! [[
		"Evaluates body for all values in a series."
		'word [word!]   "Word referring to series to iterate over"
		body  [block!]
	]
	#get-definition NAT_FORALL
]

;break: make native! [
;	[]													;@@ add /return option
;	none
;]

func: make native! [[
		"Defines a function with a given specification and body to evaluate."
		spec [block!]
		body [block!]
	]
	#get-definition NAT_FUNC
]

function: make native! [[
		"Defines a function, making all words found in body local variables."
		spec [block!]
		body [block!]
		/extern	"Exclude words that follow this refinement"
	]
	#get-definition NAT_FUNCTION
]

does: make native! [[
		"Defines a function with no arguments or local variables."
		body [block!]
	]
	#get-definition NAT_DOES
]

has: make native! [[
		"Defines a function with local variables, but no arguments."
		vars [block!]
		body [block!]
	]
	#get-definition NAT_HAS
]

exit: make native! [[
		"Exits from a function, returning UNSET."
	]
	#get-definition NAT_EXIT
]

return: make native! [[
		"Exits from a function, returning the given value."
		value [any-type!]
	]
	#get-definition NAT_RETURN
]

switch: make native! [[
		"Evaluates the first block following the value found in cases."
		value [any-type!] "The value to match"
		cases [block!]
		/default "Specify a default block, if value is not found in cases"
			case [block!] "Default block to evaluate"
	]
	#get-definition NAT_SWITCH
]

case: make native! [[
		"Evaluates the block following the first true condition."
		cases [block!] "Block of condition-block pairs"
		/all "Test all conditions, evaluating the block following each true condition"
	]
	#get-definition NAT_CASE
]

do: make native! [[
		"Evaluates a value, returning the last evaluation result."
		value [any-type!]
	]
	#get-definition NAT_DO
]

reduce: make native! [[
		"Returns a copy of a block, evaluating all expressions."
		value [any-type!]
		/into "Put results in out block, instead of creating a new block"
			out [any-block!] "Target block for results, when /into is used"
	]
	#get-definition NAT_REDUCE
]

compose: make native! [[
		"Returns a copy of a block, evaluating only parens."
		value [block!]
		/deep "Compose nested blocks"
		/only "Compose nested blocks as blocks containing their values"
		/into "Put results in out block, instead of creating a new block"
			out [any-block!] "Target block for results, when /into is used"
	]
	#get-definition NAT_COMPOSE
]

get: make native! [[
		"Returns the value a word refers to."
		word	[word!]
		/any "If word has no value, return UNSET rather than causing an error"
		return: [any-type!]
	]
	#get-definition NAT_GET
]

set: make native! [[
		"Sets the value(s) one or more words refer to."
		word	[any-word! block!] "Word or block of words to set"
		value	[any-type!] "Value or block of values to assign to words"
		/any "If word has no value, return UNSET rather than causing an error"
		return: [any-type!]
	]
	#get-definition NAT_SET
]

print: make native! [[
		"Outputs a value followed by a newline."
		value	[any-type!]
	]
	#get-definition NAT_PRINT
]

prin: make native! [[
		"Outputs a value."
		value	[any-type!]
	]
	#get-definition NAT_PRIN
]

equal?: make native! [[
		"Returns true if two values are equal."
		value1 [any-type!]
		value2 [any-type!]
	]
	#get-definition NAT_EQUAL?
]

not-equal?: make native! [[
		"Returns true if two values are not equal."
		value1 [any-type!]
		value2 [any-type!]
	]
	#get-definition NAT_NOT_EQUAL?
]

strict-equal?: make native! [[
		"Returns true if two values are equal, and also the same datatype."
		value1 [any-type!]
		value2 [any-type!]
	]
	#get-definition NAT_STRICT_EQUAL?
]

lesser?: make native! [[
		"Returns true if the first value is less than the second."
		value1 [any-type!]
		value2 [any-type!]
	]
	#get-definition NAT_LESSER?
]

greater?: make native! [[
		"Returns true if the first value is greater than the second."
		value1 [any-type!]
		value2 [any-type!]
	]
	#get-definition NAT_GREATER?
]

lesser-or-equal?: make native! [[
		"Returns true if the first value is less than or equal to the second."
		value1 [any-type!]
		value2 [any-type!]
	]
	#get-definition NAT_LESSER_OR_EQUAL?
]

greater-or-equal?: make native! [[
		"Returns true if the first value is greater than or equal to the second."
		value1 [any-type!]
		value2 [any-type!]
	]
	#get-definition NAT_GREATER_OR_EQUAL?
]

same?: make native! [[
		"Returns true if two values have the same identity."
		value1 [any-type!]
		value2 [any-type!]
	]
	#get-definition NAT_SAME?
]

not: make native! [[
		"Returns the negation (logical complement) of a value."
		value [any-type!]
	]
	#get-definition NAT_NOT
]

halt: make native! [[
		"Stops evaluation."
	]
	#get-definition NAT_HALT
]

type?: make native! [[
		"Returns the datatype of a value."
		value [any-type!]
		/word "Return a word value, rather than a datatype value"
	]
	#get-definition NAT_TYPE?
]

load: make native! [[
		"Returns a value or block of values by reading and evaluating a source."
		source [file! url! string! binary! block!]
		/header "TBD: Include Red header as a loaded value"
		/all    "TBD: Don't evaluate Red header"
		/type [word! none!] "TBD:"
	]
	#get-definition NAT_LOAD
]

stats: make native! [[
		"Returns interpreter statistics."
		/show "TBD:"
		/info "Output formatted results"
		return: [integer! block!]
	]
	#get-definition NAT_STATS
]

;------------------------------------------
;-			   Operators				  -
;------------------------------------------

;-- #load temporary directive is used to workaround REBOL LOAD limitations on some words

#load set-word! "+"  make op! :add
#load set-word! "-"  make op! :subtract
#load set-word! "*"  make op! :multiply
#load set-word! "/"  make op! :divide
#load set-word! "="  make op! :equal?
#load set-word! "<>" make op! :not-equal?
#load set-word! "==" make op! :strict-equal?
#load set-word! "=?" make op! :same?
#load set-word! "<"  make op! :lesser?
#load set-word! ">"  make op! :greater?
#load set-word! "<=" make op! :lesser-or-equal?
#load set-word! ">=" make op! :greater-or-equal?

;------------------------------------------
;-				Scalars					  -
;------------------------------------------
Red: true												;-- ultimate Truth ;-) (pre-defines Red word)

yes: on: true
no: off: false
;empty?: :tail?

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

;------------------------------------------
;-			   Mezzanines				  -
;------------------------------------------

quit-return: routine [
	"Stops evaluation and exits the program with a given status."
	status			[integer!] "Process termination value to return"
][
	quit status
]
quit: func [
	"Stops evaluation and exits the program."
	/return status	[integer!] "Return an exit status"
][
	quit-return any [status 0]
]

empty?: func [
	"Returns true if a series is at its tail."
	series	[series!]
	return:	[logic!]
][
	tail? series
]

??: func [
	"Prints a word and the value it refers to (molded)."
	'value [word!]
][
	prin mold :value
	prin ": "
	probe get/any :value
]

probe: func [
	"Returns a value after printing its molded form."
	value
][
	print mold value
	value
]

first:	func ["Returns the first value in a series."  s [series!]] [pick s 1]	;@@ temporary definitions, should be natives ?
second:	func ["Returns the second value in a series." s [series!]] [pick s 2]
third:	func ["Returns the third value in a series."  s [series!]] [pick s 3]
fourth:	func ["Returns the fourth value in a series." s [series!]] [pick s 4]
fifth:	func ["Returns the fifth value in a series."  s [series!]] [pick s 5]

last:	func ["Returns the last value in a series."  s [series!]][pick back tail s 1]

action?:	 func ["Returns true if the value is this type." value [any-type!]] [action!	= type? value]
block?:		 func ["Returns true if the value is this type." value [any-type!]] [block!	= type? value]
char?: 		 func ["Returns true if the value is this type." value [any-type!]] [char!		= type? value]
datatype?:	 func ["Returns true if the value is this type." value [any-type!]] [datatype!	= type? value]
file?:		 func ["Returns true if the value is this type." value [any-type!]] [file!		= type? value]
function?:	 func ["Returns true if the value is this type." value [any-type!]] [function!	= type? value]
get-path?:	 func ["Returns true if the value is this type." value [any-type!]] [get-path!	= type? value]
get-word?:	 func ["Returns true if the value is this type." value [any-type!]] [get-word!	= type? value]
integer?:    func ["Returns true if the value is this type." value [any-type!]] [integer!	= type? value]
issue?:    	 func ["Returns true if the value is this type." value [any-type!]] [issue!	= type? value]
lit-path?:	 func ["Returns true if the value is this type." value [any-type!]] [lit-path!	= type? value]
lit-word?:	 func ["Returns true if the value is this type." value [any-type!]] [lit-word!	= type? value]
logic?:		 func ["Returns true if the value is this type." value [any-type!]] [logic!	= type? value]
native?:	 func ["Returns true if the value is this type." value [any-type!]] [native!	= type? value]
none?:		 func ["Returns true if the value is this type." value [any-type!]] [none!		= type? value]
op?:		 func ["Returns true if the value is this type." value [any-type!]] [op!		= type? value]
paren?:		 func ["Returns true if the value is this type." value [any-type!]] [paren!	= type? value]
path?:		 func ["Returns true if the value is this type." value [any-type!]] [path!		= type? value]
refinement?: func ["Returns true if the value is this type." value [any-type!]] [refinement! = type? value]
set-path?:	 func ["Returns true if the value is this type." value [any-type!]] [set-path!	= type? value]
set-word?:	 func ["Returns true if the value is this type." value [any-type!]] [set-word!	= type? value]
string?:	 func ["Returns true if the value is this type." value [any-type!]] [string!	= type? value]
unset?:		 func ["Returns true if the value is this type." value [any-type!]] [unset!	= type? value]
word?:		 func ["Returns true if the value is this type." value [any-type!]] [word!		= type? value]

spec-of: func [
	"Returns the spec of the value, for types that support reflection."
	value
][
	reflect :value 'spec
]
body-of: func [
	"Returns the body of the value, for types that support reflection."
	value
][
	reflect :value 'body
]

system: function [
	"Returns information about the interpreter."
	/version	"Return the system version"
	/words		"Return a block of global words available"
	/platform	"Return a word identifying the operating system"
][
	case [
		version [#version]
		words	[#system [_context/get-words]]
		platform [
			#system [
				#switch OS [
					Windows  [SET_RETURN(words/_windows)]
					Syllable [SET_RETURN(words/_syllable)]
					MacOSX	 [SET_RETURN(words/_macosx)]
					#default [SET_RETURN(words/_linux)]
				]
			]
		]
		'else [
			print "Please specify a system refinement value (/version, /words, or /platform)."
		]
	]
]

Red [
	Title:   "Red base environment definitions"
	Author:  "Nenad Rakocevic"
	File: 	 %boot.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
	}
]

;-- datatype! is not defined here for obvious circular reference issue

unset!:			make datatype! #get-definition TYPE_UNSET
none!:			make datatype! #get-definition TYPE_NONE
logic!:			make datatype! #get-definition TYPE_LOGIC
block!:			make datatype! #get-definition TYPE_BLOCK
string!:		make datatype! #get-definition TYPE_STRING
integer!:		make datatype! #get-definition TYPE_INTEGER
;symbol!:		make datatype! #get-definition TYPE_SYMBOL
;context!:		make datatype! #get-definition TYPE_CONTEXT
word!:			make datatype! #get-definition TYPE_WORD
error!:			make datatype! #get-definition TYPE_ERROR
typeset!:		make datatype! #get-definition TYPE_TYPESET
file!:			make datatype! #get-definition TYPE_FILE

set-word!:		make datatype! #get-definition TYPE_SET_WORD
get-word!:		make datatype! #get-definition TYPE_GET_WORD
lit-word!:		make datatype! #get-definition TYPE_LIT_WORD
refinement!:	make datatype! #get-definition TYPE_REFINEMENT
binary!:		make datatype! #get-definition TYPE_BINARY
paren!:			make datatype! #get-definition TYPE_PAREN
char!:			make datatype! #get-definition TYPE_CHAR
issue!:			make datatype! #get-definition TYPE_ISSUE
path!:			make datatype! #get-definition TYPE_PATH
set-path!:		make datatype! #get-definition TYPE_SET_PATH
get-path!:		make datatype! #get-definition TYPE_GET_PATH
lit-path!:		make datatype! #get-definition TYPE_LIT_PATH
native!:		make datatype! #get-definition TYPE_NATIVE
action!:		make datatype! #get-definition TYPE_ACTION
op!:			make datatype! #get-definition TYPE_OP
function!:		make datatype! #get-definition TYPE_FUNCTION
closure!:		make datatype! #get-definition TYPE_CLOSURE
routine!:		make datatype! #get-definition TYPE_ROUTINE
object!:		make datatype! #get-definition TYPE_OBJECT
port!:			make datatype! #get-definition TYPE_PORT
bitset!:		make datatype! #get-definition TYPE_BITSET
float!:			make datatype! #get-definition TYPE_FLOAT

none:  			make none! 0
true:  			make logic! 1
false: 			make logic! 0

;------------------------------------------
;-				Actions					  -
;------------------------------------------

make: make action! [[									;--	this one works!	;-)
		"Returns a new value made from a specification for that value's type."
		type	 [any-type!] "The datatype or a prototype value."
		spec	 [any-type!] "The specification	of the new value."
		return:  [any-type!] "Returns the specified datatype."
	]
	#get-definition ACT_MAKE
]

;random

reflect: make action! [[
		"Returns internal details about a value via reflection."
		value	[any-type!]
		field 	[word!] "spec, body, words, etc. Each datatype defines its own reflectors"
	]
	#get-definition ACT_REFLECT
]

;to

form: make action! [[
		"Returns a user-friendly string representation of a value."
		value	  [any-type!]
		/part "Limit the length of the result"
			limit [integer!]
		return:	  [string!]
	]
	#get-definition ACT_FORM
]

mold: make action! [[
		"Returns a source format string representation of a value."
		value	  [any-type!]
		/only "Exclude outer brackets if value is a block"
		/all  "TBD: Return value in loadable format"
		/flat "TBD: Exclude all indentation"
		/part "Limit the length of the result"
			limit [integer!]
		return:	  [string!]
	]
	#get-definition ACT_MOLD
]

;-- Scalar actions --

absolute: make action! [[
		"Returns the non-negative value."
		value	 [number!]
		return:  [number!]
	]
	#get-definition ACT_ABSOLUTE
]

add: make action! [[
		"Returns the sum of the two values."
		value1	 [number!]
		value2	 [number!]
		return:  [number!]
	]
	#get-definition ACT_ADD
]

divide: make action! [[
		"Returns the quotient of two values."
		value1	 [number!] "The dividend (numerator)."
		value2	 [number!] "The divisor (denominator)."
		return:  [number!]
	]
	#get-definition ACT_DIVIDE
]

multiply: make action! [[
		"Returns the product of two values."
		value1	 [number!]
		value2	 [number!]
		return:  [number!]
	]
	#get-definition ACT_MULTIPLY
]

negate: make action! [[
		"Returns the inverse value."
		number 	 [number!]
		return:  [number!]
	]
	#get-definition ACT_NEGATE
]

power: make action! [[
		"Returns a number raised to a given power (exponent)."
		number	 [number!] "Base value."
		exponent [number!] "The power (index) to raise the base value by."
		return:	 [number!]
	]
	#get-definition ACT_POWER
]

remainder: make action! [[
		"Returns what is left over when one value is divided by another."
		value1 	 [number!]
		value2 	 [number!]
		return:  [number!]
	]
	#get-definition ACT_REMAINDER
]

round: make action! [[
		"TBD: Returns the nearest integer. Halves round up (away from zero) by default."
		n		[number!]
		/to		"Return the nearest multiple of the scale parameter"
		scale	[number!] "Must be a non-zero value"
		/even		"Halves round toward even results"
		/down		"Round toward zero, ignoring discarded digits. (truncate)"
		/half-down	"Halves round toward zero"
		/floor		"Round in negative direction"
		/ceiling	"Round in positive direction"
		/half-ceiling "Halves round in positive direction"
	]
	#get-definition ACT_ROUND
]

subtract: make action! [[
		"Returns the difference between two values."
		value1	 [number!]
		value2	 [number!]
		return:  [number!]
	]
	#get-definition ACT_SUBTRACT
]

even?: make action! [[
		"Returns true if the number is evenly divisible by 2."
		number 	 [number!]
		return:  [number!]
	]
	#get-definition ACT_EVEN?
]

odd?: make action! [[
		"Returns true if the number has a remainder of 1 when divided by 2."
		number 	 [number!]
		return:  [number!]
	]
	#get-definition ACT_ODD?
]

;-- Bitwise actions --

;and~
;complement
;or~
;xor~

;-- Series actions --

append: make action! [[
		"Inserts value(s) at series tail; returns series head."
		series	   [series!]
		value	   [any-type!]
		/part "Limit the number of values inserted"
			length [number! series!]
		/only "Insert block types as single values (overrides /part)"
		/dup  "Duplicate the inserted values"
			count  [number!]
		return:    [series!]
	]
	#get-definition ACT_APPEND
]

at: make action! [[
		"Returns a series at a given index."
		series	 [series!]
		index 	 [integer!]
		return:  [series!]
	]
	#get-definition ACT_AT
]

back: make action! [[
		"Returns a series at the previous index."
		series	 [series!]
		return:  [series!]
	]
	#get-definition ACT_BACK
]

;change

clear: make action! [[
		"Removes series values from current index to tail; returns new tail."
		series	 [series!]
		return:  [series!]
	]
	#get-definition ACT_CLEAR
]

copy: make action! [[
		"Returns a copy of a non-scalar value."
		value	 [series!]
		/part	 "Limit the length of the result"
			length [number! series!]
		/deep	 "Copy nested values"
		/types	 "Copy only specific types of non-scalar values"
			kind [datatype!]
		return:  [series!]
	]
	#get-definition ACT_COPY
]

find: make action! [[
		"Returns the series where a value is found; NONE if value is not found."
		series	 [series! none!]
		value 	 [any-type!]
		/part "Limit the length of the search"
			length [number! series!]
		/only "Treat a series search value as a single value"
		/case "Perform a case-sensitive search"
		/any  "TBD: Use * and ? wildcards in string searches"
		/with "TBD: Use custom wildcards in place of * and ?"
			wild [string!]
		/skip "Treat the series as fixed size records"
			size [integer!]
		/last "Find the last occurrence of value, from the tail"
		/reverse "Find the last occurrence of value, from the current index"
		/tail "Return the tail of the match found, rather than the head"
		/match "Match at current index only and return tail of match"
	]
	#get-definition ACT_FIND
]

head: make action! [[
		"Returns a series at its first index."
		series	 [series!]
		return:  [series!]
	]
	#get-definition ACT_HEAD
]

head?: make action! [[
		"Returns true if a series is at its first index."
		series	 [series!]
		return:  [logic!]
	]
	#get-definition ACT_HEAD?
]

index?: make action! [[
		"Returns the current series index, relative to the head."
		series	 [series!]
		return:  [integer!]
	]
	#get-definition ACT_INDEX?
]

;insert

length?: make action! [[
		"Returns the number of values in the series, from the current index to the tail."
		series	 [series!]
		return:  [integer!]
	]
	#get-definition ACT_LENGTH?
]

next: make action! [[
		"Returns a series at the next index."
		series	 [series!]
		return:  [series!]
	]
	#get-definition ACT_NEXT
]

pick: make action! [[
		"Returns the series value at a given index."
		series	 [series!]
		index 	 [integer! logic!]
		return:  [any-type!]
	]
	#get-definition ACT_PICK
]

poke: make action! [[
		"Replaces the series value at a given index, and returns the new value."
		series	 [series!]
		index 	 [integer! logic!]
		value 	 [any-type!]
		return:  [series!]
	]
	#get-definition ACT_POKE
]

remove: make action! [[
		"Removes the value, and returns the series, at the current series index."
		series	 [series! none!]
		/part "Removes multiple values, or values up to the given series index"
			length [number! series!]
		return:  [series! none!]
	]
	#get-definition ACT_REMOVE
]

;reverse

select: make action! [[
		"Find a value in a series and return the next value; NONE if value not found."
		series	 [series! none!]
		value 	 [any-type!]
		/part "Limit the length of the search"
			length [number! series!]
		/only "Treat a series search value as a single value"
		/case "Perform a case-sensitive search"
		/any  "TBD: Use * and ? wildcards in string searches"
		/with "TBD: Use custom wildcards in place of * and ?"
			wild [string!]
		/skip "Treat the series as fixed size records"
			size [integer!]
		/last "Find the last occurrence of value, from the tail"
		/reverse "Find the last occurrence of value, from the current index"
		return:  [any-type!]
	]
	#get-definition ACT_SELECT
]

;sort

skip: make action! [[
		"Returns the series relative to the current index."
		series	 [series!]
		offset 	 [integer!]
		return:  [series!]
	]
	#get-definition ACT_SKIP
]

;swap

tail: make action! [[
		"Returns a series at the index after its last value."
		series	 [series!]
		return:  [series!]
	]
	#get-definition ACT_TAIL
]

tail?: make action! [[
		"Returns true if a series is past its last value."
		series	 [series!]
		return:  [logic!]
	]
	#get-definition ACT_TAIL?
]

;take
;trim

;-- I/O actions --

;create
;close
;delete
;modify
;open
;open?
;query
;read
;rename
;update
;write

;------------------------------------------
;-				Natives					  -
;------------------------------------------

if: make native! [[
		"If condition is true, evaluate block; else return NONE."
		cond  	 [any-type!]
		then-blk [block!]
	]
	#get-definition NAT_IF
]

unless: make native! [[
		"If condition is not true, evaluate block; else return NONE."
		cond  	 [any-type!]
		then-blk [block!]
	]
	#get-definition NAT_UNLESS
]

either: make native! [[
		"If condition is true, eval true-block; else eval false-blk."
		cond  	  [any-type!]
		true-blk  [block!]
		false-blk [block!]
	]
	#get-definition NAT_EITHER
]

any: make native! [[
		"Evaluates conditions, returning at the first that is true."
		conds [block!]
	]
	#get-definition NAT_ANY
]

all: make native! [[
		"Evaluates conditions, returning at the first that is not true."
		conds [block!]
	]
	#get-definition NAT_ALL
]

while: make native! [[
		"Evaluates body until condition is true."
		cond [block!]
		body [block!]
	]
	#get-definition NAT_WHILE
]

until: make native! [[
		"Evaluates body until it is true."
		body [block!]
	]
	#get-definition NAT_UNTIL
]

loop: make native! [[
		"Evaluates body a number of times."
		count [integer!]
		body  [block!]
	]
	#get-definition NAT_LOOP
]

repeat: make native! [[
		"Evaluates body a number of times, tracking iteration count."
		'word [word!]    "Iteration counter; not local to loop"
		value [integer!] "Number of times to evaluate body"
		body  [block!]
	]
	#get-definition NAT_REPEAT
]

foreach: make native! [[
		"Evaluates body for each value in a series."
		'word  [word!]   "Word, or words, to set on each iteration"
		series [series!]
		body   [block!]
	]
	#get-definition NAT_FOREACH
]

forall: make native! [[
		"Evaluates body for all values in a series."
		'word [word!]   "Word referring to series to iterate over"
		body  [block!]
	]
	#get-definition NAT_FORALL
]

;break: make native! [
;	[]													;@@ add /return option
;	none
;]

func: make native! [[
		"Defines a function with a given specification and body to evaluate."
		spec [block!]
		body [block!]
	]
	#get-definition NAT_FUNC
]

function: make native! [[
		"Defines a function, making all words found in body local variables."
		spec [block!]
		body [block!]
	]
	#get-definition NAT_FUNCTION
]

does: make native! [[
		"Defines a function with no arguments or local variables."
		body [block!]
	]
	#get-definition NAT_DOES
]

has: make native! [[
		"Defines a function with local variables, but no arguments."
		vars [block!]
		body [block!]
	]
	#get-definition NAT_HAS
]

exit: make native! [[
		"Exits from a function, returning UNSET."
	]
	#get-definition NAT_EXIT
]

return: make native! [[
		"Exits from a function, returning the given value."
		value [any-type!]
	]
	#get-definition NAT_RETURN
]

switch: make native! [[
		"Evaluates the first block following the value found in cases."
		value [any-type!] "The value to match"
		cases [block!]
		/default "Specify a default block, if value is not found in cases"
			case [block!] "Default block to evaluate"
	]
	#get-definition NAT_SWITCH
]

case: make native! [[
		"Evaluates the block following the first true condition."
		cases [block!] "Block of condition-block pairs"
		/all "Test all conditions, evaluating the block following each true condition"
	]
	#get-definition NAT_CASE
]

do: make native! [[
		"Evaluates a value, returning the last evaluation result."
		value [any-type!]
	]
	#get-definition NAT_DO
]

reduce: make native! [[
		"Returns a copy of a block, evaluating all expressions."
		value [any-type!]
		/into "Put results in out block, instead of creating a new block"
			out [any-block!] "Target block for results, when /into is used"
	]
	#get-definition NAT_REDUCE
]

compose: make native! [[
		"Returns a copy of a block, evaluating only parens."
		value [block!]
		/deep "Compose nested blocks"
		/only "Compose nested blocks as blocks containing their values"
		/into "Put results in out block, instead of creating a new block"
			out [any-block!] "Target block for results, when /into is used"
	]
	#get-definition NAT_COMPOSE
]

get: make native! [[
		"Returns the value a word refers to."
		word	[word!]
		/any "If word has no value, return UNSET rather than causing an error"
		return: [any-type!]
	]
	#get-definition NAT_GET
]

set: make native! [[
		"Sets the value(s) one or more words refer to."
		word	[any-word! block!] "Word or block of words to set"
		value	[any-type!] "Value or block of values to assign to words"
		/any "If word has no value, return UNSET rather than causing an error"
		return: [any-type!]
	]
	#get-definition NAT_SET
]

print: make native! [[
		"Outputs a value followed by a newline."
		value	[any-type!]
	]
	#get-definition NAT_PRINT
]

prin: make native! [[
		"Outputs a value."
		value	[any-type!]
	]
	#get-definition NAT_PRIN
]

equal?: make native! [[
		"Returns true if two values are equal."
		value1 [any-type!]
		value2 [any-type!]
	]
	#get-definition NAT_EQUAL?
]

not-equal?: make native! [[
		"Returns true if two values are not equal."
		value1 [any-type!]
		value2 [any-type!]
	]
	#get-definition NAT_NOT_EQUAL?
]

strict-equal?: make native! [[
		"Returns true if two values are equal, and also the same datatype."
		value1 [any-type!]
		value2 [any-type!]
	]
	#get-definition NAT_STRICT_EQUAL?
]

lesser?: make native! [[
		"Returns true if the first value is less than the second."
		value1 [any-type!]
		value2 [any-type!]
	]
	#get-definition NAT_LESSER?
]

greater?: make native! [[
		"Returns true if the first value is greater than the second."
		value1 [any-type!]
		value2 [any-type!]
	]
	#get-definition NAT_GREATER?
]

lesser-or-equal?: make native! [[
		"Returns true if the first value is less than or equal to the second."
		value1 [any-type!]
		value2 [any-type!]
	]
	#get-definition NAT_LESSER_OR_EQUAL?
]

greater-or-equal?: make native! [[
		"Returns true if the first value is greater than or equal to the second."
		value1 [any-type!]
		value2 [any-type!]
	]
	#get-definition NAT_GREATER_OR_EQUAL?
]

same?: make native! [[
		"Returns true if two values have the same identity."
		value1 [any-type!]
		value2 [any-type!]
	]
	#get-definition NAT_SAME?
]

not: make native! [[
		"Returns the negation (logical complement) of a value."
		value [any-type!]
	]
	#get-definition NAT_NOT
]

halt: make native! [[
		"Stops evaluation."
	]
	#get-definition NAT_HALT
]

type?: make native! [[
		"Returns the datatype of a value."
		value [any-type!]
		/word "Return a word value, rather than a datatype value"
	]
	#get-definition NAT_TYPE?
]

load: make native! [[
		"Returns a value or block of values by reading and evaluating a source."
		source [file! url! string! binary! block!]
		/header "TBD: Include Red header as a loaded value"
		/all    "TBD: Don't evaluate Red header"
		/type [word! none!] "TBD:"
	]
	#get-definition NAT_LOAD
]

stats: make native! [[
		"Returns interpreter statistics."
		/show "TBD:"
		/info "Output formatted results"
		return: [integer! block!]
	]
	#get-definition NAT_STATS
]

;------------------------------------------
;-			   Operators				  -
;------------------------------------------

;-- #load temporary directive is used to workaround REBOL LOAD limitations on some words

#load set-word! "+"  make op! :add
#load set-word! "-"  make op! :subtract
#load set-word! "*"  make op! :multiply
#load set-word! "/"  make op! :divide
#load set-word! "="  make op! :equal?
#load set-word! "<>" make op! :not-equal?
#load set-word! "==" make op! :strict-equal?
#load set-word! "=?" make op! :same?
#load set-word! "<"  make op! :lesser?
#load set-word! ">"  make op! :greater?
#load set-word! "<=" make op! :lesser-or-equal?
#load set-word! ">=" make op! :greater-or-equal?

;------------------------------------------
;-				Scalars					  -
;------------------------------------------
Red: true												;-- ultimate Truth ;-) (pre-defines Red word)

yes: on: true
no: off: false
;empty?: :tail?

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

;------------------------------------------
;-			   Mezzanines				  -
;------------------------------------------

quit-return: routine [
	"Stops evaluation and exits the program with a given status."
	status			[integer!] "Process termination value to return"
][
	quit status
]
quit: func [
	"Stops evaluation and exits the program."
	/return status	[integer!] "Return an exit status"
][
	quit-return any [status 0]
]

empty?: func [
	"Returns true if a series is at its tail."
	series	[series!]
	return:	[logic!]
][
	tail? series
]

??: func [
	"Prints a word and the value it refers to (molded)."
	'value [word!]
][
	prin mold :value
	prin ": "
	probe get/any :value
]

probe: func [
	"Returns a value after printing its molded form."
	value
][
	print mold value
	value
]

first:	func ["Returns the first value in a series."  s [series!]] [pick s 1]	;@@ temporary definitions, should be natives ?
second:	func ["Returns the second value in a series." s [series!]] [pick s 2]
third:	func ["Returns the third value in a series."  s [series!]] [pick s 3]
fourth:	func ["Returns the fourth value in a series." s [series!]] [pick s 4]
fifth:	func ["Returns the fifth value in a series."  s [series!]] [pick s 5]

last:	func ["Returns the last value in a series."  s [series!]][pick back tail s 1]

action?:	 func ["Returns true if the value is this type." value [any-type!]] [action!	= type? value]
block?:		 func ["Returns true if the value is this type." value [any-type!]] [block!	= type? value]
char?: 		 func ["Returns true if the value is this type." value [any-type!]] [char!		= type? value]
datatype?:	 func ["Returns true if the value is this type." value [any-type!]] [datatype!	= type? value]
file?:		 func ["Returns true if the value is this type." value [any-type!]] [file!		= type? value]
function?:	 func ["Returns true if the value is this type." value [any-type!]] [function!	= type? value]
get-path?:	 func ["Returns true if the value is this type." value [any-type!]] [get-path!	= type? value]
get-word?:	 func ["Returns true if the value is this type." value [any-type!]] [get-word!	= type? value]
integer?:    func ["Returns true if the value is this type." value [any-type!]] [integer!	= type? value]
issue?:    	 func ["Returns true if the value is this type." value [any-type!]] [issue!	= type? value]
lit-path?:	 func ["Returns true if the value is this type." value [any-type!]] [lit-path!	= type? value]
lit-word?:	 func ["Returns true if the value is this type." value [any-type!]] [lit-word!	= type? value]
logic?:		 func ["Returns true if the value is this type." value [any-type!]] [logic!	= type? value]
native?:	 func ["Returns true if the value is this type." value [any-type!]] [native!	= type? value]
none?:		 func ["Returns true if the value is this type." value [any-type!]] [none!		= type? value]
op?:		 func ["Returns true if the value is this type." value [any-type!]] [op!		= type? value]
paren?:		 func ["Returns true if the value is this type." value [any-type!]] [paren!	= type? value]
path?:		 func ["Returns true if the value is this type." value [any-type!]] [path!		= type? value]
refinement?: func ["Returns true if the value is this type." value [any-type!]] [refinement! = type? value]
set-path?:	 func ["Returns true if the value is this type." value [any-type!]] [set-path!	= type? value]
set-word?:	 func ["Returns true if the value is this type." value [any-type!]] [set-word!	= type? value]
string?:	 func ["Returns true if the value is this type." value [any-type!]] [string!	= type? value]
unset?:		 func ["Returns true if the value is this type." value [any-type!]] [unset!	= type? value]
word?:		 func ["Returns true if the value is this type." value [any-type!]] [word!		= type? value]

spec-of: func [
	"Returns the spec of the value, for types that support reflection."
	value
][
	reflect :value 'spec
]
body-of: func [
	"Returns the body of the value, for types that support reflection."
	value
][
	reflect :value 'body
]

system: function [
	"Returns information about the interpreter."
	/version	"Return the system version"
	/words		"Return a block of global words available"
	/platform	"Return a word identifying the operating system"
][
	case [
		version [#version]
		words	[#system [_context/get-words]]
		platform [
			#system [
				#switch OS [
					Windows  [SET_RETURN(words/_windows)]
					Syllable [SET_RETURN(words/_syllable)]
					MacOSX	 [SET_RETURN(words/_macosx)]
					#default [SET_RETURN(words/_linux)]
				]
			]
		]
		'else [
			print "Please specify a system refinement value (/version, /words, or /platform)."
		]
	]
]


Misspelling of CC_BUILD_ARTIFACTS in manual

h1. Manual

This is the CruiseControl.rb manual. If you can't find what you're looking for here, make sure to look at the docs
for "plugins":/documentation/plugins or just "contact us":/documentation/contact_us.

h1. Table of Contents

* Files and folders
* Site configuration
* Project builder configuration
* Default build tasks
* Changing the build command
* Handling custom build artifacts
* Build scheduling
* Deleting a project
* Build chaining & triggers
* Environment variables
* Remote builds
* Performing a clean checkout
* Troubleshooting and support

h1(#files_and_folders). Files and folders

* *$cruise* is how this documentation refers the directory where CC.rb itself has been unpacked or checked out.

* CC.rb places all of its project, plugin, and configuration data in $HOME/.cruise (%USERPROFILE%\.cruise on Windows).
  This documentation refers to this directory as *$cruise_data*.

* *$cruise_data*/projects/your_project/ is the directory where CC.rb will place the data for the project called "your_project".

* *$cruise_data*/projects/your_project/work/ is a local copy of your_project's source code. Builder keeps it up to date
  with the source control repository and runs builds against it.

* *$cruise_data*/projects/your_project/build-123/ contains a build status file, a list of changed files,
  and other "build artifacts" created while building revision 123.

* *$cruise_data*/projects/your_project/cruise_config.rb contains the build configuration for your_project.

* *$cruise_data*/config/site_config.rb is the file where you can make centralized changes to the configuration of the dashboard
  and all builders.

h1(#site_configuration). Site configuration

p. The CruiseControl.rb package includes a file called *$cruise*/config/site_config.rb.example. By copying it to
*$cruise*/config/site_config.rb and uncommenting some lines you can set a number of global configuration settings.
Normally you would only need to do this to configure an SMTP server for email notices. Email is configured using Rails'
ActionMailer component and accepts its standard configuration settings.

h1(#project_builder_configuration). Project builder configuration

If you don't provide a Cruise configuration for your project, CC.rb will try to make some reasonable guesses about how
to build your project, particularly if it's a Ruby application. (See Default build tasks below.)

However, there are only a few configuration settings that CC.rb can guess at. Specific projects will require more advanced configuration
if you need to add email notification recipients, configure plugins, or otherwise tweak your build run. A typical project configuration
in CC.rb is about 3 to 5 lines of very simple Ruby.

When you first add a project, a configuration file called cruise_config.rb is created for you in the
*$cruise_data*/projects/your_project/ directory. It contains a number of comments, but two lines are important:

  Project.configure do |project|
  end

Every cruise_config.rb must have these two lines, and all your other configuration goes between them. It's recommended that you check
this file into version control, and if you do then changes made to the configuration will be automatically be picked up by CC.rb the
next time you check in without any additional work required.

Optionally, you can put a configuration file in both places above. CruiseControl.rb loads both files, but settings from the
cruise_config.rb in *$cruise_data*/projects/your_project/ override those stored in your project's root directory.
This can be useful when you want to see the effect of some configuration settings without checking them in, or have some
location-dependent settings.

p(hint). Hint: configuration examples below include lines like '...'. This represents other
         configuration statements that may be in cruise_config.rb. You are not meant to copy-paste those dots into
         your configuration file, as they are not valid Ruby. If you do, ./cruise start will fail to start
         due to a syntax error.

Since configuration files are written in a real programming language (Ruby), you can modularize them, use
logical statements, and generally do whatever makes sense. For example, consider the following snippet:

  Project.configure do |project|
    case project.name
    when 'MyProject.Quick' then project.rake_task = 'test:units'
    when 'MyProject.BigBertha' then project.rake_task = 'cruise:all_tests'
    else raise "Don't know what to build for project #{project.name.inspect}"
    end
  end

p(hint). Hint: Use code like above to source-control configuration of multiple CruiseControl.rb projects building the same codebase.

h1(#default_build_tasks). Default build tasks

By default, CC.rb will assume that you are building a Ruby project, load your Rakefile, and look for the cruise,
test, and default (what happens when you just type rake with no arguments) tasks,
in that order, and execute the first one it finds.

Note that Rails provides you with an automatic test task when you first create your project. The behavior
for that task is documented here.

p(hint). WARNING: with Rails projects, it is important that RAILS_ENV does not default to 'production'.
         Unless you want your migration scripts and unit tests to hit your production database, of course.
         CruiseControl.reb leaves this variable unchanged when invoking 'cruise' or other custom Rake task, and sets
         it to 'test' before invoking the defaults.

h1(#changing_the_build_command). Changing the build command or Rake task

cruise may be the task for a quick build, but you may also want to run a long build with all acceptance
tests included. This can be done by assigning the project.rake_task attribute in cruise_config.rb:

  Project.configure do |project|
    ...
    project.rake_task = 'big_bertha_build'
    ...
  end

p(hint). Hint: Be careful when defining additional build tasks. If two builds share the same RAILS_ENV value
         then they will operate against the same database, which means that if two builds run simultaneously there is
         a chance that they will interfere with each other. You can avoid this issue this by creating a separate environment
         and making sure that the Rake task for your build sets the RAILS_ENV value to that environment in your
         Rake task. Copy config/environments/test.rb to config/environments/big_bertha.rb, add a :big_bertha_init
         Rake task with ENV['RAILS_ENV'] = 'big_bertha' in it, and put it in the beginning of
         :big_bertha_build list of depenedencies.

p(hint). Hint: Ideally, you'd also want some way to chain builds so that the long build for a new checkin is only
         launched once the short build has finished succesfully. CruiseControl.rb provides support for this option through
         the triggered_by project build configuration feature; see
         Build Chaining & Triggers.

CC.rb may be written in Ruby on Rails, but you don't need to be using Ruby and Rake in order to take advantage of it.
Other build tools like "make":http://www.gnu.org/software/make/,
"Ant":http://ant.apache.org/ and "MSBuild":http://msdn2.microsoft.com/en-us/library/wea2sca5.aspx are also supported--
really, any command that can return a success or failure status code.

A custom build command can be set with the project.build_command attribute. Modify cruise_config.rb file like
this:

  Project.configure do |project|
    ...
    project.build_command = 'my_build_script.sh'
    ...
  end

If project.build_command is set, CC.rb will invoke the specified command from the project's work directory
(*$cruise_data*/projects/your_project/work/) and examine the exit code to determine whether the
build passed or failed.

p(hint). Hint: You cannot set both the rake_task and build_command attributes in a a given project configuration.

h1(#handling_custom_build_artifacts). What should I do with custom build artifacts?

Some build tasks generate custom output, like test coverage statistics, that you may want to keep and see on the build page.
CruiseControl.rb supports the integration of that output by setting the CC_BUILD_ARTIFACTS environment variable
to a directory that's been set aside specifically to collect them.

If you ensure that your special task writes its output to that directory or a subdirectory of it, then the resulting build artifacts page will automatically include links to every file or subdirectory found in the build artifacts directory.

p(hint). Hint: Code coverage analysis is a good example of custom build output. CruiseControl.rb's own build uses
         "rcov":http://eigenclass.org/hiki.rb. If you drill down into a recent CC.rb build on
         "http://cruisecontrolrb.thoughtworks.com":http://cruisecontrolrb.thoughtworks.com, you can see links
         to test coverage reports.

p(hint). Hint: The "metric_fu":http://github.com/jscruggs/metric_fu/tree/master project collects a number of
         helpful Ruby code metrics into a single, easy-to-configure plugin and integrates well with CC.rb.

h1(#build_scheduling). Build scheduling

By default, the builder polls Subversion every 10 seconds for new revisions. This can be changed by adding the
following line to cruise_config.rb:

  Project.configure do |project|
    ...
    project.scheduler.polling_interval = 5.minutes
    ...
  end

What if you want a scheduler with some interesting logic? Well, a default scheduler can be substituted by placing
your own scheduler implementation into the plugins directory and configuring it as follows:

  Project.configure do |project|
    ...
    project.scheduler = MyCustomScheduler.new(project)
    ...
  end

After initializing everything, and loading the project (this step includes evaluation of cruise_config.rb), the
builder invokes project.scheduler.run. A builder must be able to detect when its configuration has changed, or when a
build is requested by user (by pressing the Build Now button), so a custom scheduler needs to know how to recognize that situation.

Look at *$cruise*/app/models/polling_scheduler.rb to understand how a scheduler interacts with a project.

h1(#deleting_a_project). Deleting a project

To remove your_project from CruiseControl.rb, kill its builder process and then delete the *$cruise_data*/projects/your_project/
directory.

h1(#build_chaining_and_triggers). Build chaining & triggers

CC.rb uses triggers to tell it when to build a project.  Every project is configured, by default, with a ChangeInSourceControl trigger: it builds
when (surprise) it detects a change in a project's source control.

However, you can add additional triggers or replace a trigger entirely.  For example, you can have one project's successful build trigger another project's build with our SuccessfulBuildTrigger.

  project.triggered_by SuccessfulBuildTrigger.new(project, 'indie')

or, in short hand:

  project.triggered_by 'indie'

Why would you want one build to trigger another?  In this instance, maybe our project depends on indie and we want to know if a change to indie breaks our project.

These examples, *added* a SuccessfulBuildTrigger.  We could also *replace* the default trigger by writing

  project.triggered_by = [SuccessfulBuildTrigger.new(project, "fast_build")]

Why wouldn't we want our project to be triggered by a change to it's source code?  In this case, maybe we've separated our project into a fast and slow build.  We could use this to only trigger a slow build if the fast one passes.

h1(#environment_variables). Environment variables

CC.rb can set any custom environment variables that your build requires.  Every project can be configured to build with different environment variables.  For example:

  Project.configure do |project|
    project.environment['DB_HOST'] = 'db.example.com'
    project.environment['DB_PORT'] = '1234'
  end

h2(#ccrb_environment_variables). Special environment variables

CC.rb sets some environment variables when it runs your build, and you can use them inside your build process to tweak it or its output. Currently
there are just three:
* CC_BUILD_REVISION - this is the revision number of the current build, it looks like "5" or "56236"
* CC_BUILD_LABEL - usually this is the same as CC_BUILD_REVISION, but if there is more than one build of a particular revision, it will have a ".n" after it, so it might look like "323", "323.2", "4236.20", etc.
* CC_BUILD_ARTIFACTS - this is the directory which the dashboard looks in.  Any files you copy into here will be available from the dashboard.

h1(#remote_builds). Remote builds

CC.rb can run builds on remote servers.  This is done by sshing to the server in your build command.  For example:

  project.build_command = 'ssh user@server ./run_remotely.sh $CC_BUILD_REVISION'

run_remotely.sh might look something like:

  #/bin/bash
  svn up -r$1
  rake test:integration

Of course you will need to checkout the code on the remote server before running the first build.

Note that CC.rb will still maintain a checkout of the code on the local server, use it to check for modifications and store build results locally.
More robust support for builders on remote servers is expected in release 2.0.

h1(#performing_a_clean_checkout). Performing a clean checkout for each build

CC.rb supports clean checkouts, though they are not the default behavior.  To enable them, you must use the do_clean_checkout
flag together with an optional frequency. Acceptable values are :always, :never, and :every => [duration].

  project.do_clean_checkout :every => 6.hours

h1(#troubleshooting_and_support). Troubleshooting and support

If you have an issue that you cannot fix on your own, please consider subscribing to our mailing list at cruisecontrolrb-users@rubyforge.org
and asking for help. Please note, though, that we take great pains to make CC.rb easy to hack, and we encourage you to poke around in the
source code and hack away.

Should you require commercial support, training or consulting around this or other tool, "ThoughtWorks":http://thoughtworks.com/ can
provide it to you. We also offer a commercial CI product, "Cruise":http://studios.thoughtworks.com/cruise-continuous-integration, through
ThoughtWorks Studios, our product division.

p(hint). Hint to would-be contributors: documentation patches are as important, if not more so, than code patches, and would be
         gratefully accepted.

h1. Manual

This is the CruiseControl.rb manual. If you can't find what you're looking for here, make sure to look at the docs
for "plugins":/documentation/plugins or just "contact us":/documentation/contact_us.

h1. Table of Contents

* Files and folders
* Site configuration
* Project builder configuration
* Default build tasks
* Changing the build command
* Handling custom build artifacts
* Build scheduling
* Deleting a project
* Build chaining & triggers
* Environment variables
* Remote builds
* Performing a clean checkout
* Troubleshooting and support

h1(#files_and_folders). Files and folders

* *$cruise* is how this documentation refers the directory where CC.rb itself has been unpacked or checked out.

* CC.rb places all of its project, plugin, and configuration data in $HOME/.cruise (%USERPROFILE%\.cruise on Windows).
  This documentation refers to this directory as *$cruise_data*.

* *$cruise_data*/projects/your_project/ is the directory where CC.rb will place the data for the project called "your_project".

* *$cruise_data*/projects/your_project/work/ is a local copy of your_project's source code. Builder keeps it up to date
  with the source control repository and runs builds against it.

* *$cruise_data*/projects/your_project/build-123/ contains a build status file, a list of changed files,
  and other "build artifacts" created while building revision 123.

* *$cruise_data*/projects/your_project/cruise_config.rb contains the build configuration for your_project.

* *$cruise_data*/config/site_config.rb is the file where you can make centralized changes to the configuration of the dashboard
  and all builders.

h1(#site_configuration). Site configuration

p. The CruiseControl.rb package includes a file called *$cruise*/config/site_config.rb.example. By copying it to
*$cruise*/config/site_config.rb and uncommenting some lines you can set a number of global configuration settings.
Normally you would only need to do this to configure an SMTP server for email notices. Email is configured using Rails'
ActionMailer component and accepts its standard configuration settings.

h1(#project_builder_configuration). Project builder configuration

If you don't provide a Cruise configuration for your project, CC.rb will try to make some reasonable guesses about how
to build your project, particularly if it's a Ruby application. (See Default build tasks below.)

However, there are only a few configuration settings that CC.rb can guess at. Specific projects will require more advanced configuration
if you need to add email notification recipients, configure plugins, or otherwise tweak your build run. A typical project configuration
in CC.rb is about 3 to 5 lines of very simple Ruby.

When you first add a project, a configuration file called cruise_config.rb is created for you in the
*$cruise_data*/projects/your_project/ directory. It contains a number of comments, but two lines are important:

  Project.configure do |project|
  end

Every cruise_config.rb must have these two lines, and all your other configuration goes between them. It's recommended that you check
this file into version control, and if you do then changes made to the configuration will be automatically be picked up by CC.rb the
next time you check in without any additional work required.

Optionally, you can put a configuration file in both places above. CruiseControl.rb loads both files, but settings from the
cruise_config.rb in *$cruise_data*/projects/your_project/ override those stored in your project's root directory.
This can be useful when you want to see the effect of some configuration settings without checking them in, or have some
location-dependent settings.

p(hint). Hint: configuration examples below include lines like '...'. This represents other
         configuration statements that may be in cruise_config.rb. You are not meant to copy-paste those dots into
         your configuration file, as they are not valid Ruby. If you do, ./cruise start will fail to start
         due to a syntax error.

Since configuration files are written in a real programming language (Ruby), you can modularize them, use
logical statements, and generally do whatever makes sense. For example, consider the following snippet:

  Project.configure do |project|
    case project.name
    when 'MyProject.Quick' then project.rake_task = 'test:units'
    when 'MyProject.BigBertha' then project.rake_task = 'cruise:all_tests'
    else raise "Don't know what to build for project #{project.name.inspect}"
    end
  end

p(hint). Hint: Use code like above to source-control configuration of multiple CruiseControl.rb projects building the same codebase.

h1(#default_build_tasks). Default build tasks

By default, CC.rb will assume that you are building a Ruby project, load your Rakefile, and look for the cruise,
test, and default (what happens when you just type rake with no arguments) tasks,
in that order, and execute the first one it finds.

Note that Rails provides you with an automatic test task when you first create your project. The behavior
for that task is documented here.

p(hint). WARNING: with Rails projects, it is important that RAILS_ENV does not default to 'production'.
         Unless you want your migration scripts and unit tests to hit your production database, of course.
         CruiseControl.reb leaves this variable unchanged when invoking 'cruise' or other custom Rake task, and sets
         it to 'test' before invoking the defaults.

h1(#changing_the_build_command). Changing the build command or Rake task

cruise may be the task for a quick build, but you may also want to run a long build with all acceptance
tests included. This can be done by assigning the project.rake_task attribute in cruise_config.rb:

  Project.configure do |project|
    ...
    project.rake_task = 'big_bertha_build'
    ...
  end

p(hint). Hint: Be careful when defining additional build tasks. If two builds share the same RAILS_ENV value
         then they will operate against the same database, which means that if two builds run simultaneously there is
         a chance that they will interfere with each other. You can avoid this issue this by creating a separate environment
         and making sure that the Rake task for your build sets the RAILS_ENV value to that environment in your
         Rake task. Copy config/environments/test.rb to config/environments/big_bertha.rb, add a :big_bertha_init
         Rake task with ENV['RAILS_ENV'] = 'big_bertha' in it, and put it in the beginning of
         :big_bertha_build list of depenedencies.

p(hint). Hint: Ideally, you'd also want some way to chain builds so that the long build for a new checkin is only
         launched once the short build has finished succesfully. CruiseControl.rb provides support for this option through
         the triggered_by project build configuration feature; see
         Build Chaining & Triggers.

CC.rb may be written in Ruby on Rails, but you don't need to be using Ruby and Rake in order to take advantage of it.
Other build tools like "make":http://www.gnu.org/software/make/,
"Ant":http://ant.apache.org/ and "MSBuild":http://msdn2.microsoft.com/en-us/library/wea2sca5.aspx are also supported--
really, any command that can return a success or failure status code.

A custom build command can be set with the project.build_command attribute. Modify cruise_config.rb file like
this:

  Project.configure do |project|
    ...
    project.build_command = 'my_build_script.sh'
    ...
  end

If project.build_command is set, CC.rb will invoke the specified command from the project's work directory
(*$cruise_data*/projects/your_project/work/) and examine the exit code to determine whether the
build passed or failed.

p(hint). Hint: You cannot set both the rake_task and build_command attributes in a a given project configuration.

h1(#handling_custom_build_artifacts). What should I do with custom build artifacts?

Some build tasks generate custom output, like test coverage statistics, that you may want to keep and see on the build page.
CruiseControl.rb supports the integration of that output by setting the CC_BUILD_ARTFACTS environment variable
to a directory that's been set aside specifically to collect them.

If you ensure that your special task writes its output to that directory or a subdirectory of it, then the resulting build artifacts page will automatically include links to every file or subdirectory found in the build artifacts directory.

p(hint). Hint: Code coverage analysis is a good example of custom build output. CruiseControl.rb's own build uses
         "rcov":http://eigenclass.org/hiki.rb. If you drill down into a recent CC.rb build on
         "http://cruisecontrolrb.thoughtworks.com":http://cruisecontrolrb.thoughtworks.com, you can see links
         to test coverage reports.

p(hint). Hint: The "metric_fu":http://github.com/jscruggs/metric_fu/tree/master project collects a number of
         helpful Ruby code metrics into a single, easy-to-configure plugin and integrates well with CC.rb.

h1(#build_scheduling). Build scheduling

By default, the builder polls Subversion every 10 seconds for new revisions. This can be changed by adding the
following line to cruise_config.rb:

  Project.configure do |project|
    ...
    project.scheduler.polling_interval = 5.minutes
    ...
  end

What if you want a scheduler with some interesting logic? Well, a default scheduler can be substituted by placing
your own scheduler implementation into the plugins directory and configuring it as follows:

  Project.configure do |project|
    ...
    project.scheduler = MyCustomScheduler.new(project)
    ...
  end

After initializing everything, and loading the project (this step includes evaluation of cruise_config.rb), the
builder invokes project.scheduler.run. A builder must be able to detect when its configuration has changed, or when a
build is requested by user (by pressing the Build Now button), so a custom scheduler needs to know how to recognize that situation.

Look at *$cruise*/app/models/polling_scheduler.rb to understand how a scheduler interacts with a project.

h1(#deleting_a_project). Deleting a project

To remove your_project from CruiseControl.rb, kill its builder process and then delete the *$cruise_data*/projects/your_project/
directory.

h1(#build_chaining_and_triggers). Build chaining & triggers

CC.rb uses triggers to tell it when to build a project.  Every project is configured, by default, with a ChangeInSourceControl trigger: it builds
when (surprise) it detects a change in a project's source control.

However, you can add additional triggers or replace a trigger entirely.  For example, you can have one project's successful build trigger another project's build with our SuccessfulBuildTrigger.

  project.triggered_by SuccessfulBuildTrigger.new(project, 'indie')

or, in short hand:

  project.triggered_by 'indie'

Why would you want one build to trigger another?  In this instance, maybe our project depends on indie and we want to know if a change to indie breaks our project.

These examples, *added* a SuccessfulBuildTrigger.  We could also *replace* the default trigger by writing

  project.triggered_by = [SuccessfulBuildTrigger.new(project, "fast_build")]

Why wouldn't we want our project to be triggered by a change to it's source code?  In this case, maybe we've separated our project into a fast and slow build.  We could use this to only trigger a slow build if the fast one passes.

h1(#environment_variables). Environment variables

CC.rb can set any custom environment variables that your build requires.  Every project can be configured to build with different environment variables.  For example:

  Project.configure do |project|
    project.environment['DB_HOST'] = 'db.example.com'
    project.environment['DB_PORT'] = '1234'
  end

h2(#ccrb_environment_variables). Special environment variables

CC.rb sets some environment variables when it runs your build, and you can use them inside your build process to tweak it or its output. Currently
there are just three:
* CC_BUILD_REVISION - this is the revision number of the current build, it looks like "5" or "56236"
* CC_BUILD_LABEL - usually this is the same as CC_BUILD_REVISION, but if there is more than one build of a particular revision, it will have a ".n" after it, so it might look like "323", "323.2", "4236.20", etc.
* CC_BUILD_ARTIFACTS - this is the directory which the dashboard looks in.  Any files you copy into here will be available from the dashboard.

h1(#remote_builds). Remote builds

CC.rb can run builds on remote servers.  This is done by sshing to the server in your build command.  For example:

  project.build_command = 'ssh user@server ./run_remotely.sh $CC_BUILD_REVISION'

run_remotely.sh might look something like:

  #/bin/bash
  svn up -r$1
  rake test:integration

Of course you will need to checkout the code on the remote server before running the first build.

Note that CC.rb will still maintain a checkout of the code on the local server, use it to check for modifications and store build results locally.
More robust support for builders on remote servers is expected in release 2.0.

h1(#performing_a_clean_checkout). Performing a clean checkout for each build

CC.rb supports clean checkouts, though they are not the default behavior.  To enable them, you must use the do_clean_checkout
flag together with an optional frequency. Acceptable values are :always, :never, and :every => [duration].

  project.do_clean_checkout :every => 6.hours

h1(#troubleshooting_and_support). Troubleshooting and support

If you have an issue that you cannot fix on your own, please consider subscribing to our mailing list at cruisecontrolrb-users@rubyforge.org
and asking for help. Please note, though, that we take great pains to make CC.rb easy to hack, and we encourage you to poke around in the
source code and hack away.

Should you require commercial support, training or consulting around this or other tool, "ThoughtWorks":http://thoughtworks.com/ can
provide it to you. We also offer a commercial CI product, "Cruise":http://studios.thoughtworks.com/cruise-continuous-integration, through
ThoughtWorks Studios, our product division.

p(hint). Hint to would-be contributors: documentation patches are as important, if not more so, than code patches, and would be
         gratefully accepted.


Updating the link to screencast

Updating the link to screencast

git-svn-id: 50a8ad97cae5d6ab203d2d535a9b32cd3858a8ac@414 c04ce798-636b-4ca8-9149-0f9336831111

h1. Screencasts

<div class="screencast_image">
  !/images/documentation/5_minute_install.png!:http://cruisecontrolrb.com/5_minute_install.mov
</div>

h3. "5 Minute Install":http://cruisecontrolrb.com/5_minute_install.mov

This is a 5 minute video that takes you through the steps of getting cruise control up and running with a rails project.

h1. Screencasts

<div class="screencast_image">
  !/images/documentation/5_minute_install.png!:http://www.cruisecontrolrb.com.php5-1.websitetestlink.com/5_minute_install.mov
</div>

h3. "5 Minute Install":http://www.cruisecontrolrb.com.php5-1.websitetestlink.com/5_minute_install.mov

This is a 5 minute video that takes you through the steps of getting cruise control up and running with a rails project.


FIX: very minor code cleanup.

FIX: very minor code cleanup.

Red/System [
	Title:   "Red native functions"
	Author:  "Nenad Rakocevic"
	File: 	 %natives.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
	}
]

natives: context [
	verbose: 0

	lf?: no												;-- used to print or not an ending newline

	print*: does [
		lf?: yes
		prin*
		lf?: no
	]

	prin*: func [
		/local
			arg		[red-value!]
			str		[red-string!]
			series	[series!]
	][
		#if debug? = yes [if verbose > 0 [print-line "native/prin"]]

		arg: stack/arguments

		either TYPE_OF(arg) = TYPE_STRING [
			str: as red-string! arg
		][
			actions/form*
			str: as red-string! arg + 1
			assert any [
				TYPE_OF(str) = TYPE_STRING
				TYPE_OF(str) = TYPE_SYMBOL					;-- symbol! and string! structs are overlapping
			]
		]
		series: GET_BUFFER(str)

		either lf? [
			switch GET_UNIT(series) [
				Latin1 [platform/print-line-Latin1 as c-string! series/offset]
				UCS-2  [platform/print-line-UCS2   as byte-ptr! series/offset]
				UCS-4  [platform/print-line-UCS4   as int-ptr!  series/offset]

				default [
					print-line ["Error: unknown string encoding:" GET_UNIT(series)]
				]
			]
		][
			switch GET_UNIT(series) [
				Latin1 [platform/print-Latin1 as c-string! series/offset]
				UCS-2  [platform/print-UCS2   as byte-ptr! series/offset]
				UCS-4  [platform/print-UCS4   as int-ptr!  series/offset]

				default [
					print-line ["Error: unknown string encoding:" GET_UNIT(series)]
				]
			]
		]
		stack/set-last unset-value
	]

	compare: func [
		op		   [integer!]
		reverse	   [logic!]
		return:    [red-logic!]
		/local
			args   [red-value!]
			result [red-logic!]
	][
		args: stack/arguments
		result: as red-logic! args
		res: actions/compare args args + 1 op
		result/value: either reverse [not res][res]
		result/header: TYPE_LOGIC
		result
	]

	equal?*: func [
		return:    [red-logic!]
	][
		#if debug? = yes [if verbose > 0 [print-line "native/equal?"]]
		compare COMP_EQUAL no
	]

	not-equal?*: func [
		return:    [red-logic!]
	][
		#if debug? = yes [if verbose > 0 [print-line "native/not-equal?"]]
		compare COMP_EQUAL yes
	]

	strict-equal?*: func [
		return:    [red-logic!]
	][
		#if debug? = yes [if verbose > 0 [print-line "native/strict-equal?"]]
		compare COMP_STRICT_EQUAL no
	]

	lesser?*: func [
		return:    [red-logic!]
	][
		#if debug? = yes [if verbose > 0 [print-line "native/lesser?"]]
		compare COMP_LESSER no
	]

	greater?*: func [
		return:    [red-logic!]
	][
		#if debug? = yes [if verbose > 0 [print-line "native/greater?"]]
		compare COMP_GREATER no
	]

	lesser-or-equal?*: func [
		return:    [red-logic!]
	][
		#if debug? = yes [if verbose > 0 [print-line "native/lesser-or-equal?"]]
		compare COMP_LESSER_EQUAL no
	]

	greater-or-equal?*: func [
		return:    [red-logic!]
	][
		#if debug? = yes [if verbose > 0 [print-line "native/greater-or-equal?"]]
		compare COMP_GREATER_EQUAL no
	]

	not*: func [
		/local bool [red-logic!]
	][
		#if debug? = yes [if verbose > 0 [print-line "native/not"]]

		bool: as red-logic! stack/arguments
		bool/value: logic/false?						;-- run test before modifyin stack
		bool/header: TYPE_LOGIC
	]

	;--- Natives helper functions ---

	foreach-next: func [
		return: [logic!]
		/local
			series [red-series!]
			word   [red-word!]
			s	   [series!]
			result [logic!]
	][
		series: as red-series! stack/arguments - 1
		word:   as red-word!   stack/arguments - 2

		assert any [									;@@ replace with any-block?/any-string? check
			TYPE_OF(series) = TYPE_BLOCK
			TYPE_OF(series) = TYPE_STRING
		]
		assert TYPE_OF(word) = TYPE_WORD

		stack/mark exec/_pick							;@@ replace it with direct calls
		copy-cell as red-value! series stack/push
		integer/push 1
		actions/pick*
		stack/unwind

		_context/set word stack/last-value
		series/head: series/head + 1
		s: GET_BUFFER(series)

		either TYPE_OF(series) = TYPE_BLOCK [			;@@ replace with any-block?/any-string? check
			result: s/offset + series/head <= s/tail
		][
			result: (as byte-ptr! s/offset)
				+ (series/head << (GET_UNIT(s) >> 1))
				<= (as byte-ptr! s/tail)
		]
		result
	]

]

Red/System [
	Title:   "Red native functions"
	Author:  "Nenad Rakocevic"
	File: 	 %natives.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
	}
]

natives: context [
	verbose: 0

	lf?: no												;-- used to print or not an ending newline

	print*: does [
		lf?: yes
		prin*
		lf?: no
	]

	prin*: func [
		/local
			arg		[red-value!]
			str		[red-string!]
			series	[series!]
	][
		#if debug? = yes [if verbose > 0 [print-line "native/prin"]]

		arg: stack/arguments

		either TYPE_OF(arg) = TYPE_STRING [
			str: as red-string! arg
		][
			actions/form*
			str: as red-string! arg + 1
			assert any [
				TYPE_OF(str) = TYPE_STRING
				TYPE_OF(str) = TYPE_SYMBOL					;-- symbol! and string! structs are overlapping
			]
		]
		series: GET_BUFFER(str)

		either lf? [
			switch GET_UNIT(series) [
				Latin1 [platform/print-line-Latin1 as c-string! series/offset]
				UCS-2  [platform/print-line-UCS2   as byte-ptr! series/offset]
				UCS-4  [platform/print-line-UCS4   as int-ptr!  series/offset]

				default [
					print-line ["Error: unknown string encoding:" GET_UNIT(series)]
				]
			]
		][
			switch GET_UNIT(series) [
				Latin1 [platform/print-Latin1 as c-string! series/offset]
				UCS-2  [platform/print-UCS2   as byte-ptr! series/offset]
				UCS-4  [platform/print-UCS4   as int-ptr!  series/offset]

				default [
					print-line ["Error: unknown string encoding:" GET_UNIT(series)]
				]
			]
		]
		stack/set-last unset-value
	]

	compare: func [
		op		   [integer!]
		reverse	   [logic!]
		return:    [red-logic!]
		/local
			args   [red-value!]
			result [red-logic!]
	][
		args: stack/arguments
		result: as red-logic! args
		res: actions/compare args args + 1 op
		result/value: either reverse [not res][res]
		result/header: TYPE_LOGIC
		result
	]

	equal?*: func [
		return:    [red-logic!]
	][
		#if debug? = yes [if verbose > 0 [print-line "native/equal?"]]
		compare COMP_EQUAL no
	]

	not-equal?*: func [
		return:    [red-logic!]
	][
		#if debug? = yes [if verbose > 0 [print-line "native/not-equal?"]]
		compare COMP_EQUAL yes
	]

	strict-equal?*: func [
		return:    [red-logic!]
	][
		#if debug? = yes [if verbose > 0 [print-line "native/strict-equal?"]]
		compare COMP_STRICT_EQUAL no
	]

	lesser?*: func [
		return:    [red-logic!]
	][
		#if debug? = yes [if verbose > 0 [print-line "native/lesser?"]]
		compare COMP_LESSER no
	]

	greater?*: func [
		return:    [red-logic!]
	][
		#if debug? = yes [if verbose > 0 [print-line "native/greater?"]]
		compare COMP_GREATER no
	]

	lesser-or-equal?*: func [
		return:    [red-logic!]
	][
		#if debug? = yes [if verbose > 0 [print-line "native/lesser-or-equal?"]]
		compare COMP_LESSER_EQUAL no
	]

	greater-or-equal?*: func [
		return:    [red-logic!]
	][
		#if debug? = yes [if verbose > 0 [print-line "native/greater-or-equal?"]]
		compare COMP_GREATER_EQUAL no
	]

	not*: func [
		/local bool [red-logic!]
	][
		#if debug? = yes [if verbose > 0 [print-line "native/not"]]

		bool: as red-logic! stack/arguments
		bool/value: logic/false?						;-- run test before modifyin stack
		bool/header: TYPE_LOGIC
	]

	;--- Natives helper functions ---

	foreach-next: func [
		return: [logic!]
		/local
			series [red-series!]
			word   [red-word!]
			s	   [series!]
			result [logic!]
	][
		series: as red-series! stack/arguments - 1
		word:   as red-word!   stack/arguments - 2

		assert any [									;@@ replace with any-block?/any-string? check
			TYPE_OF(series) = TYPE_BLOCK
			TYPE_OF(series) = TYPE_STRING
		]
		assert TYPE_OF(word) = TYPE_WORD

		stack/mark exec/_pick							;@@ replace it with direct calls
		copy-cell as red-value! series stack/push
		integer/push 1
		actions/pick*
		stack/unwind

		_context/set (word) stack/last-value
		series/head: series/head + 1
		s: GET_BUFFER(series)

		either TYPE_OF(series) = TYPE_BLOCK [			;@@ replace with any-block?/any-string? check
			result: s/offset + series/head <= s/tail
		][
			result: (as byte-ptr! s/offset)
				+ (series/head << (GET_UNIT(s) >> 1))
				<= (as byte-ptr! s/tail)
		]
		result
	]

]


FEAT: now object! implements REFLECT action for 'words and 'values selectors.

Red/System [
	Title:   "Object! datatype runtime functions"
	Author:  "Nenad Rakocevic"
	File: 	 %object.reds
	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
	}
]

object: context [
	verbose: 0

	do-indent: func [
		buffer	[red-string!]
		tabs	[integer!]
		part	[integer!]
		return:	[integer!]
		/local
			n [integer!]
	][
		n: tabs
		until [
			string/concatenate-literal buffer "    "
			n: n - 1
			zero? n
		]
		part - (4 * tabs)
	]

	serialize: func [
		obj		[red-object!]
		buffer	[red-string!]
		only?	[logic!]
		all?	[logic!]
		flat?	[logic!]
		arg		[red-value!]
		part	[integer!]
		indent?	[logic!]
		tabs	[integer!]
		return: [integer!]
		/local
			syms	[series!]
			values	[series!]
			sym		[red-value!]
			s-tail	[red-value!]
			value	[red-value!]
	][
		syms:   as series! obj/symbols/value
		values: as series! obj/values/value

		sym:	syms/offset
		s-tail: syms/tail
		value: 	values/offset

		while [sym < s-tail][
			if indent? [part: do-indent buffer tabs part]

			part: word/mold as red-word! sym buffer no no flat? arg part tabs
			string/concatenate-literal buffer ": "
			part: part - 2

			part: actions/mold value buffer only? all? flat? arg part tabs

			if any [indent? sym + 1 < s-tail][			;-- no final LF when FORMed
				string/append-char GET_BUFFER(buffer) as-integer lf
				part: part - 1
			]
			sym: sym + 1
			value: value + 1
		]
		part
	]

	rebind: func [
		fun		[red-function!]
		ctx 	[red-context!]
		/local
			s	 [series!]
			more [red-value!]
	][
		s: as series! fun/more/value
		more: s/offset

		if TYPE_OF(more) = TYPE_NONE [
			print-line "*** Error: COPY stuck on missing function's body block"
			halt
		]
		_context/bind as red-block! more ctx yes
		_context/bind as red-block! more fun/ctx no

		more: more + 2
		more/header: TYPE_UNSET			;-- invalidate compiled body
	]

	make-at: func [
		cell	[red-object!]
		slots	[integer!]
		return: [red-object!]
	][
		cell/header:  TYPE_OBJECT
		cell/symbols: alloc-cells slots
		cell/values:  alloc-cells slots
		cell
	]

	;-- Actions --

	make: func [
		proto	[red-object!]
		spec	[red-block!]
		return:	[red-object!]
		/local
			obj	 [red-object!]
	][
		#if debug? = yes [if verbose > 0 [print-line "object/make"]]

		obj: as red-object! ALLOC_TAIl(root)

		either TYPE_OF(proto) = TYPE_OBJECT [
			copy proto obj null yes null				;-- /deep
		][
			make-at obj 4								;-- arbitrary value
		]
		_context/collect-set-words as red-context! obj spec
		_context/bind spec as red-context! obj yes
		interpreter/eval spec
		obj
	]

	reflect: func [
		obj		[red-object!]
		field	[integer!]
		return:	[red-block!]
		/local
			blk [red-block!]
			s	[series!]
	][
		blk: 		as red-block! stack/push*
		blk/header: TYPE_BLOCK
		blk/head: 	0

		case [
			field = words/words [
				blk/node: obj/symbols
				stack/set-last as red-value! block/clone blk no
			]
			field = words/values [
				blk/node: obj/values
				stack/set-last as red-value! block/clone blk no
			]
			field = words/body [
				--NOT_IMPLEMENTED--
			]
			true [
				--NOT_IMPLEMENTED--						;@@ raise error
			]
		]
		blk												;@@ TBD: remove it when all cases implemented
	]

	form: func [
		obj		[red-object!]
		buffer	[red-string!]
		arg		[red-value!]
		part	[integer!]
		return: [integer!]
	][
		#if debug? = yes [if verbose > 0 [print-line "object/form"]]

		serialize obj buffer no no no arg part no 0
	]

	mold: func [
		obj		[red-object!]
		buffer	[red-string!]
		only?	[logic!]
		all?	[logic!]
		flat?	[logic!]
		arg		[red-value!]
		part	[integer!]
		indent	[integer!]
		return: [integer!]
	][
		#if debug? = yes [if verbose > 0 [print-line "object/mold"]]

		string/concatenate-literal buffer "make object! [^/"
		part: serialize obj buffer only? all? flat? arg part - 15 yes indent + 1
		if indent > 0 [part: do-indent buffer indent part]
		string/append-char GET_BUFFER(buffer) as-integer #"]"
		part - 1
	]

	eval-path: func [
		parent	[red-object!]							;-- implicit type casting
		element	[red-value!]
		set?	[logic!]
		return:	[red-value!]
		/local
			word [red-word!]
			ctx  [red-context!]
	][
		word: as red-word! element
		ctx:  as red-context! parent

		if word/ctx <> ctx [							;-- bind the word to object's context
			word/index: _context/find-word ctx word/symbol
			word/ctx: ctx
		]
		either set? [
			_context/set-in word stack/arguments ctx
			stack/arguments
		][
			_context/get-in word ctx
		]
	]

	copy: func [
		obj      [red-object!]
		new	  	 [red-object!]
		part-arg [red-value!]
		deep?	 [logic!]
		types	 [red-value!]
		return:	 [red-object!]
		/local
			value [red-value!]
			tail  [red-value!]
			src	  [series!]
			dst	  [series!]
			size  [integer!]
			slots [integer!]
	][
		#if debug? = yes [if verbose > 0 [print-line "object/copy"]]

		if OPTION?(types) [--NOT_IMPLEMENTED--]

		if OPTION?(part-arg) [
			print-line "***Error: copy/part is not supported on objects"
			halt
		]

		src:	as series! obj/symbols/value
		size:   as-integer src/tail - src/offset
		slots:	size >> 4

		new: make-at new slots

		;-- process SYMBOLS
		dst: as series! new/symbols/value
		copy-memory as byte-ptr! dst/offset as byte-ptr! src/offset size
		dst/size: size
		dst/tail: dst/offset + slots
		_context/set-context-each as red-context! new dst

		;-- process VALUES
		src: as series! obj/values/value
		dst: as series! new/values/value
		copy-memory as byte-ptr! dst/offset as byte-ptr! src/offset size
		dst/size: size
		dst/tail: dst/offset + slots

		if deep? [
			value: dst/offset
			tail:  dst/tail

			while [value < tail][
				switch TYPE_OF(value) [					;@@ replace it with ANY_SERIES?()
					TYPE_BLOCK
					TYPE_PAREN
					TYPE_PATH
					TYPE_SET_PATH
					TYPE_GET_PATH
					TYPE_LIT_PATH
					TYPE_STRING
					TYPE_FILE [
						actions/copy value value null yes null ;-- overwrite the value
					]
					TYPE_FUNCTION [
						rebind as red-function! value as red-context! new
					]
					default [0]
				]
				value: value + 1
			]
		]

		new
	]

	init: does [
		datatype/register [
			TYPE_OBJECT
			TYPE_VALUE
			"object!"
			;-- General actions --
			:make
			null			;random
			:reflect
			null			;to
			:form
			:mold
			:eval-path
			null			;set-path
			null			;compare
			;-- Scalar actions --
			null			;absolute
			null			;add
			null			;divide
			null			;multiply
			null			;negate
			null			;power
			null			;remainder
			null			;round
			null			;subtract
			null			;even?
			null			;odd?
			;-- Bitwise actions --
			null			;and~
			null			;complement
			null			;or~
			null			;xor~
			;-- Series actions --
			null			;append
			null			;at
			null			;back
			null			;change
			null			;clear
			:copy
			null			;find
			null			;head
			null			;head?
			null			;index?
			null			;insert
			null			;length?
			null			;next
			null			;pick
			null			;poke
			null			;remove
			null			;reverse
			null			;select
			null			;sort
			null			;skip
			null			;swap
			null			;tail
			null			;tail?
			null			;take
			null			;trim
			;-- I/O actions --
			null			;create
			null			;close
			null			;delete
			null			;modify
			null			;open
			null			;open?
			null			;query
			null			;read
			null			;rename
			null			;update
			null			;write
		]
	]
]

Red/System [
	Title:   "Object! datatype runtime functions"
	Author:  "Nenad Rakocevic"
	File: 	 %object.reds
	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
	}
]

object: context [
	verbose: 0

	do-indent: func [
		buffer	[red-string!]
		tabs	[integer!]
		part	[integer!]
		return:	[integer!]
		/local
			n [integer!]
	][
		n: tabs
		until [
			string/concatenate-literal buffer "    "
			n: n - 1
			zero? n
		]
		part - (4 * tabs)
	]

	serialize: func [
		obj		[red-object!]
		buffer	[red-string!]
		only?	[logic!]
		all?	[logic!]
		flat?	[logic!]
		arg		[red-value!]
		part	[integer!]
		indent?	[logic!]
		tabs	[integer!]
		return: [integer!]
		/local
			syms	[series!]
			values	[series!]
			sym		[red-value!]
			s-tail	[red-value!]
			value	[red-value!]
	][
		syms:   as series! obj/symbols/value
		values: as series! obj/values/value

		sym:	syms/offset
		s-tail: syms/tail
		value: 	values/offset

		while [sym < s-tail][
			if indent? [part: do-indent buffer tabs part]

			part: word/mold as red-word! sym buffer no no flat? arg part tabs
			string/concatenate-literal buffer ": "
			part: part - 2

			part: actions/mold value buffer only? all? flat? arg part tabs

			if any [indent? sym + 1 < s-tail][			;-- no final LF when FORMed
				string/append-char GET_BUFFER(buffer) as-integer lf
				part: part - 1
			]
			sym: sym + 1
			value: value + 1
		]
		part
	]

	rebind: func [
		fun		[red-function!]
		ctx 	[red-context!]
		/local
			s	 [series!]
			more [red-value!]
	][
		s: as series! fun/more/value
		more: s/offset

		if TYPE_OF(more) = TYPE_NONE [
			print-line "*** Error: COPY stuck on missing function's body block"
			halt
		]
		_context/bind as red-block! more ctx yes
		_context/bind as red-block! more fun/ctx no

		more: more + 2
		more/header: TYPE_UNSET			;-- invalidate compiled body
	]

	make-at: func [
		cell	[red-object!]
		slots	[integer!]
		return: [red-object!]
	][
		cell/header:  TYPE_OBJECT
		cell/symbols: alloc-cells slots
		cell/values:  alloc-cells slots
		cell
	]

	;-- Actions --

	make: func [
		proto	[red-object!]
		spec	[red-block!]
		return:	[red-object!]
		/local
			obj	 [red-object!]
	][
		#if debug? = yes [if verbose > 0 [print-line "object/make"]]

		obj: as red-object! ALLOC_TAIl(root)

		either TYPE_OF(proto) = TYPE_OBJECT [
			copy proto obj null yes null				;-- /deep
		][
			make-at obj 4								;-- arbitrary value
		]
		_context/collect-set-words as red-context! obj spec
		_context/bind spec as red-context! obj yes
		interpreter/eval spec
		obj
	]

	form: func [
		obj		[red-object!]
		buffer	[red-string!]
		arg		[red-value!]
		part	[integer!]
		return: [integer!]
	][
		#if debug? = yes [if verbose > 0 [print-line "object/form"]]

		serialize obj buffer no no no arg part no 0
	]

	mold: func [
		obj		[red-object!]
		buffer	[red-string!]
		only?	[logic!]
		all?	[logic!]
		flat?	[logic!]
		arg		[red-value!]
		part	[integer!]
		indent	[integer!]
		return: [integer!]
	][
		#if debug? = yes [if verbose > 0 [print-line "object/mold"]]

		string/concatenate-literal buffer "make object! [^/"
		part: serialize obj buffer only? all? flat? arg part - 15 yes indent + 1
		if indent > 0 [part: do-indent buffer indent part]
		string/append-char GET_BUFFER(buffer) as-integer #"]"
		part - 1
	]

	eval-path: func [
		parent	[red-object!]							;-- implicit type casting
		element	[red-value!]
		set?	[logic!]
		return:	[red-value!]
		/local
			word [red-word!]
			ctx  [red-context!]
	][
		word: as red-word! element
		ctx:  as red-context! parent

		if word/ctx <> ctx [							;-- bind the word to object's context
			word/index: _context/find-word ctx word/symbol
			word/ctx: ctx
		]
		either set? [
			_context/set-in word stack/arguments ctx
			stack/arguments
		][
			_context/get-in word ctx
		]
	]

	copy: func [
		obj      [red-object!]
		new	  	 [red-object!]
		part-arg [red-value!]
		deep?	 [logic!]
		types	 [red-value!]
		return:	 [red-object!]
		/local
			value [red-value!]
			tail  [red-value!]
			src	  [series!]
			dst	  [series!]
			size  [integer!]
			slots [integer!]
	][
		#if debug? = yes [if verbose > 0 [print-line "object/copy"]]

		if OPTION?(types) [--NOT_IMPLEMENTED--]

		if OPTION?(part-arg) [
			print-line "***Error: copy/part is not supported on objects"
			halt
		]

		src:	as series! obj/symbols/value
		size:   as-integer src/tail - src/offset
		slots:	size >> 4

		new: make-at new slots

		;-- process SYMBOLS
		dst: as series! new/symbols/value
		copy-memory as byte-ptr! dst/offset as byte-ptr! src/offset size
		dst/size: size
		dst/tail: dst/offset + slots
		_context/set-context-each as red-context! new dst

		;-- process VALUES
		src: as series! obj/values/value
		dst: as series! new/values/value
		copy-memory as byte-ptr! dst/offset as byte-ptr! src/offset size
		dst/size: size
		dst/tail: dst/offset + slots

		if deep? [
			value: dst/offset
			tail:  dst/tail

			while [value < tail][
				switch TYPE_OF(value) [					;@@ replace it with ANY_SERIES?()
					TYPE_BLOCK
					TYPE_PAREN
					TYPE_PATH
					TYPE_SET_PATH
					TYPE_GET_PATH
					TYPE_LIT_PATH
					TYPE_STRING
					TYPE_FILE [
						actions/copy value value null yes null ;-- overwrite the value
					]
					TYPE_FUNCTION [
						rebind as red-function! value as red-context! new
					]
					default [0]
				]
				value: value + 1
			]
		]

		new
	]

	init: does [
		datatype/register [
			TYPE_OBJECT
			TYPE_VALUE
			"object!"
			;-- General actions --
			:make
			null			;random
			null			;reflect
			null			;to
			:form
			:mold
			:eval-path
			null			;set-path
			null			;compare
			;-- Scalar actions --
			null			;absolute
			null			;add
			null			;divide
			null			;multiply
			null			;negate
			null			;power
			null			;remainder
			null			;round
			null			;subtract
			null			;even?
			null			;odd?
			;-- Bitwise actions --
			null			;and~
			null			;complement
			null			;or~
			null			;xor~
			;-- Series actions --
			null			;append
			null			;at
			null			;back
			null			;change
			null			;clear
			:copy
			null			;find
			null			;head
			null			;head?
			null			;index?
			null			;insert
			null			;length?
			null			;next
			null			;pick
			null			;poke
			null			;remove
			null			;reverse
			null			;select
			null			;sort
			null			;skip
			null			;swap
			null			;tail
			null			;tail?
			null			;take
			null			;trim
			;-- I/O actions --
			null			;create
			null			;close
			null			;delete
			null			;modify
			null			;open
			null			;open?
			null			;query
			null			;read
			null			;rename
			null			;update
			null			;write
		]
	]
]