LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   Making a C++ shell (http://www.linuxquestions.org/questions/programming-9/making-a-c-shell-775690/)

Tblade 12-14-2009 10:59 PM

Making a C++ shell
 
Hello, I am looking for help on getting my basic shell to change directories, and I'm kind of lost. This is for a program in my operating systems class and I'm kind of confused. I was given the following code and right now it will list whats in a directory but I don't know how to make it work for changing directory's .
We are supposed to use cd (folder name) and cd .. (to go back up just like in bash)
Please help me!!

Code:


#include <unistd.h>    // getpid(), getcwd()
#include <sys/types.h>  // type definitions, e.g., pid_t
#include <sys/wait.h>  // wait()
#include <signal.h>    // signal name constants and kill()
#include <iostream>
#include <vector>
#include <string>
using namespace std;


int main()
{
  while ( true )
  {
    // Show prompt.
    cout << getcwd(NULL, 0) << ">> " << flush;
    char command[128];
    cin.getline( command, 128 );

    vector<char*> args;
    char* prog = strtok( command, " " );
    char* tmp = prog;
    while ( tmp != NULL )
    {
      args.push_back( tmp );
      tmp = strtok( NULL, " " );
    }

    char** argv = new char*[args.size()+1];
    for ( int k = 0; k < args.size(); k++ )
      argv[k] = args[k];

    argv[args.size()] = NULL;

    if ( strcmp( command, "exit" ) == 0 )
    {
      return 0;
    }
    else
    {
      pid_t kidpid = fork();
      if ( kidpid < 0 )
      {
        perror( "Internal error: cannot fork." );
        return -1;
      }
      else if ( kidpid == 0 )
      {
        // I am the child.
        execvp( prog, argv );
        // The following lines should not happen (normally).
        perror( command );
        return -1;
      }
      else
      {
        // I am the parent.  Wait for the child.
        if ( waitpid( kidpid, 0, 0 ) < 0 )
        {
          perror( "Internal error: cannot wait for child." );
          return -1;
        }
      }
    }
  }

  return 0;
}


smeezekitty 12-15-2009 01:36 AM

http://www.cs.cf.ac.uk/Dave/C/node20.html

Tblade 12-15-2009 11:35 AM

I would really like help here
 
If any one can help me please help. This is a bit over my head for all the stuff I need to do for it. Please help.

johnsfine 12-15-2009 11:52 AM

Quote:

Originally Posted by Tblade (Post 3792407)
This is a bit over my head for all the stuff I need to do for it. Please help.

Do you understand even the basic concepts in the code that you posted at the start of this thread? (Or did you copy it from somewhere with zero understanding of it?)

Did you click on the link Smeezekitty provided and read the example of the chdir() function there?

It is hard to imagine how anyone would be unable to adapt from that example into the code you posted, unless they don't understand any of the code you posted.

If you need more specific help, ask a more specific question.

Otherwise I think the link Smeezekitty provided is the only help that could be provided short of actually doing your homework for you, which is not appropriate here.

Tblade 12-15-2009 12:19 PM

What I am having trouble with is setting up the chdir() child more or less when I have tried implementing chdir() my shell stops running completely. (almost as if in an infinite loop). Also the concept of how to go 'up' in a directory setting by using .. is not making any sense I know to use the compare string but how to determine the directory im trying to get into is not making any sense.

Do i need to make the chdir() run in the background? I think I might be able to get that done. I'm new to C++ and linux completely this is my second programming based class ever and I'm quite confused.

johnsfine 12-15-2009 01:16 PM

Quote:

Originally Posted by Tblade (Post 3792457)
What I am having trouble with is setting up the chdir() child

Because chdir should not be a child!

It should be a function call within the shell itself. You don't want to fork at all for processing a chdir command.

Quote:

Also the concept of how to go 'up' in a directory setting by using .. is not making any sense
I'm not 100% sure. I think the chdir() function takes care of that for you. It should be pretty easy to test whether it does so. If it doesn't, then your code would need to do a little extra work, but even that shouldn't be very hard.

Quote:

I'm new to C++ and linux completely this is my second programming based class ever and I'm quite confused.
You asked a much better question this time. That got you a better answer. I hope you understand this answer.

smeezekitty 12-15-2009 01:39 PM

Quote:

I'm not 100% sure. I think the chdir() function takes care of that for you.
I thought so too, but it does not seem to. But its not that hard to implement with getcwd() and chdir() combo.

TheIndependentAquarius 12-15-2009 11:40 PM

I have modified a part of this program. The modified part has been shown in RED.

Now test the program and tell me the results !!

Code:

#include <unistd.h>    // getpid(), getcwd()
#include <sys/types.h>  // type definitions, e.g., pid_t
#include <sys/wait.h>  // wait()
#include <signal.h>    // signal name constants and kill()
#include <iostream>
#include <vector>
#include <string>
using namespace std;


int main()
{
  while ( true )
    {
      // Show prompt.
      cout << get_current_dir_name () << "$ " ;
      char command[128];
      cin.getline( command, 128 );
     
      vector<char*> args;
      char* prog = strtok( command, " " );
      char* tmp = prog;
      while ( tmp != NULL )
        {
          args.push_back( tmp );
          tmp = strtok( NULL, " " );
        }
     
      char** argv = new char*[args.size()+1];
      for ( int k = 0; k < args.size(); k++ )
        argv[k] = args[k];
     
      argv[args.size()] = NULL;
     
      if ( strcmp( command, "exit" ) == 0 )
        {
          return 0;
        }
      else
        {
          if (!strcmp (prog, "cd"))
            {
              if (argv[1] == NULL)
                {
                  chdir ("/");
                }
              else
                {
                  chdir (argv[1]);
                }
              perror (command);
            }
          else

            {
              pid_t kidpid = fork();

              if (kidpid < 0)
                {
                  perror( "Internal error: cannot fork." );
                  return -1;
                }
              else if (kidpid == 0)
                {
                  // I am the child.
                  execvp (prog, argv);
                 
                  // The following lines should not happen (normally).
                  perror( command );
                  return -1;
                }
              else
                {
                  // I am the parent.  Wait for the child.
                  if ( waitpid( kidpid, 0, 0 ) < 0 )
                    {
                      perror( "Internal error: cannot wait for child." );
                      return -1;
                    }
                }
            }
        }
    }
 
  return 0;
}


Tblade 12-16-2009 02:26 AM

Thanks so much
 
Quote:

Originally Posted by anishakaul (Post 3793126)
I have modified a part of this program. The modified part has been shown in RED.

This worked great! Thanks so much. You solved the biggest question I had. Which was if I should nest it in the existing if statement or if I should put it before the existing one. This was a huge help and will make the rest of this project go smoothly.

I will ask though any pointers on how to use "&" to make a program run in the background. I know this will have to be forked and all. But my biggest problem is getting my shell to not recognize the & as a command line argument and as part of the string. I also think I might need to skip the getpid in the program, so the parent doesn't stay waiting.

Please let me know if I'm making any sense, or if you have any ideas on how to get it to use the & right.

TheIndependentAquarius 12-16-2009 03:22 AM

Quote:

Originally Posted by Tblade
This worked great! Thanks so much. You solved the biggest question I had. Which was if I should nest it in the existing if statement or if I should put it before the existing one. This was a huge help and will make the rest of this project go smoothly.

I will ask though any pointers on how to use "&" to make a program run in the background. I know this will have to be forked and all.

I am glad, it helped u !

By the way, did u understand why and what happened in the code, so that it started running ?

Quote:

Originally Posted by Tblade
But my biggest problem is getting my shell to not recognize the & as a command line argument and as part of the string.

Actually i do not know much about '&' , let me start a thread for knowing about '&' , how does it work !!

Tblade 12-16-2009 03:52 AM

Quote:

Originally Posted by anishakaul (Post 3793359)
I am glad, it helped u !

By the way, did u understand why and what happened in the code, so that it started running ?

Yea I understand exactly whats happening now. I set up a bunch of print statements as per to trouble shoot and I got the gist of what was really going on. It makes a lot more sense for me now.

TheIndependentAquarius 12-16-2009 05:14 AM

Quote:

Originally Posted by Tblade
Yea I understand exactly whats happening now. I set up a bunch of print statements as per to trouble shoot and I got the gist of what was really going on. It makes a lot more sense for me now.

If this thread has solved your basic problems may be u should label it [SOLVED]. :)

johnsfine 12-16-2009 09:04 AM

Quote:

Originally Posted by anishakaul (Post 3793126)
I have modified a part of this program. The modified part has been shown in RED.

Please don't do homework for those who request it.

There is an important difference between help, which is OK and do, which is not.

Also, you made some mistakes.

johnsfine 12-16-2009 09:17 AM

Quote:

Originally Posted by Tblade (Post 3793316)
how to use "&" to make a program run in the background.

http://www.linuxquestions.org/questi...79#post3793379
As smeezekitty and wje_lq explained (in the other thread anishakaul helpfully started for you), you implement the & behavior by not doing the waitpid() that the parent currently does in your code.

(It needs to be conditional, because if you don't have the &, you still need the waitpid())

Quote:

But my biggest problem is getting my shell to not recognize the & as a command line argument and as part of the string.
That should be easy at any one of several points in the existing code you have to parse the command.

1) You start with a command in a char array.
2) You tokenize it into a std::vector of char*
3) You copy that to an array of char*

The easiest point (by a very slight margin) to handle the & would be after step 2, before step 3. If the last arg at that point is "&" then flag that fact (for later suppression of the waitpid) and reduce the arg count by 1.


All times are GMT -5. The time now is 04:48 AM.