AI
Animation
CGI
Compression
Console
Database
Debug
Dialects
Dialogs
Editor
Email
Encryption
Extension
External Library
File
File Handling
Files
Financial
FTP
Game
Games
Graphics
GUI
HTML
HTTP
Internet
LDC
Markup
Math
Module
Network
Networking
None
Other - Net
Parse
Patch
Printing
Protocol
Rebol
Scheme
Scientific
SDK
Security
Shell
Sound
SQL
TCP
Testing
Text
Text Processing
UI
User Interface
Util
Utility
VID
Visualization
Web
Win API
X-File
XML
rebol [
	title:		"args - generic command-line argument parser."
	file: 		%args.r
	version:	0.1.10
	date: 		2008-12-17
	author:		"Maxim Olivier-Adlhoch"
	copyright:	"Copyright (c) 2008 Maxim Olivier-Adlhoch"
	license:    'mit
	purpose:	"End to end command-line argument management.  Using a command-line description dialect parse a command-line and if its valid, construct a context which reflects it."
	note:       "requires vprint.r module from rebol.org to be run prior to this one"

	;-- REBOL.ORG header --
	library: [
		level:          'intermediate
		platform:       'all
		type:           [ module ]
		domain:         [ external-library dialects shell  ]
		tested-under:   [win view 2.7.5]
		license:        'MIT
		see-also:       "vprint.r args-test.r"
	]


	to-do: {
	-must continue expanding command-line error reporting
	-debug all datatypes when defining optional datatype for arguments (order and mutual inclusion)
	}

	changes: {}
	
	history: {
		v0.1.1 - 2008-04-09/16:50:42 (max)
			-first history entry, after lengthy dev cycle
			-added extended file path notation, to allow paths with spaces. (ex, program files, documents and settings, etc)

		v0.1.6 - 2008-12-10/02:11:32 (max)
			-added a bit more docs about -????? flag
			-started embedded documentation at end of script

		v0.1.7 - 2008-12-15/00:34:48 (max)
			-switch now can act as a toggle between two values, instead of only supporting boolean on/off functionality.
			-added '0' & '1' to the valid boolean notations in command parsing
			-converted to simple rebol 'DO format for rebol.org release

		v0.1.8 - 2008-12-16/04:18:11 (max)
			-added command-line error reporting basics should report missing arguments
			-explicit support for command-line reporting in decimal! and integer! datatypes.

		v0.1.9 - 2008-12-16/20:26:20 (max)
			-fixed command-line parsing bug when specifying integer! and decimal! as both valid for a type...

		v0.1.10 - 2008-12-17/03:31:14 (max)
			-flags now specifically enfore that flags follow string alphanumeric word format (starting with a "-")
	}
]


