Solved

Separating commands from string?

Posted on 2004-08-24
21
244 Views
Last Modified: 2010-04-01
Hello,

I wondered if anyone could advise? I am trying to write a command line interface which allows several commands be enter together as a string and we separate these for processing.

The commands are all in uppercase, and can be single or come with a value.

An example input could be   COMMAND SECONDCOMMAND:VALUE

The : symbol means a value is attached to this command, I thought perhaps I could use the strtok function to find the : values which would also give the command, here this would give SECONDCOMMAND:VALUE, but I wondered how I could locate the single commands?

I also thought I could create an object for each command, and it value such as:

struct{
string command;
string value;
}

I would be appreicate some guidance, should I perhaps be trying not use existing tools. And loop through the string line searching for uppercase letters?

Thank you
0
Comment
Question by:AntoniRyszard656
  • 11
  • 5
  • 2
21 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 11884399
Even if you don't want to use existing tools, you should consider using 'getopt', which is a ready made interface for command line processing and seems to be ideal for your situation:

getopt.h
---------------------------------------------------------->8-------------------------------------------------
#ifndef UNIX    /* avoid conflict with stdlib.h */
int getopt(int argc, char **argv, char *opts);
extern char *optarg;
extern int optind;
#endif
---------------------------------------------------------->8-------------------------------------------------

getopt.c
---------------------------------------------------------->8-------------------------------------------------
/*
*  This is the AT&T public domain source for getopt(3).  It is the code
*  which was given out at the 1985 UNIFORUM conference in Dallas.
*  
*  There is no manual page.  That is because the one they gave out at
*  UNIFORUM was slightly different from the current System V Release 2
*  manual page.  The difference apparently involved a note about the
*  famous rules 5 and 6, recommending using white space between an
*  option and its first argument, and not grouping options that have
*  arguments.  Getopt itself is currently lenient about both of these
*  things.  White space is allowed, but not mandatory, and the last option
*  in a group can have an argument.  That particular version of the man
*  page evidently has no official existence.  The current SVR2 man page
*  reflects the actual behavor of this getopt.
*/

#include <string.h>
#include <stdio.h>
#include "getopt.h"

/*LINTLIBRARY*/
#ifndef NULL
#define NULL      0
#endif
#define EOF      (-1)
#define ERR(str, chr) (opterr ? fprintf(stderr, "%s%s%c\n", argv[0], str, chr) : 0)

int      opterr = 1;
int      optind = 1;
int      optopt = 0;
char      *optarg = 0;

int
getopt(int argc, char **argv, char *opts)
{
      static int sp = 1;
      register int c;
      register char *cp;

      if(sp == 1) {
            if(optind >= argc || (argv[optind][0] != '+' &&
               argv[optind][0] != '-') || argv[optind][1] == '\0')
                  return EOF;
            else if(strcmp(argv[optind], "--") == 0) {
                  optind++;
                  return EOF;
            }
            /* '+' for config options, '+' should not be in the opts list */
            if (argv[optind][0] == '+') {
                  optarg = argv[optind++] + 1;
                  return '+';
            }
      }
      optopt = c = argv[optind][sp];
      if(c == ':' || (cp=strchr(opts, c)) == NULL) {
            ERR(": illegal option -- ", c);
            if(argv[optind][++sp] == '\0') {
                  optind++;
                  sp = 1;
            }
            return '\0';
      }
      if(*++cp == ':') {
            if(argv[optind][sp+1] != '\0')
                  optarg = &argv[optind++][sp+1];
            else if(++optind >= argc) {
                  ERR(": option requires an argument -- ", c);
                  sp = 1;
                  return '\0';
            } else
                  optarg = argv[optind++];
            sp = 1;
      } else {
            if(argv[optind][++sp] == '\0') {
                  sp = 1;
                  optind++;
            }
            optarg = NULL;
      }
      return c;
}
---------------------------------------------------------->8-------------------------------------------------

For more info, see http://www.opengroup.org/onlinepubs/007908799/xsh/getopt.html
0
 

Author Comment

by:AntoniRyszard656
ID: 11884732
Thank you for replying.

Do you think an alternative could be to use the sscanf() function and change it's search value.

