ECA_Opt Tutorial

This is a quick tutorial that shows how to use ECA_Opt. I will start with a simple “Hello World!” program that takes a single option, and then add some more options and embellish it in ways that make it clear how to use most of the features of ECA_Opt.

What you will need

You will need the current version of ECA_Opt which is contained in the header file eca_opt3.h and the source file eca_opt3.c. If you don’t already have them, download those files and put them in a directory somewhere. If you are not reading this file on fish-dna-math.homeunix.net then those links won’t work, but know that the source and header file are in the src directory of the ECA_Opt download archive. I am going to put those two files in a directory called: ECA_Opt_Tutorial. For the purposes of this tutorial, we’ll just assume those files are in the current working directory so that we don’t have to do anything fancy for the compiler to find them.

Some familiarity with the programming language C will be helpful too, since that is the language used.

A basic Hello World program with no options

We’ll start with a simple program that everyone is familiar with—your basic Hello World program:

#include <stdio.h>
 
int main(void)
{
  printf("Hello World!\n");
  return(0);
}

That is a pretty limited little program. It doesn’t interact with the user at all. We’ll add a simple feature in the next section.

Hello -Name-!

Here we will expand the program a little bit so that if the user uses the command line option -N Fred, for example, it will print “Hello Fred!” instead of “Hello World!”. However, we will leave the default behavior to be simply printing “Hello World!”. Here is how we will do it with ECA_Opt:

  1. main must be declared with parameters (int argc, char *argv[]). This is pretty standard. When the system enters function main in this case, the variable argc within main will hold the number of command line arguments, and argv is an array of strings, each element holding one of the command line arguments.
  2. We will use a separate function to collect the options for our program. Let’s call this option GetHelloOpts. Within in this function is where all the ECA_Opt related code will go. Since this is where we parse the command line, we will have to pass argc and argv into this function, and we will pass in some other output parameters which we will use to get input back out of the function. GetHelloOpts can be a function that returns any arbitrary type or void. NOTE! The variables that contain the number of command line arguments and the arguments MUST be named argc and argv in the function within which the command line gets parsed.
  3. We will use just a minimum of the features of ECA_Opt.

The source file hello_single_option.c shows how this is done. A listing of the file appears below. Things in UPPERCASE turquoise are ECA_Opt macros. The relevance of everything is explained in the comments in the source code.

#include <stdio.h>
#include <string.h> /* we might need some string functions */
#include "eca_opt3.h" /* gotta include this header file */
 
void GetHelloOpts(
		  int argc, 
		  char *argv[], 
		  char *Name  /* output parameter for returning the name */
		  )
{
 
  int Name_f=0;  /* Serves as a counter for the number of times the "name" option is invoked on the command line.
		    Must be initialized to 0 */
 
  DECLARE_ECA_OPT_VARS   /* macro that declares necessary variables for ECA_Opt 
			    This must occur after all other variable declarations in the function 
			    and before any other code gets executed in the function */
 
  /* This is a good place to set some default values for variables in your program */
  sprintf(Name,"World");   /* <-- Default name is World, so it says Hello World */
 
  BEGIN_OPT_LOOP  /* macro that prepares a loop for cycling over command line arguments, and
                         does a bunch of other stuff too related to outputting documentation */
 
 
    /* OPTION is a macro that takes parameters.  It is a macro that returns a 0 or a 1.  It 
     gets executed on each loop through the "OPT_LOOP" and tokens on the command line are
    compared to it. In this case, if the token is a -N or a --name, then OPTION returns a 1.
    In such a case, the code within the "if" block below it executes.  This is where we put
    in code to extract the name following -N or --name off the command line.  In general the 
    macro OPTION and its derivatives should be tested by "if".*/  
    if( OPTION(
	   Whom To Welcome,   /* ENGLISH_NAME */
	   Name_f,            /* USAGE_COUNTER */
	   N,                 /* SHORT -- i.e. short option tag.  will be "-N"  */
	   name,              /* LONG -- i.e. long option tag.  will be "--name" */
	   S,                 /* ARGS -- i.e. what type of argument does it take (a string--S) */
	   name of person to greet,  /* SHORT_COMMENT */
	   Name of person to greet.  S should be a string which is a the name of a person 
	   that you want the program to say welcome to.  If no name is given\054 then the 
	   program will default to Hello World!  This option may only be
	   issued a single time.  /*  LONG_COMMENT */
	   )
	) {
      
      if(ARGS_EQ(1)) {  /* this little macro tests to make sure that there is, in this case
			   only 1 argument to the -N option.  If so, it returns 1.  If not,
			   it returns 0, prints an error informs ECA_Opt that program execution
			   should terminate */
	
	GET_STR(Name);  /* if we get down here, we know that the option -N has only a single 
			   argument, so we grab that argument off the command line as a string
			   and copy it to the variable Name */
      }
    }
 
 
 
  END_OPT_LOOP   /* Macro that closes the Main ECA_Opt Loop and does some error checking 
			  behind the scenes */
 
    
}
 
