Input arguments with C++ | Unix Linux Forums | Programming

  Go Back    


Programming Post questions about C, C++, Java, SQL, and other programming languages here.

Input arguments with C++

Programming


Closed Thread    
 
Thread Tools Search this Thread Display Modes
    #1  
Old 01-16-2013
kristinu kristinu is offline
Registered User
 
Join Date: Dec 2009
Last Activity: 29 August 2014, 3:38 AM EDT
Posts: 844
Thanks: 59
Thanked 8 Times in 8 Posts
Input arguments with C++

I am using getopt_long to pass arguments to a C++ program. Arguments are passed with a key and a value separated by a space of '=' sign. Some options do not need to assign a value to them.

Example:


Code:
./raytrac dist=0.3 --color

I have some classes that need to use some of these parameters ant created a class Parsing to handle the arguments passed from argv.


Code:
   bool  Parsing::get_int
   bool  Parsing::get_float
   bool  Parsing::get_vect2
   bool  Parsing::get_string

Then if a class (let us say Tomog) needs those parameters I call


Code:
Tomog::set_param(Pc)

Where Pc is of class Parsing. Pc is a list associating a key with the corresponding argument. If the key matches you get the value.

Example


Code:
    float f;
    if (Pc.get_string("--dist",f)) {

Hence if the user passed --dist=0.3, f will contain the value 0.3

I am wondering what people think about this system of passing command line variables. And suggestions if there are better ways to do this.

Some more details of Tomog::set_param is given below




Code:
void Tomog::set_param (
  Parsing&  Pc
) {

  int  i;
  int  nf;

  String  s;
  String  T;

    if (Pc.get_string("--lglvl",s)) {
    if ( !get_log_level(s, lglvl) ) {
      error("invalid value for --lglvl");
    }
    cerr << "Tomog::set_param, --lglvl = " << s << endl;
  } else {
    lglvl = normal;
    cerr << "Tomog::set_param, --lglvl = normal = " << lglvl << endl;
  }
float f;
 if (Pc.get_float("--dist", f)) {
    nf = s.nfields(':');
    if (nf < NLayers) {
      error ("value for --nzs is less than the number of layers");
    }
    cerr << "Tomog::SetParam, nzs = " << s << endl;
    for (i = 0; i < NLayers; i++) {
      T = s.get_token(':');
      T >> NzS[i];
    }
  } else {
    NzS.fill(2);
  }

  ifstream  ifs_base;
  Parsing  Pb;
  if ( !Pc.get_string("--ifbase", s) ) {
    error ("no value for --ifbase");
  }
  ifs_base.open(s);
  if (ifs_base.bad()) {
    error ("ifs_base failed to open");
  }
  Pb.parse_file(ifs_base);
  if (lglvl >= medium) {
    cerr << "Tomog::set_param, --ifbase = " << s << endl;
  }

  // get model boundaries from base file

  Vect2  Xi;
  Vect2  Xf;
  Pb.get_vect2("XI", Xi);
  Pb.get_vect2("XF", Xf);

  cerr << "Tomog::set_param: Xi = " << Xi << endl;
  cerr << "Tomog::set_param: Xf = " << Xf << endl;

// Read Travel Time Data File --------------------------------------------------

  Parsing  Pd;

  // tdat ----------------------------------------------------------------------
  // name of file containing travel times

  ifstream  ifs_tdat;
  if ( !Pc.get_string("--iftdat", s) ) {
    error ("no value for --iftdat");
  }
  ifs_tdat.open (s);
  if (ifs_tdat.bad()) {
    error ("ifs_tdat failed to open");
  }
  cerr << "Tomog::SetParam, ifs_tdat = " << s << endl;
  Pd.parse_file (ifs_tdat);

  Mod.set_data(Pd);
  Mod.set_param(Pc);    // calling ModMisfit::SetRealData

Sponsored Links
    #2  
Old 01-16-2013
Corona688 Corona688 is offline Forum Staff  
Mead Rotor
 
Join Date: Aug 2005
Last Activity: 29 August 2014, 9:07 PM EDT
Location: Saskatchewan
Posts: 19,271
Thanks: 774
Thanked 3,237 Times in 3,035 Posts
This scheme seems a bit messy, since it lets you splatter commandline argument parsing wherever you feel like, instead of keeping it central in main(). And it's not really more organized than the scheme you had before, which was just a big list of variables.

What is a vect2? A 2d vector, but of what, ints, floats, doubles?

Last edited by Corona688; 01-16-2013 at 11:06 AM..
Sponsored Links
    #3  
Old 01-16-2013
kristinu kristinu is offline
Registered User
 
Join Date: Dec 2009
Last Activity: 29 August 2014, 3:38 AM EDT
Posts: 844
Thanks: 59
Thanked 8 Times in 8 Posts
Yes, vect2 is a class I created. It is a template so can handle various types. It has some functions for cartesian vector computations.

I have discussed this with another person who said the same thing. Thus I am planning to recode this part of the program. I would need suggestions on how to go about a solution.
    #4  
Old 01-16-2013
Corona688 Corona688 is offline Forum Staff  
Mead Rotor
 
Join Date: Aug 2005
Last Activity: 29 August 2014, 9:07 PM EDT
Location: Saskatchewan
Posts: 19,271
Thanks: 774
Thanked 3,237 Times in 3,035 Posts
I wrote some generic commandline parsing code years ago because I wasn't happy with how pointlessly complicated C getopt was, and have been using it in nearly all my projects ever since.

The idea is, you give the program an array of arguments to look for and pointers to variables to fill. Then you plug argc and argv into tsm_getopt, and it fills them if able.

Here is how it looks:


Code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "tsm_getopt.h"

// Structure to keep all global variables in one place.
struct {
        float fval;
        const char *stringval;
        const char *mandatorystring;
        int ival;
        int optionalflag;
        float mandatoryfloat;
} globals={
        3.14159,                // Default value for fval
        "where in the world",   // Default value for stringval
        NULL,                   // Mandatory, NULL if not set for error
        0,                      // Default value for ival
        0,                      // default value for optionalflag
        0.0/0.0,              // mandatory, defaults to invalid 0/0 if not set
};

const opt options[]={
        // "fval" for "--fval" argument,
        // 'f' for '-f' argument,
        // 1 since it takes one argument,
        // a pointer to a float number,
        // "%f" to read one float,
        // and "Float Value" to print as help text.
        {"fval", 'f', 1, &globals.fval, "%f", "Float value"},
        // Similar, but an integer number.
        {"ival", 'i', 1, &globals.ival, "%d", "Integer value"},
        // A string.  Needs a pointer to a char *(not the char * itself).
        {"sval", 's', 1, &globals.stringval, NULL, "String Value"},
        {"mstr", 'm', 1, &globals.mandatorystring, NULL, "Mandatory string"},
        // An option with no parameters.
        // Changes globals.optionalflag from 0 to 1 if set.
        {"optionalflag", 'o', 0, &globals.optionalflag, NULL, "optional flag"},
        // Need this as the last thing in the list, to tell when the list ends
        {"mfloat", 'l', 1, &globals.mandatoryfloat, "%f", "Mandatory float"},
        {NULL},
};

int main(int argc, char *argv[])
{
        if(argc < 2) // No arguments
        {
                tsm_usage(argc, argv, options);
                exit(1);
        }

        if(tsm_getopt(argc, argv, options) < 0)
        {
                tsm_usage(argc, argv, options);
                exit(1);
        }

        // Check any mandatory arguments
        if(globals.mandatorystring == NULL)
        {
                printf("mandatorystring not set\n");
                exit(1);
        }

        if(globals.ival == 0)
        {
                printf("ival not set\n");
                exit(1);
        }

        if(isnan(globals.mandatoryfloat))
        {
                printf("mfloat not set\n");
                exit(1);
        }

        // Arguments should now be ready.
        printf("fval = %f\n", globals.fval);
        printf("stringval = %s\n", globals.stringval);
        printf("mandatorystring = %s\n", globals.mandatorystring);
        printf("ival = %d\n", globals.ival);
        printf("optionalflag = %d\n", globals.optionalflag);
        printf("mandatoryfloat = %f\n", globals.mandatoryfloat);
        return(0);
}

It uses this code:


Code:
/* tsm_getopt.c */
#include <stdio.h>
#include <string.h>
#include "tsm_getopt.h"

static int tsm_findarg(const char *str, const opt options[]);

static int tsm_findarg(const char *str, const opt options[])
{
        int n;
        if(str[1] == '\0')
                return(-1);

        for(n=0; options[n].lname != NULL; n++)
        {
                // "-s"
                if((options[n].sname) &&
                        (str[1] == options[n].sname) &&
                        (str[2] == '\0'))
                        return(n);

                // "-s=..."
                if((options[n].sname) &&
                        (str[1] == options[n].sname) &&
                        (str[2] == '='))
                        return(n);

                // "--sval" or "--sval=..."
                if(str[1] == '-')
                if(strncmp(str+2, options[n].lname, strlen(options[n].lname))==0)
                if((str[2+strlen(options[n].lname)]=='\0')||
                   (str[2+strlen(options[n].lname)]=='='))
                        return(n);
        }

        return(-1);
}

int tsm_usage(int argc, char *argv[], const opt options[])
{
        int n;

        fprintf(stderr, "Usage:  %s\n", argv[0]);

        for(n=0; options[n].lname != NULL; n++)
        {
                fprintf(stderr, "\t--%s", options[n].lname);
                if(options[n].sname)
                        fprintf(stderr,"(-%c)", options[n].sname);
                if(options[n].usage)
                        fprintf(stderr, "\t%s", options[n].usage);
                fprintf(stderr, "\n");
        }
}

int tsm_getopt(int argc, char *argv[], const opt options[])
{
        int arg=1;
        while(arg < argc)
        {
                int which;
                if(strcmp(argv[arg], "--") == 0)
                        return(arg+2);
                else if(argv[arg][0] == '-')
                {
                        which=tsm_findarg(argv[arg], options);
                        if(which < 0)
                        {
                                fprintf(stderr, "invalid option '%s'\n",
                                        argv[arg]);
                                return(-1);
                        }

                        if(options[which].args)
                        {
                                // Handle -s=asdf or --sval=asdf
                                char *eq=strchr(argv[arg], '=');
                                char *argstr=NULL;

                                if(eq != NULL)
                                {
                                        eq++;
                                        if(eq[0] == '\0') eq=NULL;
                                }

                                if(((argc - arg) < 2)&&(eq==NULL))
                                {
                                        fprintf(stderr, "Need argument for %s\n",
                                                argv[arg]);
                                        return(-1);
                                }

                                if(eq) argstr=eq;
                                else    argstr=argv[arg+1];

                                // Store if possible
                                if(options[which].val)
                                {
                                        if(options[which].cmdstr)
                                        {
                                                if(sscanf(argstr,
                                                        options[which].cmdstr,
                                                        options[which].val) != 1)
                                                {
                                                        fprintf(stderr, "Invalid value "
                                                                "'%s' for option '%s'\n",
                                                                argv[arg], argv[arg+1]);
                                                        return(-1);
                                                }
                                        }
                                        else
                                                *((char **)options[which].val)=argstr;

                                        if(eq == NULL)  arg++;
                                }
                        }
                        else if(options[which].val != NULL)
                        {
                                // flag if possible
                                *((int *)options[which].val)=1;
                        }

                        arg++;
                }
                else
                        return(arg);
        }

        return(arg);
}


Code:
/* tsm_getopt.h */
#ifndef __TSM_GETOPT_H__
#define __TSM_GETOPT_H__

typedef struct opt
{
        const char      *lname;         // Long option, mandatory.
        unsigned char   sname;          // Short option, optional.
        int             args;           // Has arguments.
                                                // When cmdstr is NULL, stores
                                                // pointer to arg in *val
                                                // when cmdstr isn't NULL,
                                                // scanf's string into val
        void            *val;           // What to store
        const char      *cmdstr;        // Command string for scanf
        const char      *usage;         // Usage description
} opt;

#ifdef __cplusplus
extern "C" {
#endif

// Parse commandline parameters.  Returns index of first unparsed value.
int tsm_getopt(int argc, char *argv[], const opt options[]);
// Print usage for optional parameters
int tsm_usage(int argc, char *argv[], const opt options[]);

#ifdef __cplusplus
}
#endif

#endif/*__TSM_GETOPT_H__*/

I've just modified it to accept both --arg string and --arg=string syntax.

I'd need to see your vect2 class to add it to this, but maybe you could add the ability to be initialized from strings to your vect2 class instead?
Sponsored Links
    #5  
Old 01-16-2013
kristinu kristinu is offline
Registered User
 
Join Date: Dec 2009
Last Activity: 29 August 2014, 3:38 AM EDT
Posts: 844
Thanks: 59
Thanked 8 Times in 8 Posts
I am going to stick with the getopt_long for now. My only question is how can I have the class Tomog set the value for dist as example.
Sponsored Links
    #6  
Old 01-16-2013
Corona688 Corona688 is offline Forum Staff  
Mead Rotor
 
Join Date: Aug 2005
Last Activity: 29 August 2014, 9:07 PM EDT
Location: Saskatchewan
Posts: 19,271
Thanks: 774
Thanked 3,237 Times in 3,035 Posts
Since these are supposed to be global, putting them into a class doesn't make much sense, how about a namespace instead?


Code:
namespace options {
        int x, y, z;

        bool parse(int argc, char *argv[])
        {
                x=5;
                y=6;
                z=7;
        }
};

int main(int argc, char *argv[])
{
        if(!options::parse(argc, argv))
        {
                return(1);
        }

        printf("Got x %d\n", options::x);
        printf("Got y %d\n", options::y);
        printf("Got z %d\n", options::z);
        return(0);
}

That's with it all in one file. If you wanted the namespace accessible from multiple different C++ files, it'd be like this:


Code:
#ifndef __NS_H__
#define __NS_H__

namespace options {
        extern int x, y, z;
        bool parse(int argc, char *argv[]);
};

#endif/*__NS_H__*/


Code:
#include <stdio.h>
#include "ns.h"

int main(int argc, char *argv[])
{
        if(!options::parse(argc, argv))
        {
                return(1);
        }

        printf("Got x %d\n", options::x);
        printf("Got y %d\n", options::y);
        printf("Got z %d\n", options::z);
        return(0);
}

// These definitions only belong in one single file
int options::x=-1, options::y=-1, options::z=-1;

bool options::parse(int argc, char *argv[])
{
        x=5;
        y=6;
        z=7;
}

Sponsored Links
    #7  
Old 01-16-2013
kristinu kristinu is offline
Registered User
 
Join Date: Dec 2009
Last Activity: 29 August 2014, 3:38 AM EDT
Posts: 844
Thanks: 59
Thanked 8 Times in 8 Posts
My problem is not the parsing routine itself that takes the arguments and parses them in main, but how to get a class Tomog set the value for dist which was supplied by the parser in main.
Sponsored Links
Closed Thread

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

More UNIX and Linux Forum Topics You Might Find Helpful
Thread Thread Starter Forum Replies Last Post
function terminating if i give input as space or no input and enter BHASKARREDDY006 Shell Programming and Scripting 2 08-02-2012 11:09 AM
Script to delete files with an input for directories and an input for path/file *ShadowCat* Shell Programming and Scripting 3 06-28-2012 09:16 PM
grep with two arguments to arguments to surch for Cybertron Shell Programming and Scripting 1 04-11-2011 04:46 AM
Accepting user input and arguments in PERL jisha Shell Programming and Scripting 2 01-03-2011 12:56 AM
Reading specific contents from 1 input files and appending it to another input file sksahu Shell Programming and Scripting 5 01-14-2009 05:09 AM



All times are GMT -4. The time now is 04:17 AM.