;; conditional lib execution, simulates C/C++ #ifndef 
do unless (value? 'lib-args) [[

;; declare lib
lib-args: true


lib-args-ctx: context [
	;- LIBS
	;slim/open 'core none ; for slim-link
	;os: slim/open 'os none
	
	;----------
	; GLOBALS
	;- max-args
	max-args: 1000 ; just a safety for parser deadlock or application hacking (too many args could cause some apps to crash)
	
	;- error-index-symbol: 
	error-index-symbol: ""
	
	;- load-error:
	; used for storage of error info when parsing command lines.
	load-error: none
	
	;- load-error-offset:
	load-error-offset: none
	
	;- error-msg:
	error-msg: none
	
	
	;- flag-name
	flag-name: none
	
								

	
	
	;----------
	; INTERNALS
	; localise values:
	rlv-str: val: none
	
	
		
	;-  
	;- VALUE-RULES[]
	value-rules: context [
		;-    context locals
		here-text: none
	
	
		;-    bitsets
		space: #" " ; newline and tab are already defined
		digit: charset [#"0" - #"9"]
		letter: charset [#"A" - #"Z"   #"a" - #"z" ]
		upper-case: charset [#"A" - #"Z"]
		alphanumeric: charset [ #"A" - #"Z"  #"a" - #"z"  #"0" - #"9"  #"-" #"_"]
		chars: complement charset [#"\" #"'"]
		block-end: complement charset [#"]"]
		anychar: complement charset [#" "]
		
		xtdpath-char: complement charset "'"
		
		white-space: charset reduce [ space tab newline]
		spaces: [some white-space]
		spacer: _: [any white-space] ; when its not required
		non-white-space: complement white-space
		separator: [[some white-space] | end]
	
	;-    type rules
		escape-char: [#"\" skip]
		string: [
			[
				; one of 3 string syntaxes!
				[{'} copy rlv-str [any [chars | escape-char]] {'}] |
				[{"} copy rlv-str [any [chars | escape-char]] {"}] |
				["{" copy rlv-str [any [chars | escape-char]] "}"]
			]
			
			( rlv-str: any [rlv-str copy ""] )
		
		] ; skip escaped chars{"} ]
		
		integer: [ 0 1 "-" some digit]
		float:   [ 0 1 "-" any digit "." some digit 0 1 ["E" some digit]]
		bool:  ["true" | "false" | "on" | "off" | "0" | "1"]
		flag: [ ["-" 0 1 "-" letter any alphanumeric] ] ; -switches cannot start with a digit
		datatype: [ [some letter "!"] ]
		path: file-path: [ 0 1 "%" ["./" | "/" | "\" | ".\" | [letter ":"]] any [non-white-space ]]
		block: [ "[" copy rlv-str to "]" skip] ; no "]" chars in any way within blocks.
		extended-file-path: [ 
			0 1 "%" 
			(rlv-str: none)
			[
				"'" copy rlv-str [ ["./" | "/" | "\" | ".\" | [letter ":"]]  any xtdpath-char]  "'"
			]|[
				copy rlv-str [["./" | "/" | "\" | ".\" | [letter ":"]] any [non-white-space ]]
			]
		]
		
		; any text (all chars until next flag (but not including it) )
		skip-text-rule: [skip here-text: ]
		skip-rule: none
		here-mem: none
		skip-flag: none
		any-text: [
			( skip-rule: skip-text-rule)
			some [
				here-mem:
				[
					some white-space skip-flag: flag  ( ; note that "-doo" in ski-doo will not match as a flag
						here-text: here-mem
						
						skip-rule: "_" ; we want the next skip to fail, and thus end the skipping, since here will start at a "-"
					)
					 :skip-flag
				]
				| 
				skip-rule 
			]
			:here-text 
		]
		
		error-at: none
		;-    compound rules
		value: [
			[
				error-at:
				copy val string  (append current-rblk rlv-str vprint ["STRING!: " rlv-str] rlv-str: none) | ; here we use rlv-str, because it contains no " chars
				copy val path    (if #"%" = first val [remove val] append current-rblk to-rebol-file val vprint ["PATH!: " val	]) |
				copy val bool    (append current-rblk to-logic do val vprint ["BOOL!: " val]) | 
				copy val float   (append current-rblk to-issue val vprint ["FLOAT!: " val]) | 
				copy val integer (append current-rblk to-issue val vprint ["INT!: " val]) |
				copy val flag  (append current-rblk to-word val vprint ["LABEL!: " val	]) |
				copy val datatype  (append current-rblk to-datatype val vprint ["DATATYPE!: " val	]) |
				copy val block   (append/only current-rblk val: parse/all rlv-str " " vprint ["BLOCK!: " mold/all val]) 
				(arg-load-count: arg-load-count + 1 if arg-load-count > max-args [print "arguments maximum count reached" halt])
				
			]
			(val: none)
		]
		
		; this rule loads ALL values from string, if they obey basic values rules	
		parameters: [ (current-rblk: copy [] arg-load-count: 0) some [ value | spaces]]
		
		arg-load-count: 0
		current-rblk: copy []
		
		
		;-    arg loading rules
		parsed-value: none
;		integer-rule: [
;			(parsed-value: none)
;			[
;				copy val integer 
;				(parsed-value: to-issue val vprint ["INT!: " val])
;				val: none
;			]|
;			[
;				(to-error "FUCK")
;			]
;		]
		
		integer-rule: [(parsed-value: none ) copy val integer separator   (parsed-value: to-issue val vprint ["INT!: " val]) val: none ]
		float-rule:   [(parsed-value: none ) copy val float  separator  (parsed-value: to-issue val vprint ["FLOAT!: " val]) val: none ]
		text-rule:    [(parsed-value: none) copy val any-text separator (parsed-value: trim val vprint ["TEXT!: " parsed-value]) val: none]
		bool-rule:    [(parsed-value: none) copy val bool separator (parsed-value: to-logic do val vprint ["BOOL!: " val] val: none)]
		string-rule:  [(parsed-value: none) string separator (parsed-value: rlv-str vprint ["STRING!: " rlv-str] rlv-str: none)] ; here we use rlv-str, because it contains no ' chars
		file-rule:    [(parsed-value: none) extended-file-path  separator (parsed-value: to-rebol-file rlv-str vprint ["PATH!: " parsed-value] val: none)] ; here we use rlv-str, because it contains no ' chars
	]
		
		
	;-    spec parsing rules
	;---
	; these are in fact words, not actual datatypes, since the spec is not loaded.
	;
	; CRITICAL NOTE!:
	;     Following list must be symmetric with switch list and untyped args in arg-ctx/init()
	;---
	spec-datatypes: ['integer! | 'string! | 'logic! | 'file! | 'decimal! | 'text! ]
		
	
;	
;	either LINKED?: false [
;		args: system/script/args
;	][
;		; just some generic argument
;		args: { -stack [fubar 001 25] plate ball 1 box counter  C:/some/path/to/a/file.txt +LR +BLUR }
;	]
	
	;-  
	;- FUNCTIONS
	;-------------
	;-     load-args()
	;-------------
	load-args: func [
		argstr [string!]
	][
		return either parse/all/case argstr value-rules/parameters [
			
			; all is well with command-line parsing, return loaded block
			first reduce [value-rules/current-rblk value-rules/current-rblk: rlv-str: val: none]
		
		][
			; an error occured, clear all data and return the error
			value-rules/current-rblk: rlv-str: val: none
			value-rules/error-at
		]
	]
	
	
	;-------------
	;-     construct-args()
	;-------------
	set 'construct-args func [
		"returns an object with all fields filled and fully validated, according to spec, an error string otherwise."
		args [string! block!] "either the argument string or a load-args block"
		spec [block!] {
		-flag [
			[switch!] arg type! [type! [...]] [default-value] ; both type and default value are optional
			[|] ; optional, changes flag's mode to mutually exclusive args based on type
			arg [...] 
			[|] ; as above
			arg [...]
		]
		-flag [...]

		
		; trailing args by type OR nothing, in which case any additional args are put in values: field
		
		integer! [default-value]
		file! [...]		
		...
}
		/local arg-ctx flag-name arg-name arg-type arg-value-when-set arg-value-when-unset arg-default 
			subrule flag-type here-error spec-error
			current-flag-rule new-flag-rule cmd-line-rule flag-ctx flags
			arg-val args-ctx error-msg entry-args
	][
		;---------------------
		;-         args-ctx:
		; used to store all arg names and default values, later on is converted to an object and filled up
		; *supplied-flags is used to know what flags where actually supplied on the command-line,
		;    in case some app features need this data (two flags sharing the same args).
		args-ctx: copy/deep [*supplied-flags: [] *error: none]
		
		;---------------------
		;-         flags:
		; we store all generated flag ctx here.
		; once spec parsing is done, we will run through this list and create a compiled command-line parse rule
		; and it will fill up the end-result args-ctx.
		flags: copy []
		
		;---------------------
		;-         cmd-line-rule:
		; this stores the compiled command-line parse rule, with all flags and args within.
		cmd-line-rule: copy []
		

		;---------------------
		; entry-args
		entry-args: args  ;  potentially deprecated ????
		
		
		;---------------------
		; perform parsing within a safe and verbose error recovery
		;
		if error? spec-error: try [
			;--------------------------------------------------------------------
			;---                                                              ---    
			;---                   DEFINE ARG SPEC CONTEXTS                   ---
			;---                                                              ---    
			;--------------------------------------------------------------------
			vprobe args
			vprint "^/----------------------^/starting args-context()"

			;-------------
			;-         flag-ctx[]
			; 
			; each flag in your command-line spec, will generate one flag-ctx and add it to the flags block.
			;-------------
			flag-ctx: context [
				;-             name:
				name: none
				;-             type:
				type: 'arg
				;-             args:
				args: none
				;-             rule:
				rule: none
				;-             required?:
				required?: false

				;------------------------------
				;-             apply-defaults()
				;------------------------------
				apply-defaults: func [/local arg][
					foreach arg args [
						arg/apply-default
					]
				]
				
				;------------------------------
				;-             link-args()
				;------------------------------
				; here we check if all supplied args are valid amongst themselves.
				;
				; possible errors:
				; 	-a required arg is specified AFTER optional ones
				;------------------------------
				link-args: func [
					/local required? arg rule-tmp paren
				][
					vin "link-args()"
					required?: true
					
					
					foreach arg args [
						;-----------------------------------------------------------------
						; -????? is a shadow tag which never gets linked in the system.
						; its purpose is to modify the args-ctx directly, without really
						; adding args to your spec.
						unless name = '-????? [
							; make sure required args are not specified after optional ones.
							rule-tmp: tail rule
							any [
								all [
									not required? 
									arg/required?
									(make error! rejoin ["ERROR: Required arg '" arg/name "' follows optional args in " name " flag spec!"])
								]
								all [
									not arg/required?
									required?: false
								]
							]
							
							append rule arg/rule
							new-line rule-tmp true
						]
						; add args and defaults to args-ctx
						append args-ctx to-set-word arg/name
						append args-ctx arg/default
					]
					if rule [
						paren: [vout] 
						append/only rule to-paren paren
					]
					vout
				]
				
				;------------------------------
				;-             register()
				;------------------------------
				register: func [][
					;-----------------------------------------------------------------
					; -????? is a shadow tag which never gets linked in the system.
					; its purpose is to modify the args-ctx directly, without really
					; adding args to your spec.
					unless name = '-????? [
						append flags self
					]
				]
				
				;-----------------
				;-             confirm-flag-name()
				;-----------------
				confirm-flag-name: func [
				][
					vin [{confirm-flag-name()}]
					unless parse/all to-string name value-rules/flag [
						to-error join "ARGS.r template dialect ERROR:  Invalid flag name: " to-string name
					]
					vout
				]
				
				

				;------------------------------
				;-             init()
				;----------
				; NOTE before calling init, ALL object fields MUST be filled-in
				;------------------------------
				init: func [
					/local paren
				][
					vin "init-flag()"
					
					confirm-flag-name
					
					;----------
					; support required? in flag spec
					;----------
					
					args: copy []
					
					
					
					
					
					;-----------------------------------------------------------------
					; -????? is a shadow tag which never gets linked in the system.
					; its purpose is to modify the args-ctx directly, without really
					; adding args to your spec.
					;
					; use it to set default values, without specifying any tag on the command line, for example
					unless name = '-????? [
					
						; the required? mode will be a post parse op, where we check if all required flags where specified at least
						; once in the *supplied-flags field
						append/only cmd-line-rule rule: compose/deep [(to-string name) value-rules/separator ]
						append cmd-line-rule '|

						paren: compose[vin flag-name: (to-string name)] 
						append/only rule to-paren paren 
						
						paren: compose [append args-ctx/*supplied-flags (to-lit-word name)]
						unless type = 'switch [
							append paren bind 'apply-defaults self
						]
						new-line/skip paren false 0
						paren: to paren! paren
						append/only rule paren


					]
					vout
				]
			]
			
			;-------------
			;-         arg-ctx[]
			;-------------
			arg-ctx: context [
				;-             name:
				name: none
				;-             type:
				type: 'arg
				;-             flag:
				flag: none
				;-             rule:
				rule: none
				;-             default:
				default: none
				;-             required?:
				required?: true
				;-             types:
				types: none
				
				;------------------------------
				;-             apply-default()
				;------------------------------
				apply-default: func [][
					set in args-ctx name default
				]
				
				;------------------------------
				;-             apply-arg()
				;------------------------------
				apply-arg: func [/using value][
					switch type [
						arg [
							set in args-ctx name value
						]
						switch [
							vprint "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"
							set in args-ctx name self/value
							vprobe name
							vprobe args-ctx
						]
					]
				]
				
				;------------------------------
				;-             init()
				;------------------------------
				init: func [
					/local real-type datatype paren src-rule
				][
					vin "init-arg()"
					;----------
					; NOTE before calling init, object fields must be filled-in
					;----------
					
					;-----------------------------------------------------------------
					; -????? is a shadow tag which never gets linked in the system.
					; its purpose is to modify the args-ctx directly, without really
					; adding args to your spec.
					;
					; use it so set default values, without specifying any tag on the command line, for example
					unless name = '-????? [
						; we start by creating the type rule
						
						switch type [
							arg [
								either types [
									rule: copy []
									foreach datatype types [
										;---
										; NOTE: switch list must be symmetric with all allowed 
										; types below and in spec-parsing arg-rule
										src-rule: switch datatype [
											; the switch value is a word, the return value is a datatype parse block
											integer! [ 'integer-rule ]
											decimal! [ 'float-rule   ]
											logic! [ 'bool-rule]
											text! [ 'text-rule]
											string! [ 'string-rule]
											file! [ 'file-rule]
										]
										append/only rule get in value-rules src-rule
										append rule '|
									]
									remove back tail rule
								][
									;---
									; NOTE: This list must be symmetric with switch list above and in spec-parsing arg-rule
									rule:  [integer-rule | float-rule | bool-rule | text-rule | string-rule | file-rule]
									bind rule value-rules
								]
								
								src-rule: rule
								
								paren: compose [apply-arg/using value-rules/parsed-value]
								bind paren 'paren
								
								rule: compose/only [(rule) (to-paren paren )]
								;append/only rule value-rules/separator
								unless required? [
									rule: compose/only [0 1 (rule)]
								]
								vprobe mold/all rule
								
								;---------------------
								; add error handling to value-loading rule!
								vprint "^/^/-----------------------------------------"
								vprobe rule
								
								rule: compose/only/deep [
									(
										to-paren compose [vprint (join "argument: " name)]
									)
									[
									load-error-offset: [
										(rule) 
										load-error-offset: (
											to-paren [
												vprint "RULE OK!"
												vprint load-error-offset
												;ask "?"
											]
										)
									] | [
										( 
											to-paren compose/deep [
												load-error: rejoin [ "Expecting " (mold types) " for '" (to-string name) "' argument" ]
												vprint "RULE FAILED"
												vprint load-error-offset
												;ask "!"
											print load-error
											]
										)
									 	(src-rule) ; this will always fail if first rule failed!
									]
								]]
								
								vprobe rule
								
							]
							
							switch [
								if name [
									paren: compose [ (bind 'apply-arg 'flag) ]
									rule: compose/only [ (to-paren paren)]
								]
							]
						]
					]	

					append flag/args self

					vout
				]
			]

			;--------------------------------------------------------------------
			;---                                                              ---    
			;---                DEFINE ARG SPEC PARSING RULES                 ---
			;---                                                              ---    
			;--------------------------------------------------------------------
			
			;------------------------------------
			;-         text-flag-rule:
			;
			; this is a special flag which will load up ALL character data up to 
			; the next specified flag on the command-line (or its end).
			;------------------------------------
			text-flag-rule: [
				(vout) ; previous rule failed, get out of previous vin
				(
					vin "trying text subrule"
				)
				[
					here:
					( arg-name: arg-type: arg-default: none)
					copy arg-name word!
					here-error:
					'text!
					here-error:
					copy arg-default 0 1 block!
					here-error:
					(
						current-flag: make flag-ctx [
							name: flag-name
							init
						]
						vprint "VALID ARG FOUND" 
						vprobe here
						arg-name: arg-name/1
						vprint rejoin ["add flag argument: " arg-name " of type: " arg-type " with default: " arg-default]
						new-arg: make arg-ctx [
							name: arg-name
							required?: not block? arg-default
							default: all [arg-default pick first arg-default 1]
							types: [text!]
							flag: current-flag
							init
						]
						
					)
				] 
				[
					;----------
					; if we reach end of args block, then we finalize flag
					end 
					(
					current-flag/link-args
					current-flag/register
					vprint "---"
					vprint "FLAG:"
					vprobe current-flag
					)
				]
				|
				here:
				[
					;----------
					; we didn't reach the end for some reason, this means the spec is invalid
					;-                -arg flag error
					(
						error-msg: rejoin [
							"ERROR: unexpected item in '" flag-name "' specification.  Value: " 
							mold pick here-error 1 "^/ NEAR: " 
							remove head remove back tail mold here-error
						]
						make error! error-msg
					)
				]
			]
			
			
			
			;------------------------------------
			;-         flag-rule:
			;
			; a flag is the basic building block of command line parsing.  
			;
			; each word preceded by a dash ('-') is identified as a flag.
			;
			; note that scalar values (integers, decimals, etc) which 
			; start by a minus sign are NOT considered flags so cannot be 
			; used as flag names.
			; 
			;    (note: -1e isn't a valid scalar, so its a valid flag name)
			;------------------------------------
			flag-rule: [
				[ 
					;-------------------------------------
					;-            -switch flags
					;-------------------------------------
					(
						vin "trying flag switch subrule"
						current-flag: none
						new-arg: none
					)
					'switch! [
						[
							(vprint "SWITCH!")
							(
								current-flag: make flag-ctx [
									name: flag-name
									type: 'switch
									init
								]
							)
							(
								arg-value-when-unset: arg-name
								arg-value-when-set: none
								default-value: false
								arg-value-when-set: true 
							)
							here-error: [
								; assigning the flag to an argument is optional...
								; you can just look in args-ctx/flags if that is all you need.
								0 1 [
									copy arg-name word!
									here-error:
									0 1 [ into [
										; toggle setup (two values)
										[
											; value when set
											copy arg-value-when-set 
											skip
											here-error:
											
											; value when unset
											copy default-value
											skip 
											here-error:

											
											; there musn't be more than two values
											end
											
											(
												arg-value-when-set: first arg-value-when-set
												default-value: first default-value
												
												if find ['true | 'false | 'on | 'off] default-value [
													default-value: do default-value
												]
												if find ['true | 'false | 'on | 'off] arg-value-when-set [
													arg-value-when-set: do arg-value-when-set
												]
												
												vprint "^^---^/TOGGLE-type switch flag setup" 
												vprobe arg-name
												vprint "-"
												v??  arg-value-when-set
												vprint "-"
												v??  default-value ; default value
											)
										] 
										|
										
										; boolean setup
										[
											; default value (must be boolean)
											copy default-value ['true | 'false | 'on | 'off]
											here-error:
											
											; there must not be more than one value
											end
											(
												default-value: do first default-value
												arg-value-when-set: not default-value
												
												vprint "^^---^/BOOLEAN-type switch flag setup" 
												vprobe arg-name
												vprint "-"
												v??  arg-value-when-set
												vprint "-"
												v??  default-value ; default value
											)
											
										]
										
									]]	
								]
								here-error:
								(
									; create the flag's argument if its specified and valid
									if arg-name [
										arg-name: arg-name/1
										vprint rejoin ["add flag argument: " arg-name " of type: " arg-type " with default: " arg-default]
										new-arg: make arg-ctx [
											name: arg-name
											type: 'switch
											default: default-value
											value: arg-value-when-set
											flag: current-flag
											required?: false
											init
										]
									]
									
									vprobe new-arg
								)
							]
						]
						
						[
							;----------
							; if we reach end of args block, then we finalize flag
							end 
							(
							current-flag/link-args
							current-flag/register
							vprint "---"
							vprint "FLAG:"
							vprobe current-flag
							)
						]
						|
						here:
						[
							;----------
							; we didn't reach the end for some reason, this means the spec is invalid
							;-                -switch  error
							(
								error-msg: rejoin [
									"ERROR: unexpected item in '" flag-name "' specification.  Value: " 
									mold pick here-error 1 "^/ NEAR: " 
									remove head remove back tail mold here-error
								]
								make error! error-msg
							)
						]
					]
				]|[
					;-------------------------------------
					;-            -arg flags
					;-------------------------------------
					;

					(vout) ; previous rule failed, get out of previous vin
					(
						vin "trying flag value subrule"
						current-flag: make flag-ctx [
							name: flag-name
							init
						]
					)
					some [
						here:
						( arg-name: arg-type: arg-default: none)
						copy arg-name word!
						here-error:
						copy arg-type any spec-datatypes
						here-error:
						copy arg-default 0 1 block!
						here-error:
						(
							vprint "VALID ARG FOUND" 
							vprobe here
							arg-name: arg-name/1
							vprobe arg-type
							vprint rejoin ["add flag argument: " arg-name " of type: " mold arg-type " with default: "  arg-default]
							new-arg: make arg-ctx [
								name: arg-name
								required?: not block? arg-default
								default: all [arg-default pick first arg-default 1]
								types: arg-type
								flag: current-flag
								init
							]
							
						)
					] 
					[
						;----------
						; if we reach end of args block, then we finalize flag
						end 
						(
						current-flag/link-args
						current-flag/register
						vprint "---"
						vprint "FLAG:"
						vprobe current-flag
						)
					]
					|
					here:
					[
						;----------
						; we didn't reach the end for some reason, this means the spec is invalid
						;-                -arg flag error
						(
							error-msg: rejoin [
								"ERROR: unexpected item in '" flag-name "' specification.  Value: " 
								mold pick here-error 1 "^/ NEAR: " 
								remove head remove back tail mold here-error
							]
							make error! error-msg
						)
					]
				]
				(vout)
			]
			
			;------------------------------------
			;-        type-rule:
			;-------------------------------------
			type-rule: [
				(vin)
				(
					vprint "entering subrule flag"
				)
				copy arg-default block!
				(
					vprint rejoin ["add argument: trailing-" flag-type " with default: " arg-default]
				)
				(vout)
			]
			




			;--------------------------------------------------------------------
			;---                                                              ---    
			;---                          PARSE SPEC                          ---
			;---                                                              ---    
			;--------------------------------------------------------------------
			;-        PARSE SPEC
			vprobe parse spec [
				(subrule: none) 
				any [
					here:
					(vin rejoin ["PARSING: " head replace/all mold pick here 1 "^/" " "])
					[
						copy flag-name word! ( 
							vprint "flag name detected"
							flag-name: first flag-name
							vprobe flag-name
							subrule: flag-rule 
						)
						(vout)
					]|[
						into subrule
						(vout)
					]|[
						copy flag-type datatype! (
							vprint "trailing datatype values detected"
							vprobe flag-type
							subrule: type-rule 
						)
						(vout)
					]
					here:
					(
						to-error rejoin ["ERROR, invalid template near: " mold here]
					)
				]
			]
			
			
			
			;--------------------------------------------------------------------
			;---                                                              ---    
			;---                     PARSE COMMAND LINE                       ---
			;---                                                              ---    
			;--------------------------------------------------------------------
			;-        PARSE CMD
			vprint "^/^/---------------------------------^/PARSING COMMAND LINE ARGUMENTS^/---------------------------------" 

			; remove trailing '|
			remove back tail cmd-line-rule
			
			cmd-line-rule: compose/only copy [value-rules/spacer some (cmd-line-rule)]
			vprobe mold/all cmd-line-rule
			
			
			args-ctx: context args-ctx
			; temporary
			arg-load-blk: copy []
			vprobe args
			
			;probe args-ctx
			
			unless vprobe parse/all args cmd-line-rule [
				args-ctx/*error: rejoin [
					"Command-line error in '" flag-name "' flag"
					"^/Description: " load-error
					"^/Location : "	args
					"^/         "
					head insert/dup copy "" " " index? load-error-offset 
					;#"^^"
					;"A"
					;#"^(a4)" ; ยค
					"_" #"^(18)" "_"  ; 
					"^/"
					
				]
				vprint "^/^/"
				vprint error-msg
				vprint "^/^/"
			]
			vprobe arg-load-blk
			vprobe args-ctx
			
		][
			;--------------------------------------------------------------------
			;---                                                              ---    
			;---                args-context() error recovery                 ---
			;---                                                              ---    
			;--------------------------------------------------------------------
			vprint "------------------------"
			catch-error: false
			either catch-error [
				spec-error: disarm spec-error
				vprint spec-error/arg1
			][
				spec-error
			]
		]
		args-ctx
	]
]]]






            
            
        
Copyright © 2018 Rebol Software Foundation