int main(int argc, char *argv[])  /* notice the two arguments---no longer just void */
{
  char name_str[1000];  /* hope that no one enters a name longer than 1000 characters */
 
  /* here we call GetHelloOpts.  When it is through, name_str holds the name that
     we will greet with the program */ 
  GetHelloOpts(argc, argv, name_str);
 
  
  printf("Hello %s!\n",name_str);
 
  return(0);
}

About the OPTION macro and its relatives

The OPTION macro is the main tool used to establish and document a command line option. You can find it in eca_opt3.h. To use it, it is often easiest to copy it from eca_opt3.h and paste it into your document:

#define OPTION(ENGLISH_NAME,USAGE_COUNTER,SHORT,LONG,ARGS,SHORT_COMMENT,LONG_COMMENT)

then change the parameters to the values you wish them to be. The parameters are as follows:

  • ENGLISH_NAME This is the name that you would give to the option if you were just speaking plain English and not code-ese. It is also the title that will be given to the option in the GuiLiner option tree.
  • USAGE_COUNTER This should be an integer, initialized to zero, that is declared within the scope of the function where you are using ECA_Opt’s main loop that is contained within the BEGIN_OPT_LOOP / END_OPT_LOOP pair. It is used to count the number of occurrences of the flag for this particular option. In this case, if that number is greater than 1, then the program issues an error. With the MULT_USE_OPTION and the MULT_USE_REQ_OPTION macros, the number of occurrences of the option’s flag can be greater than 1.
  • SHORT This is a single character that defines the “short” flag for this option. For example, if you set this parameter to the character “N” then this option could be invoked with the flag -N on the command line. The “short” format of an option flag is always just a single dash followed by a single letter. It has to be an alphabetical letter. IMPORTANT NOTE! You do not enclose the parameter value in any quotation marks! It gets quoted using the string paste-izer. Please don’t pass in a non-letter character for this parameter. That oughtn’t work.
  • LONG This is a word composed of characters, that can be digits or alphabetical characters or other characters that don’t have special significance in the shell. I recommend restricting yourself to alphabetical letters and the hyphen. This parameter is used to make the “long” version of the option flag. The “long” version is a word that is preceded by two dashes. In passing in this parameter the user does not pass the preceding dashes in. So, for example if the parameter value were: “name” then the long option flag associated with this option would be “--name”. AGAIN! You do not enclose the parameter value in any quotation marks! It gets quoted using the string paste-izer.
  • ARGS This is an unquoted string describing the expected format of the arguments to this option. These formats are used to provide documentation in the --help options and it determines the type of panel that will be requested in the GuiLiner XML file. There are currently 7 types of arguments that are expected. Each expected argument is named by a word starting with a first letter which denotes what type of argument it is and followed by 0 or more letters or numbers that can be used to describe the argument. The 7 expected types, named by the initial letters that signify them are:
    1. F : a file path. Example: infile.txt
    2. D : a directory path. Example: /Users/eriq/MyCode/
    3. J : an integer. Example: 18
    4. R : a real number. Example: 2.718
    5. S : a string. Example: yippie or it may be a quoted string like: “This is a quoted string argument”
    6. G : a range. This signifies a range of integers like you might use with the unix cut utility. Example: 1,5-10,17
    7. C : a choice or a “constrained string”. This signifies an argument that can take a small set of possible string options. The possible choices should be listed between curly braces and separated by pipes immediately following the C-word naming the argument. This would look like, for example: C1{boing|bong|foo|bar|100}. For example, suppose you have an option to your program called --looking-for that wants to gather from the user whether they are looking for a male/female who is tall/short with between a minimum age and a maximum age that can be specified as a real number. Then you might do an ARGS string that looked like: Csex{male|female} Cheight{tall|short} R_min_age R_max_age. Again, don’t quote these.
  • SHORT_COMMENT This is the text that you would like to appear in the short help format (obtained by invoking the program with the --help option). This also appears in blue in the GuiLiner information window for the option. Typically about 50 characters or less giving a quick description of the option. Remember this is an unquoted string and BEWARE OF COMMAS (see below).
  • LONG_COMMENT This is the text that you want to appear in the long version of the documentation. This should provide a full description of the option. It will come out with the --help-full, --help-nroff, and --help-xml options. It will appear in the information window in GuiLiner. Remember this is an unquoted string and beware of commas (see below).

