english
version "1.0"
identify "%Z%%M% %I% %E%"

#: Copyright (c) 1992-2005 by Wayne C. Gramlich.
#, All rights reserved.

module command_parse

#: The {commands_parse} module implements a facility for scanning command
#, line options and arguments that roughly adheres to the POSIX standard.
#, Eventually, it will be made to totally adhere to the POSIX standard.
#,
#, On UNIX, broadly speaking, options are prefixed by a hyphen ("-") whereas
#, arguments are not.  POSIX compliant options have the further restriction
#, that they must be represented as a single character -- usually a letter
#, or digit.  The POSIX standard allows multiple option characters to be
#, concatonated together behind a single hyphen; for example, "-abc" is
#, equivalent to "-a -b -c".  Some options take an additional argument
#, after the option, (e. g. "-I <include file>" or "-o <output file>.)
#, Whenever options with arguments are concatoned behind a single hyphen,
#, the arguments are taken in order from left to right; for example,
#, "-IIo ifile1 ifile2 ofile" is equivalent to "-I ifile1 -I ifile2 -o ofile".
#, It is a mystery why POSIX endorsed this behavior.
#,
#, The {command_parse} module further implements a standardized help facility
#, that is not part of the POSIX standard.  A single "-?" will print a
#, terse single line summary of the acceptable command line options.  A
#, double "-??" will print a more expanded summary that contains a brief
#, description of each option and argument.  Many programs that use the
#, {command_parse} will elect to print the terse one line summary whenever
#, the no options or arguments are supplied.
#,
#, The options faciliity is used in the following steps:
#,
#,   1.	A record structure is defined that will hold the options.  By
#,	convention, the name of this type is {options}.
#,
#,   2. An {command_parse} object is created.
#,
#,   3. For each valid option or argument, an appropriate specification
#,	procedure is called to register the option/argument in the
#,	{command_parse} object.
#,
#,   4. The arguments are parsed by calling {parse@comamnd_parse} with
#,	the command line arguments supplied.  The resulting {options}
#,	object is returned.
#,
#, For example:
#,
#,	english
#,	version "1.0"
#,	
#,	module my_compiler
#,
#,	define
#,	    record options
#,		no_link logical			# -c
#,		debug logical			# -g
#,		includes vector[string]		# -I <directory> ...
#,		output_file string		# -o <output file>
#,		source_files vector[string]	# <source file> ...
#,	    generate allocate, erase, print
#,
#,	procedure main
#,	    takes
#,		system
#,	    returns unsigned
#,
#,	    # Parse command line options.
#,	    command_parse :@= create@command_parse[options]()
#,	    logical_option@(command_parse, "-c",
#,	      no_link_set@options,
#,	      'Produce a .o, do not run linker')
#,	    logical_option@(command_parse, "-g",
#,	      debug_set@options,
#,	      'Produce debugging information')
#,	    arguments_optional@(command_parse, "-I <directory>",
#, 	      includes_set@options,
#,	      'Add <directory> to include file search path')
#,	    argument_required@(command_parse, "-o <output file>",
#,	      output_file_set@options,
#,	      'Store output into <output file>')
#,	    arguments_required@(command_parse, "<source file>",
#,	      source_files_set@options,
#,	      'Source file to compile')
#,	    options :@= parse@(command_parse, system.arguments)
#,	    ...


# {command_parse} procedures:

procedure create@command_parse[options]
    takes
	program_name string
    returns command_parse[options]

    #: This procedure will create and return an {command_parse} object.


procedure parse@command_parse[options]
    takes
	command_parse command_parse[options]
	command_arguments vector[string]
	out_stream out_stream
	exit_on_error logical
	print_usage logical
    returns options
    needs
	procedure allocate@options
	    takes_nothing
	    returns options

    #: This procedure will parse all of the arguments in {command_arguments}
    #, and store the result in a new {options} object which is returned.
    #, Any errors are output to {out_stream}.  If either "-?" or "-??"
    #, are specified, a help message is output to {out_stream}.  If
    #, {exit_on_error} is {true@logical}, this procedure will exit if
    #, any errors are encountered; otherwise, the new {options} object is
    #, returned.


