getting input from keyboard, passing to execvp

This is a discussion on getting input from keyboard, passing to execvp within the C++ Programming forums, part of the General Programming Boards category; Hi, I'm trying to create a simple shell program that reads in a command from the keyboard and passes it ...

  1. #1
    Registered User
    Join Date
    Oct 2003
    Posts
    9

    getting input from keyboard, passing to execvp

    Hi, I'm trying to create a simple shell program that reads in a command from the keyboard and passes it to execvp to execute. I'm working in a Linux environment. I'm splitting the input line into a command (the first token) and arguments (the remaining tokens). For example, ls -l has ls as command and -l as the sole argument. The problem is that execvp does not recognize the first argument. If I input "ls -l", it executes just "ls" and drops the "-l." If I input "ls -l -a", then it executes "ls -a." If I input "ls," it doesn't execute anything. Any thoughts? Thanks! Here is my code:

    Code:
    #include <unistd.h>
    #include <iostream>
    #include </usr/include/errno.h>
    #include </usr/include/sys/errno.h>
    #include <string>
    
    using namespace std;
    
    int main(int argc, char *argv[])
    {
            // issue prompt
            cout << "> ";
    
            // get input from user
            string inputStr;
            char inputStrArr[128];
            char * argArr[128];
            char separators[]   = " ,\t\n";
            char *token, *command;
            int numArgs = -1;
            int k;
            int i;
    
            getline(cin, inputStr);
            for(i=0; i<inputStr.length(); i++)
                    inputStrArr[i] = inputStr[i];
    	inputStrArr[i] = '\0';
    	token = strtok(inputStrArr, separators);
    	command = token;
    
            while( token != NULL )
            {
                    token = strtok( NULL, separators );
    
                    argArr[++numArgs] = token;
            }
    
            argArr[++numArgs] = '\0';
     
            // fork
            int childpid, flag;
    
            if ((childpid = fork()) == 0) // child code
            {
                    cout << "Process ID: child: " << getpid();
                    flag = execvp(command, argArr);
    
                    if (flag < 0)
                    {
                            perror("execvp failed");
                    }
            }
            else if (childpid > 0) // parent code
        {
            cout << "Process ID: " << getpid();
        }
        else // fork unsuccessful
        {
            cout << "\nError: fork failed\n";
        }
    
    return 0;
    }

  2. #2
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,499
    > command = token;
    Follow with

    argArr[++numArgs] = token;

    argv[0] is the name of the program, not the first parameter

    > argArr[++numArgs] = '\0';
    This is a pointer, not a character, so
    argArr[++numArgs] = NULL;
    is more usual
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  3. #3
    Registered User
    Join Date
    Oct 2003
    Posts
    9
    Thanks Salem, I missed that one!

    Now I have another question about comparing the value in a char pointer.
    I need to see if the last token on the line is "&" -- which indicates a background process. If so, it needs to be excluded from the argument array and a bool flag set. The problem is I don't know how to compare the value in this last token with "&". Here is my code:
    Code:
    #include <unistd.h>
    #include <iostream>
    #include </usr/include/errno.h>
    #include </usr/include/sys/errno.h>
    #include <string>
    
    using namespace std;
    
    int main(int argc, char *argv[])
    {
            cout << "program has started\n";
    
            // issue prompt
            cout << "> ";
    
            // get input from user
            bool background = false;
            string inputStr;
            string commandStr;
            char inputStrArr[128];
            char * argArr[128];
            char separators[]   = " ,\t\n";
            char *token, *command;
            int numArgs = -1;
            int k;
            int i;
    
            getline(cin, inputStr);
            while (inputStr.length() == 0)
            {
                    cout << "> ";
                    getline(cin, inputStr);
            }
    
            for(i=0; i<inputStr.length(); i++)
                    inputStrArr[i] = inputStr[i];
            inputStrArr[i] = '\0';
                                                                       
    	token = strtok( inputStrArr, separators );
            command = token;
    
            for (i=0; token[i] != '\0'; i++)
            {
                    commandStr += token[i];
    
            }
    
            argArr[++numArgs] = token;
    
            while( token != NULL )
            {
                    token = strtok( NULL, separators );
                    argArr[++numArgs] = token;
            }
    
            if (argArr[numArgs] == '&')
            {
                    background = true;
                    argArr[numArgs] = NULL;
            }
            else
                    argArr[++numArgs] = NULL;
    
        // is command built-in?
            if(commandStr == "quit")
            {
                    cout << "============= quit called\n";
                    return 0;
            }
            else
            {
    	    // execute external command
    	        int childpid, flag;
    	        childpid = fork();
    	        cout << "forking\n";
    	        if (childpid == 0) // child code
    	        {
    	                cout << "Process ID: child: " << getpid();
    	                flag = execvp(command, argArr);
    	
    	                if (flag < 0)
    	                {
    	                        perror("execvp failed");
    	                }
    	        }
    	        else if (childpid > 0) // parent code
    	        {
    	                cout << "Process ID: " << getpid();
    	        }
    	        else // fork unsuccessful
    	        {
    	                cout << "\nError: fork failed\n";
    	        }
    	} // end else
    return 0;
    }

  4. #4
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,499
    > if (argArr[numArgs] == '&')
    Try
    if (argArr[numArgs][0] == '&')

    > #include </usr/include/errno.h>
    > #include </usr/include/sys/errno.h>
    1. You shouldn't specify the paths
    2. you should only need errno.h
    3. perhaps it should be called
    #include <cerrno>
    if you're following current C++ conventions for including standard C header files
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  5. #5
    Registered User
    Join Date
    Oct 2003
    Posts
    9
    Thanks again. I've got my shell working well at this point. However, I would like to create a class and split the main pieces of code into functions. The problem I have is with the get_command function. It takes the command from the user and does everything as before. The client then should be able to access the command and arguments. However, I must not be passing the argments to get_command properly, because I'm getting a segmentation error when the client tries to access "command" and "args." Here is the function delaration:
    void get_command(char* command, char* args[]);
    and the client code:
    Code:
            char * argArr[128];
            char * command;
            shell1.get_command(command, argArr);
    I tried passing the arguments as pointer references:
    void get_command(char*& command, char*& args[]);
    but no luck there, either. Then the program won't even compile. Any ideas? Thanks!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. How do I input an unbuffered character via the keyboard???
    By Michael_in_Ohio in forum C Programming
    Replies: 1
    Last Post: 03-23-2008, 12:00 PM
  2. Need some help with C program writing
    By The_PC_Gamer in forum C Programming
    Replies: 9
    Last Post: 02-12-2008, 08:12 PM
  3. User Input - Keyboard
    By Scarvenger in forum Windows Programming
    Replies: 2
    Last Post: 08-02-2006, 07:56 PM
  4. Intercepting keyboard input
    By EvBladeRunnervE in forum Windows Programming
    Replies: 3
    Last Post: 01-08-2004, 08:03 AM
  5. Keyboard input without waiting (Borland C++)
    By adamdalziel in forum Game Programming
    Replies: 6
    Last Post: 09-24-2001, 04:20 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21