Euphoria Ticket #496: Add validation and conversion to cmd_parse

cmd_parse() currently always returns strings. It would be nice (and easy) to add conversion and some built in validation attributes to given options. Options should be:

  • INTEGER
  • ATOM
  • BOOLEAN
  • DATETIME, format
  • EXISTING_FILE
  • EXISTING_DIR
  • CONVERSION_RID

Example use:

sequence opts = { 
  { "w", 0, "Width of each LCD character", { HAS_PARAMETER, INTEGER } }, 
  { 0, "after", "Limit results for items created after date", { HAS_PARAMETER, DATETIME, "%m/%d/%Y" } }, 
  { 0, "template", "Template file for output", { HAS_PARAMETER, EXISTING_FILE } } 
} 

I'm sure once discussion starts up on 4.1, other attributes will come up.

Details

Type: Feature Request Severity: Normal Category: Library Routine
Assigned To: jeremy Status: New Reported Release: 4531
Fixed in SVN #: View VCS: none Milestone: 4.1.0

1. Comment by Jerome Mar 02, 2013

This ticket is already assigned but here is a first go. I didn't add DATETIME or CONVERSION_RID because I wasn't clear on the intent!

# HG changeset patch 
# User Ira Hill 
# Date 1362239222 18000 
# Node ID 653c040bbc956721d00609e3ec8951a2e505c5d6 
# Parent  e4a83317c7ce3e42603bb4aff92c945b33e6deb1 
Ticket 496: Cmd_parse updates with validation and conversion 
 
diff -r e4a83317c7ce -r 653c040bbc95 include/std/cmdline.e 
--- a/include/std/cmdline.e	Fri Mar 01 16:55:16 2013 -0500 
+++ b/include/std/cmdline.e	Sat Mar 02 10:47:02 2013 -0500 
@@ -14,8 +14,9 @@ 
 include std/sequence.e 
 include std/text.e 
 include std/types.e 
- 
- 
+include std/convert.e 
+include std/search.e 
+include std/filesys.e 
 --**** 
 -- === Constants 
  
@@ -26,6 +27,21 @@ 
 	--** This option switch does have a parameter. See [[:cmd_parse]] 
 	HAS_PARAMETER = 'p', 
  
+	--** HAS_PARAMETER option for Integer type. See [[:cmd_parse]] 
+	PARAM_INTEGER =  'I', 
+	 
+	--** HAS_PARAMETER option for Atom type. See [[:cmd_parse]] 
+	PARAM_ATOM    =  'A', 
+	 
+	--** HAS_PARAMETER option for Boolean type. See [[:cmd_parse]] 
+	PARAM_BOOLEAN =  'B', 
+	 
+	--** HAS_PARAMETER option for Existing File. See [[:cmd_parse]] 
+	PARAM_EXISTING_FILE =  'F', 
+	 
+	--** HAS_PARAMETER option for Existing Dir. See [[:cmd_parse]] 
+	PARAM_EXISTING_DIR =  'D', 
+	 
 	--** This option switch is not case sensitive. See [[:cmd_parse]] 
 	NO_CASE       = 'i', 
  
@@ -1099,6 +1115,33 @@ 
 	return { cmds, call_count } 
 end function 
  
+function convert_opt( object param, object opt ) 
+	integer loc 
+	object orig_param = param 
+	loc = find_any({PARAM_ATOM,PARAM_INTEGER,PARAM_BOOLEAN,PARAM_EXISTING_FILE,PARAM_EXISTING_DIR},opt) 
+	if (loc) then 
+		switch opt[loc] do 
+			case PARAM_ATOM then 
+				param = to_number(param) 
+			case PARAM_INTEGER then 
+				param = to_integer(param) 
+			case PARAM_BOOLEAN then 
+				param = to_integer(param) 
+				if param > 0 then param = TRUE else param = FALSE end if 
+			case PARAM_EXISTING_FILE then 
+				param = {file_exists(param), orig_param} 
+			case PARAM_EXISTING_DIR then 
+				if sequence( dir(param) ) then 
+					param = {1, orig_param} 
+				else 
+					param = {0, orig_param} 
+				end if 
+			case else 
+		end switch 
+	end if 
+return param 
+end function 
+ 
 function handle_opt( sequence find_result, integer arg_idx, sequence opts, map parsed_opts, 
 		sequence cmds, object add_help_rid, object parse_options, sequence call_count, 
 		integer validation, integer help_on_error, integer auto_help ) 
@@ -1158,10 +1201,10 @@ 
 						{find_result[2]}, opts, add_help_rid, cmds, parse_options, help_on_error, auto_help ) 
 				end if 
 			else 
-				map:put(parsed_opts, opt[MAPNAME], param) 
+				map:put(parsed_opts, opt[MAPNAME], convert_opt(param, opt[OPTIONS]))	 
 			end if 
 		else 
-			map:put(parsed_opts, opt[MAPNAME], param, map_add_operation) 
+			map:put(parsed_opts, opt[MAPNAME], convert_opt(param, opt[OPTIONS]), map_add_operation) 
 		end if 
 	end if 

Tested with the following:

-- test.ex 
include std/cmdline.e 
include std/map.e as map 
include std/pretty.e 
include std/filesys.e 
 
 
sequence option_definition = { 
    { "a", "atom",    "Give an atom",     { MULTIPLE, HAS_PARAMETER, PARAM_ATOM} }, 
    { "i", "int",     "Give an int",      { MULTIPLE, HAS_PARAMETER, PARAM_INTEGER} }, 
    { "b", "bool",    "Give a  bool",     { HAS_PARAMETER, PARAM_BOOLEAN} }, 
    { "d", "dir",     "Give a  dir",      { HAS_PARAMETER, PARAM_EXISTING_DIR} }, 
    { "f", "file",    "Give a  file",     { HAS_PARAMETER, PARAM_EXISTING_FILE} }, 
$ 
} 
 
map:map opts = cmd_parse(option_definition, NO_HELP) 
 
pretty_print(1, map:get(opts, "atom"), {3} ) 
puts(1,"\n") 
 
pretty_print(1, map:get(opts, "int"), {3} ) 
puts(1,"\n") 
 
pretty_print(1, map:get(opts, "bool"), {3} ) 
puts(1,"\n") 
 
pretty_print(1, map:get(opts, "dir"), {3} ) 
puts(1,"\n") 
 
pretty_print(1, map:get(opts, "file"), {3} ) 
puts(1,"\n") 
-- End test.ex 
 
[../source/build/test]$ ../eui test.ex -a 10.4 -a=-15.9234 -i=-11 -i 15 -b=2 -d /usr/share/euphoria -f /tmp/no_file_here.txt 
 
 
{10.4,-15.9234} 
{-11,15} 
1 
{ 
  1, 
  "/usr/share/euphoria" 
} 
{ 
  0, 
  "/tmp/no_file_here.txt" 
} 

2. Comment by SDPringle Mar 02, 2013

This gives me a larger idea; value() returns {error_code,value}. CONVERSION_ID is probably meant to be a routine id of a routine that behaves like value(). It seems more robust to offer only conversion id, and a special EUPHORIA_VALUE_RID which means use 'value()'. Then write value() like routines for parsing datetime, boolean, existig file. The value returned by these routines should be a pair with an error value because the string could be badly formed.

Search



Quick Links

User menu

Not signed in.

Misc Menu