procedure help_print@command_parse
    takes
	out_stream out_stream
	help_count unsigned
	name_size_max unsigned
	prefix string
	name string
	suffix string
	help string
    returns_nothing

    #: This procedure will print a help message to {out_stream}.


# These routine insert rules into {command_parse}.

procedure argument_optional@command_parse[options]
    routine_types
	procedure value_set
	    takes options, string
	    returns_nothing
    takes
	command_parse command_parse[options]
	name string
	help string
	value_set value_set
    returns_nothing

    #: This procedure specifies that an optional argument named {name}
    #, is an acceptable command on the line.


procedure argument_required@command_parse[options]
    routine_types
	procedure value_set
	    takes options, string
	    returns_nothing
    takes
	command_parse command_parse[options]
	name string
	help string
	value_set value_set
    returns_nothing

    #: This procedure specifies that a required argument named {name}
    #, is valid.


procedure arguments_optional@command_parse[options]
    routine_types
	procedure value_set
	    takes options, vector[string]
	    returns_nothing
    takes
	command_parse command_parse[options]
	name string
	help string
	value_set value_set
    returns_nothing

    #: This procedure specifies that a list of arguments named {name}
    #, is valid.  The user may supply zero, one, or more.


procedure arguments_required@command_parse[options]
    routine_types
	procedure value_set
	    takes options, vector[string]
	    returns_nothing
    takes
	command_parse command_parse[options]
	name string
	help string
	value_set value_set
    returns_nothing

    #: This procedure specifies that list of arguments named {name}
    #, is valid.  At least one must be supplied on the command line.


procedure option_argument_optional@command_parse[options]
    routine_types
	procedure value_set
	    takes options, string
	    returns_nothing
    takes
	command_parse command_parse[options]
	name string
	help string
	value_set value_set
    returns_nothing

    #: This procedure specifies that an optional argument named {name}
    #, is valid.


procedure option_argument_required@command_parse[options]
    routine_types
	procedure value_set
	    takes options, string
	    returns_nothing
    takes
	command_parse command_parse[options]
	name string
	help string
	value_set value_set
    returns_nothing

    #: This procedure specifies that an option argument named {name}
    #, is both valid and required.


procedure option_arguments_optional@command_parse[options]
    routine_types
	procedure value_set
	    takes options, vector[string]
	    returns_nothing
    takes
	command_parse command_parse[options]
	name string
	help string
	value_set value_set
    returns_nothing

    #: This procedure specifies that a list of arguments named {name}
    #, is valid.  The user may supply zero, one, or more.


procedure option_arguments_required@command_parse[options]
    routine_types
	procedure value_set
	    takes options, vector[string]
	    returns_nothing
    takes
	command_parse command_parse[options]
	name string
	help string
	value_set value_set
    returns_nothing

    #: This procedure specifies that a list of arguments named {name}
    #, is valid.  The user may supply zero, one, or more.


procedure option_count@command_parse[options]
    routine_types
	procedure value_set
	    takes options, unsigned
	    returns_nothing
    takes
	command_parse command_parse[options]
	name string
	help string
	value_set value_set
    returns_nothing

    #: This procedure specifies that an optional argument named {name}
    #, is valid.


procedure option_logical@command_parse[options]
    routine_types
	procedure value_set
	    takes options, logical
	    returns_nothing
    takes
	command_parse command_parse[options]
	name string
	help string
	value_set value_set
    returns_nothing

    #: This procedure specifies that an optional argument named {name}
    #, is valid.


procedure rule_append@command_parse[options]
    takes
	command_parse command_parse[options]
	name string
	help string
	data command_rule_data[options]
    returns_nothing

    #: This procedure will create a {command_rule} from {name}, {help}, and
    #, {command_rule_data} and append it to the rules in {command_parse}.