A Word About Commas

Note: this macro and the related ones make heavy use of the preprocessor’s “string-pasteizer”, which means that if you are supplying a string argument to it, you leave that string unquoted. There is one nasty problem with this: if the string you are supplying includes a comma, it is going to completely screw up the macro (the preprocessor will interpret the comma as something that is separating macro parameters). The handy way around this is to use the backslash-preceded ascii code for the comma: \054. For example, if you were documenting an option in the LONG field and you wanted to say, “This option is sometimes useful, sometimes not.” You would supply the unquoted string: This option is sometimes useful\054 sometimes not. There are other times you may wish to use the octal code for punctuation; sometimes it is necessary to put in an unmatched parenthesis \050 or \051 or quotation marks: \042, etc.

Running the program

Let’s compile it up into a.out

/ECA_Opt_Tutorial/--% gcc hello_single_option.c eca_opt3.c

(Note that the part in yellow-green is my command prompt).

Then we can run it with no options:

/ECA_Opt_Tutorial/--% a.out
Hello World!

Or we can pass it the -N/--name option:

/ECA_Opt_Tutorial/--% a.out -N Fred
Hello Fred!
/ECA_Opt_Tutorial/--% a.out --name Frank
Hello Frank!

Getting Documentation about this program

We can also give the --help option:

/ECA_Opt_Tutorial/--% a.out --help

which returns this:

Please Supply Program Name with SET_PROGRAM_NAME macro  --  Please Supply Short Description with SET_PROGRAM_SHORT_DESCRIPTION macro



     --help                                  short listing of options
     --help-full                             long listing of options
     --help-nroff                            long listing of options in nroff man-page format
     --help-xml                              output all options in XML format (in development)
     --version                               prints program version information
     --version-history                       prints history of different versions
     --command-file           F              inserts contents of file F into the command line
-N , --name                   S              name of person to greet

This shows all the options that are available to us. The first 7 are options that come automatically when you use ECA_Opt. The one that we have created is at the bottom. The SHORT_COMMENT documentation goes to the right of each option.

Notice the line:

Please Supply Program Name with SET_PROGRAM_NAME macro  --  Please Supply Short Description with SET_PROGRAM_SHORT_DESCRIPTION macro

This tells us that we can (and should) supply a name and description for the program. We’ll explore that more in the section program_name_description_author_versions.

Let’s check out the --help-full option, which will give us the LONG_COMMENT documentation:

/ECA_Opt_Tutorial/--% a.out --help-full

returns:

Please Supply Program Name with SET_PROGRAM_NAME macro

  --  Please Supply Short Description with SET_PROGRAM_SHORT_DESCRIPTION macro



Author(s):
	

  --- Please Supply Author String with SET_PROGRAM_AUTHOR_STRING macro --- 



About the Program:
    --- Developer! Please Supply Long Description with SET_PROGRAM_LONG_DESCRIPTION
    macro ---