For example %s to find the separate commands and : to find the commands with a value attached.

Or use the strtok() and change it search value.

Do you think this could work?

0
 

Author Comment

by:AntoniRyszard656
ID: 11885005
For example, if I used the strtok as below, I thought this would find all the separate commands.

  char * pch;
 
  pch = strtok (str," ");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ");
  }

  And if I used : this would I find all the command:value in a string

  char * pch;
 
  pch = strtok (str,":");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, ":");
  }

Would you recommend this approach?

Thanks
0
 
LVL 86

Expert Comment

by:jkr
ID: 11885171
>>Would you recommend this approach?

It seems a feasible approach. However, 'getopt()' has been used and testd over ages, thus *I* would avoid re-inventing the wheel.
0
 

Author Comment

by:AntoniRyszard656
ID: 11896439
Hello,

I have used sscanf() and strtok() before and thought it would a good idea to use them.

The problem is, the command are inputted as a string but these parson function work with char arrays.

Is there any function in C++ to change string to a char array?

Thanks
0
 
LVL 86

Expert Comment

by:jkr
ID: 11896483
>>Is there any function in C++ to change string to a char array?

You mean a 'std::string'? Sure, use

string str;

// ...

char* psz = strdup ( str.c_str());
0
 

Author Comment

by:AntoniRyszard656
ID: 11896547

Would this also work to create an char[] from a string?

for example  char input[] = strdup(str.c_str());
0
 
LVL 86

Expert Comment

by:jkr
ID: 11896570
Not really using this syntax. But, actually, there is no difference between

char* psz = new char [ 255];

and

char ac [ 255];

What you always can do is

char ac [ 255];

if ( str.size() < 255) {

    strcpy ( ac, str.c_str());
}
0
 

Author Comment

by:AntoniRyszard656
ID: 11896647
Hello,

Would I be able to parson through a char * as in this example does with a char[]?

  char str[] ="COMMAND1      COMMAND2:VALUE";
  char * pch;

  pch = strtok (str," ");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ");
  }
0
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 

Author Comment

by:AntoniRyszard656
ID: 11896656

And should I enter the command line as a char * rather than a string?

Thanks
0
 
LVL 86

Accepted Solution

by:
jkr earned 45 total points
ID: 11896743
>>Would I be able to parson through a char * as in this example does with a char[]?

Yes, definitely. However, that would fail if you used

char* str ="COMMAND1      COMMAND2:VALUE";

since this would be a 'const' string.

>>And should I enter the command line as a char * rather than a string?

How *are* you getting the command line now?
0
 

Author Comment

by:AntoniRyszard656
ID: 11897570
Thank you for replying.

I decided the best approach would be to create a char[], at the moment the commands are enter as strings. Is there any different between char * and a string?

Below is example parson method, using the char[]. I wondered also, if I decided to use a char * rather an string. How could I compare a char * for example to test if the char * had a value PARSON.

Using a string this would be just if(command == "PARSON")

Thank you

void exampleParson(string script){    
   char input [sizeof script];
   
   for(int i = 0; i < sizeof input; i++){
      input[i] = script[i];
   }      

   char * parson;
   parson = strtok (input," ");
   
   while(parson != NULL){
      printf ("%s\n",parson);
      parson = strtok(NULL, " ");  
   }

}
0
 

Author Comment

by:AntoniRyszard656
ID: 11902909
Hello,

The commands are all entered as uppercase, and we store the input as a string. But also the user can enter lowercase words which makes the input read like a sentence. My hope was to just pass over the lowercase words, and separate the uppercase commands from the string.

An example could be:     in this script we have COMMAND1 and COMMAND2:VALUE

And some how locate COMMAND1, AND COMMAND2:VALUE from the script.

And finally separate any command with a value, and store both the commands and values.

I wrote this method to try and firstly locate,  COMMAND1  COMMAND2:VALUE

I would appreciate if you could offer any guidance.

Thanks

typedef struct input{
   string strings;
};

vector <input> stringVect;

void parsonMethod(string script){    
   int i = 0; string parson= "";

   while(i < sizeof script){
      if(isupper(script[i])){
     
         while(i < sizeof script){        
            parson = "";
           
            if(isupper(script[i]) || script[i] == ":"){
               parson = parson + script[i];
               i++;
            }
            else{
               i++;
               break;
            }
         }

         input newinput;
         newinput.strings =  parson;
         stringVect.push_back(newinput);                      
      }
      else{
         i++;
      }
   }

}
0
 
LVL 13

Expert Comment

by:SteH
ID: 11904511
If you already have STL string s why not use string::find to locate ' ' and ':'

And stringVect should be declared as:

vector<string> stringVect;

This allows access to them using stringVect[i] and not stringVect[i].strings and stringVect.push_back (parson)

int pos, pos2;
do {
  pos = script.find (' ');
  string command = script.substr (0, pos); // or pos-1?  and command could be renamed to parson to match the examples above.
                                                             // but I find command a more intuitive name.
  pos2 = script.find_first_not_of (" ");
  script = script.substr (pos2); // remove found command and trailing whitespaces.
  pos2 = command.find (':');
  if (pos2 != string::npos) { // : found in string
     command = command.substr (0, pos2-1); // take only part before colon
  }
  stringVect.push_back (command);
} while (pos != string::npos)
0
 

Author Comment

by:AntoniRyszard656
ID: 11905132
Thank you for replying.

An example input could be:

in this script we have COMMAND1 and COMMAND2:VALUE

The input includes the lowercase words, and I thought the only approach separate the uppercase words, would be:

typedef struct input{
   string strings;
};

vector <input> stringVect;

void parsonMethod(string script){    
   int i = 0; string parson= "";

   while(i < sizeof script){
      if(isupper(script[i])){
     
         while(i < sizeof script){        
            parson = "";
           
            if(isupper(script[i]) || script[i] == ":"){
               parson = parson + script[i];
               i++;
            }
            else{
               i++;
               break;
            }
         }

         input newinput;
         newinput.strings =  parson;
         stringVect.push_back(newinput);                      
      }
      else{
         i++;
      }
   }

}

This would hopefully create two objects from the input line:
COMMAND1
COMMAND2:VALUE

And then write another separating method to separate COMMAND's and VALUE's.

I just if anyone knew of some other approach?

Thank you
0
 
LVL 13

Assisted Solution

by:SteH
SteH earned 45 total points
ID: 11910441
The line
         while(i < sizeof script){        
should be
         while (i < script.size ())   // or
         while (i < script.length ())
To check if a string is all uppercase do
   string string1, string2;
   // fill string1 with token
   string2 = do_toupper(string1.begin (), string1.end()) // make string2 be string1 in uppdercase.
   if (string1 == string2) {
        // token was all uppercase.
   }
 
0
 

Author Comment

by:AntoniRyszard656
ID: 12046894
Thanks.

In the code below, I managed to separate the input into individual words, and store these in a vector.

I hoped now loop through this vector, and when we find a uppercase word divide this word into two strings. And create another vector of objects, from the uppercase words.

For example, building the objects using:

struct{
   string field1;
   string field2;
};

The first object would hold COMMAND in field1, and the second object would contain COMMAND1 in field1 and 1221 in field2. Could anyone advise, how best to further divide the strings?

Thank you  

   vector <string> stringVect;
   vector<string>::iterator it;
   
   string script = "in this script we have COMMAND1 and COMMAND2:1221";
   char array[script.length()];
   strcpy(array, script.c_str());
         
   char * parson = strtok(array," ");
           
   while(parson !=NULL){      
      stringVect.push_back(parson);
      parson = strtok(NULL, " ");  
   }
   
   int i = 0;
   for (it = stringVect.begin(); it != stringVect.end(); ++it){  
      cout << endl << *it;
   }
0
 

Author Comment

by:AntoniRyszard656
ID: 12046968
Sorry my mistake:

struct commands{
   string field1;
   string field2;
};

vector<commands>newVector;

The first object would hold COMMAND1 in field1, and the second object would contain COMMAND2 in field1 and 1221 in field2.
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Errors will happen. It is a fact of life for the programmer. How and when errors are detected have a great impact on quality and cost of a product. It is better to detect errors at compile time, when possible and practical. Errors that make their wa…
C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now