In the following:
	"J" refers to an integer argument to an option

	"R" refers to a real number argument to an option

	"S" refers to a string argument to an option

	"F" refers to a file path argument to an option. For example,
		"datfile.txt" if the file is in the current working directory, or
		something like "~/eriq/Documents/data/datfile.txt" if you want to
		provide a complete file path.  (Beware of spaces in file paths!)

	"D" refers to a directory path argument to an option. For example,
		"data_direcory/" if the directory is in the current working directory, or
		something like "~/eriq/Documents/data_directory/" if you want to
		provide a complete directory path.  Note that the trailing slash should be
		optional, but currently is not.  (ERIC ADD MACROS FOR GETTING FILES AND DIRECTORIES

	"G" refers to a string that gives a (possibly) discontinous range of
		nonnegative integers.  For example:  "1-5,7,9,10-15" specifies
		the integers 1 through 5, 7, 9, and 10 through 15.  There can be no
		whitespace in the string specifying the range, and the numbers must all
		be increasing.  Also, the string cannot start nor end with a comma or a dash.
		Finally, you should not use "-" to denote two ranges without placing any
		commas in between.

	"C" refers to a "constrained" string argument to an option,
		i.e., the argument is a string that may only be drawn from a small
		set of alternatives, as specified in the help-full description.

   ****  Program-description and documentation  parameters  ****

     --help                   
        this returns a short list of all program options and associated
        arguments

     --help-full              
        this returns a full list of all program options and associated
        arguments

     --help-nroff             
        this returns a full list of all program options and associated
        arguments using the formatting styles in nroff that give you the look
        of a man page. View the formatted ouput by doing: 'prog --help-nroff
        | nroff -man | more' where prog is the name of the program.

     --help-xml               
        This returns a list of all options in a simple XML format which is
        suitable for input to the guiLiner front end.

     --version                
        prints program version information

     --version-history        
        prints history of different versions

     --command-file           F
        By using this option you can store command line arguments in the file
        named in F. You may have any kind of white space (including line
        endings) in the file. The line endings are treated as just another
        space. Comments may be included in the file by enclosing them within
        a pair of ampersands (the & character). Note that you must have a &
        at the beginning and at the end of the comment. You cannot use just a
        single & to comment to the end of a line. Your comments may spread
        over several lines---they will still be stripped from the resulting
        command line so long as the are enclosed in ampersands. This feature
        is helpful if you have long and complex command lines that you wish
        to store if it makes it easier to read the command line by breaking
        it across multiple lines or if you have certain clusters of options
        that you like to store together as a module. This option may be used
        up to 10000 times. Optional.

-N , --name                   S
        Name of person to greet. S should be a string which is a the name of a
        person that you want the program to say welcome to. If no name is
        given, then the program will default to Hello World! This option may
        only be issued a single time.

The --help-nroff option gives all the same info, but in Unix man page option. Try doing:

/ECA_Opt_Tutorial/--% a.out --help-nroff | nroff -man | less

If you have nroff and less on your system you should get some nice output.

Program Name, Description, Author, Versions

Here, we will add some information to the program. This involves just adding a few lines immediately before the BEGIN_OPT_LOOP macro:

[...]
 
  /* some information about the program, author, etc */
  SET_PROGRAM_NAME("hello_single_option_MoreInfo");  /* Note:  QUOTED string */
  SET_PROGRAM_SHORT_DESCRIPTION("Illustrate ECA_Opt and program description"); /* QUOTED string */
  SET_PROGRAM_LONG_DESCRIPTION(This is just a little program I whipped up to illustrate 
                               a few things about ECA_opt in the tutorial.  I hope
                               someone actually uses this code. It has proven useful for me.
                               Note that if you want a comma\054 then you use the octal code 054
                               preceded by a backslash.);  /* UN-QUOTED string! */
  SET_PROGRAM_AUTHOR_STRING("Eric C. Anderson"); /* QUOTED string */
  SET_VERSION("Version 1.0");  /* QUOTED string */
  SET_VERSION_HISTORY("Version 1.0 written Nov. 8, 2007\nVersion 0.0 conceived days before.\nblah, blah..."); /*QUOTED string */
 
 
  BEGIN_OPT_LOOP  /* macro that prepares a loop for cycling over command line arguments, and
                         does a bunch of other stuff too related to outputting documentation */
[...]

The source code file with these changes is in hello_single_option_moreinfo.c. Compile it up and see now a little difference when you do --help or help-full

A More Complex Example

OK, now we are going to get a little more complex. Here is what we will add:

  1. A REQUIRED option -l or --language that chooses the language from amongst english, italian, spanish, or other. If the user chooses other then he will be required to specify what word or phrase should be used in place of “Hello” by using the --define-salutation option. Note that the --define-salutation option is not going to have a short option flag (like -d).
  2. We are also going to allow -N/--name to be invoked multiple times, each time providing a different name. And, in fact, now we will require that the -N option be issued at least once. It will be a required option.
  3. We will add another option called -r or --repetitions which takes integer arguments telling us how many times to replicate the “Hello XXX” phrase (or its italian, spanish, or other equivalent) for each person named with a -N/--name option. This is a little tricky because the number of arguments required depends on how many times the -N option has been issued. Therefore we will have to check to make sure that no more -N options are issued on the command line after this -r option, and we have to check that at least one -N option has already been issued. This will not be a required option. By default, everything will get printed once.
  4. Then we will have an unrelated option (which we will put in a different subset of options) called --sum-or-prod that would be invoked like
    --sum-or-prod  sum 12.4  34.2 12.2

    or

    --sum-or-prod  product 234.3 343 9944.1 838.3 883.4

    and which will return the sum or the product of the numbers following it on the command line. The interesting part here is that it can have a variable number of arguments so long as it has two or more arguments.

Listing of the source code

Here is what the whole source code file looks like. By reading the comments, you should gain more understanding of how the different macros are used:

#include <stdio.h>
#include <string.h> 
#include <stdlib.h>
#include "eca_opt3.h" /* gotta include this header file */
 
/* some constants for declaring arrays */
#define MAXNAMES 1000
#define MAXNAMELENGTH 1000
 
 
void GetHelloOpts(
		  int argc, 
		  char *argv[], 
		  char **name_array,  /* output parameter for returning the names */
		  int *NumNames, /* output parameter for number of names used */
		  char *Salutation, /* output parameter for salutation.  Depends on language or is defined by user */
		  int *Reps, /* array to output number of reps for each name */
		  int *SumProdInvoked,  /* output parameter to announce if the --sum-or-prod option was invoked */
		  double *Result /* for returning the results of the sum-or-prod calculation */
		  )
{
  int i;
  
  int Name_f=0,  /* Serves as a counter for the number of times the "name" option is invoked 
		    Must be initialized to 0 */
    salutation_f=0, /* counter for --define-salutation option */
    language_f=0, /* counter for -l option */
    reps_f=0,    /* counter for -r option */
    sumprod_f=0; /* counter for --sum-or-prod option */
 
  DECLARE_ECA_OPT_VARS  
 
 
 
  /* This is a good place to set some default values for variables in your program */
  *NumNames = 0;  /* initialize this to 0 */
  for(i=0;i<MAXNAMES;i++) { Reps[i]=1; } /* establish the default number of reps. */
  *SumProdInvoked=0;
	  
 
  /* some information about the program, author, etc */
  SET_PROGRAM_NAME("hello_more_complex");  /* Note:  QUOTED string */
  SET_PROGRAM_SHORT_DESCRIPTION("Illustrate ECA_Opt and program description"); /* QUOTED string */
  SET_PROGRAM_LONG_DESCRIPTION(This is just a little program I whipped up to illustrate 
			       a few things about ECA_opt in the tutorial.  This particular
			       program has an example of a more complicated set of options\054
			       some of which are dependent on others\054, etc.);  /* UN-QUOTED string! */
  SET_PROGRAM_AUTHOR_STRING("Eric C. Anderson"); /* QUOTED string */
  SET_VERSION("Version 1.0");  /* QUOTED string */
  SET_VERSION_HISTORY("Version 1.0 written Nov. 8, 2007\nGrew out of simpler programs.\nblah, blah..."); /*QUOTED string */
 
 
  BEGIN_OPT_LOOP  
 
 
    /* use this to start a block of related options.  Close the block with the CLOSE_SUBSET macro (below)  */
    OPEN_SUBSET(Options Dealing With the Greeting Part of The Program,  /* Name of Subset for output in --help, --help-full, and --help-nroff */
		 Greeting Options, /* Name of subset for lumping them together in GuiLiner */
		 These options all have to do with the semi-Hello-World aspect of the program /* Description of subset.  Not really used currently */
		)   /* NOTE.  These are all UNQUOTED strings.  Beware of commas. */
 
    /* here is the language option See that it is required. */
    if(REQUIRED_OPTION(
	   Language,
	   language_f,
	   l,
	   language,
	   C{english|italian|spanish|other},  /* using the C, or "constrained string" arg specifier.
					       all the stuff in braces really only gets used in the --help-xml output
					      for designing the GUI. */
	   select what language to use,
	   Follow this option flag with one of: english\054 italian\054 spanish\054 or other.  It will determine how the
	      program says Hello.  If you want the program to say hello in some other way\054 use other.  Doing so
	   will then make the --define-salutation option mandatory.
	   )
       ) {
      if(ARGS_EQ(1)) {char lang[1000];
      
          GET_STR(lang);  /* You pull the response off the command line as a string
			 ECA_Opt does not have a facility for testing choices.  That must be
			 done by you! */
	  if(strcmp(lang,"english")==0) {
	    sprintf(Salutation,"Hello");
	  } 
	  else if(strcmp(lang,"italian")==0) {
	    sprintf(Salutation,"Buon Giorno");
	  }
	  else if(strcmp(lang,"spanish")==0) {
	    sprintf(Salutation,"Buenos Dias");
	  }
	  else if(strcmp(lang,"other")==0) {
	    sprintf(Salutation,"NeedsDef"); /* we will use this as a flag that tells us the user needs to define it */
	  }
	  else {
	    fprintf(stderr,"Unrecognized choice %s given in option -l/--language.  Must be english, italian, spanish, or other.  Exiting...\n",lang);
	    exit(1);
	  }
      }
    }
    
	
	
	
	
    /* Look! We used MULT_USE_REQ_OPTION instead of OPTION.  Program now exits with error if this option is not used, and the
     option can be invoked MAX_USES times. */
	/* Format for this macro: MULT_USE_REQ_OPTION(ENGLISH_NAME,USAGE_COUNTER,SHORT,LONG,ARGS,SHORT_COMMENT,LONG_COMMENT, MAX_USES) */
    if( MULT_USE_REQ_OPTION(
	   Whom To Welcome,   /* ENGLISH_NAME */
	   Name_f,            /* USAGE_COUNTER */
	   N,                 /* SHORT -- i.e. short option tag.  will be "-n"  */
	   name,              /* LONG -- i.e. long option tag.  will be "--name" */
	   S,                 /* ARGS -- i.e. what type of argument does it take (a string--S) */
	   name of person to greet,  /* SHORT_COMMENT */
	   Name of person to greet.  S should be a string which is a the name of a person 
	   that you want the program to say welcome to.  If no name is given\054 then the 
	   program will default to Hello World!  This option may be issued multiple times.  Each 
	   time it adds another name to say hello to.  It can be used no more than MAXNAME times.,
	   MAXNAMES       /* MAX_USES -- the most times this option can be issued without causing ECA_Opt to shut it down and exit */
	   )
	) {
      
      if(ARGS_EQ(1)) {  /* this little macro tests to make sure that there is, in this case
			   only 1 argument to the -N option.  If so, it returns 1.  If not,
			   it returns 0, prints an error informs ECA_Opt that program execution
			   should terminate */
			   
		if(!HAS_BUT_SHOULD_NOT(reps_f,-r/--repetitions)) {  /* check to make sure this isn't being given after the -r option.
		                                                    If so, this will cause program to exit with error.  Note that you have to
                                                            negate it with the ! */
 	
			name_array[*NumNames]=(char *)calloc(MAXNAMELENGTH, sizeof(char));  /* allocate some memory to store the name */
			GET_STR(name_array[*NumNames]);  /* get the name off the command line */
			(*NumNames)++; /* increment the NumNames counter */
		}
      }
    }
 
 
	if(OPTION(
		Number Of Reps,
		reps_f,
		r,
		repetitions,
		J1 J2 ...,
		Number of times to repeat salutation for each name,
		Number of times to repeat salutation for each name.
		This option takes an integer for every different name that you have put on the command
		line using the -N/--name option.  Once you issue this option\054 you cannot issue any
		other -N options.  The number of arguments must match the number of uses of the -N option.
		If not\054 the program will exit.  
		)
	  )
	  {
		if(ALREADY_HAS(Name_f,"-N/--name")) {  /* make sure the -N option has been issued at least once */
			if(ARGS_EQ(*NumNames)) {int i;   /* check to make sure you have the right number of arguments */
				for(i=0;i<*NumNames;i++)  {  /* cycle over all those integer arguments  */
					Reps[i] = GET_INT;  /* collect each integer off the command line with this macro */
				}
				
			}
		}
	  }
	  
	  
	  
	  
  /* format for this macro: COND_REQ_OPTION(ENGLISH_NAME,USAGE_COUNTER,SHORT,LONG,ARGS,SHORT_COMMENT,LONG_COMMENT, WHEN_REQUIRED, CODEPEND_STATEMENT) */	  
  if(COND_REQ_OPTION(  
	Custom Salutation,
	salutation_f,
	,  /* note -- no SHORT name so you just leave it blank */
	define-salutation,
	S,
	Customize the greeting.,
	Customize the greeting.  The string S will be used to replace Hello.  This option may only be given after the -l/--language option\054
	and then only if \042other\042 was chosen.  If  \042other\042 was chosen in the -l option\054 then this option becomes required.,
	strcmp(Salutation,"NeedsDef")==0,  /* WHEN_REQUIRED: Recall, we used the fact that Salutation=="NeedsDef" as a flag to this option is required */ 
	when you have given the argument of \042other\042 to the -l/--language option   /* CODEPEND_STATEMENT -- for error message saying it is required */
	)) {
		if(ALREADY_HAS(language_f,-l/--language)) {  /* this must come after the -l option */  
			if(strcmp(Salutation,"NeedsDef")==0) {  /* make sure they chose the "other" choice in the --language option */
				if(ARGS_EQ(1)) {
					GET_STR(Salutation);  /* collect the desired salutation off the command line */
				}
			}
			else {  /* give an error message if they chose something other than "other" */
				fprintf(stderr,"Error!  You issued the --define-salutation option, but you did not choose the \"other\" choice in the -l/--language option.  You must choose \042other\042 to use this option.  Exiting...\n");
				exit(1); 
			}
		}
	}
	
  CLOSE_SUBSET;  /* done with the greeting-related options */
  
  OPEN_SUBSET(Totally unrelated option, 
			  Unrelated option,
			  These options are totally unrelated )
			  
  if(OPTION(
	  Sum or product,
	  sumprod_f,
	  ,
	  sum-or-prod,
	  C{sum|product} R1 R2 ...,
	  ask for the sum or the product of the following real numbers,
	  Ask for the sum or the product of the following real numbers.  C must be one of 
	  \042sum\042 or \042product\042.  (no quotation marks\054 though!) R1 R2 ... are an
	  arbitary number (but at least one) of real numbers that you want to have the sum
	  or the product of))
	  {
		if(ARGS_GEQ(2))  {  char temp[1000]; int n; /* if there are 2 or more arguments */
			*SumProdInvoked=1;  /* set a flag announcing that this option was correctly invoked */
			GET_STR(temp);  /* get the string that is the user's choice input */
			n=COUNT_ARGS;  /* count number of argument to this option that are now left on the command line */
			if(strcmp(temp,"sum")==0) {  /* if it wants the sum...*/
				*Result=0.0;  /* initialize to accumualate a sum */
				for(i=0;i<n;i++)  {
					*Result += GET_DUB;  /* collect the next string off the command line, convert to a double, and add to Result */
				}
			}
			else if(strcmp(temp,"product")==0) { /* if it wants the product...*/
				*Result=1.0;  /* initialize to accumualate a product */
				for(i=0;i<n;i++)  {
					*Result *= GET_DUB;  /* collect the next string off the command line, convert to a double, and multiply to Result */
				}
			}
			else {
				fprintf(stderr, "Unrecognized choice %s as first argument to option --sum-or-prod.  Expecting \"sum\" or \"product\".  Exiting...\n",temp);
				exit(1);
			}
		}
	  }
			  
  CLOSE_SUBSET;
 
  END_OPT_LOOP   /* Macro that loses the Main ECA_Opt Loop and does some error checking 
			  behind the scenes */
 
    
}
 
int main(int argc, char *argv[])  /* notice the two arguments---no longer just void */
{
  int i,j;
  char *name_array[MAXNAMES]; 
  int NumNames;
  char Salut[1000];
  int Reps[MAXNAMES];
  double Res;
  int SumProdFlag;
 
 
  /* here we call GetHelloOpts.  When it is through, name_str holds the name that
     we will greet with the program */ 
  GetHelloOpts(argc, 
	       argv, 
	       name_array,
	       &NumNames,
	       Salut,
	       Reps,
		   &SumProdFlag,
	       &Res
	       );
 
  
  /* now print all the stuff */
  for(i=0;i<NumNames;i++)  {
	for(j=0;j<Reps[i];j++)  {
		printf("%s %s!\n",Salut, name_array[i]);
	}
	printf("\n");
  }
 
  /* if indicated, print the sum-or-prod result  */
  if(SumProdFlag) {
	printf("\n\nThe Result of Summing or Multiplying is %f\n\n",Res);
  }
  
  return(0);
}

You’ll notice a few new macros in there like ALREADY_HAS, HAS_BUT_SHOULD_NOT, COUNT_ARGS, and GET_INT. All these macros are documented in the Doxygen documentation for eca_opt.h.

 
software/eca_opt/eca_opt_tutorial.txt · Last modified: 2007/11/13 13:14 by eriq
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki