Shell with C++

SinYung
SinYung used Ask the Experts™
on
I am asked to write a 'shell'. The basic idea is to use a link list. I have completed the followings.

#include <iostream>
#include <string>
using namespace std;

string instr;
string filename;
struct FileNode{
        string name;
        FileNode * next;
        FileNode * subdir;
        FileNode (const string& f, FileNode * n){
                name = f;
                next = n;
                subdir = 0;
        }
};
void PrintList(FileNode * list){            
  for (FileNode * p = list; p != 0; p = p->next)
    cout << p->name << ' ';
  cout << endl;
}

int main(){

  FileNode * mylist(0);
  PrintList(mylist);

  mylist = new FileNode(".", mylist);
  mylist = new FileNode("..", mylist);
        do{
        cout<<"[/]$";
        cin>>instr;
        if (instr == "ls")
          PrintList(mylist);
        else if (instr == "touch"){
          cin>>filename;
          mylist = new FileNode(filename, mylist);
        }
        else if (instr == "rm"){
          cin>>filename;
          FileNode * p = mylist;
          while (p->next->name != filename)
                  p=p->next;
                FileNode * r = p->next;
                p->next = p->next->next;
                delete r;
        }
        else
                cerr<<"Bad command or filename"<<endl;
        }while(instr != "exit");
                exit(0);
        }  
However, I don't know how to modify it to support, sub-directories. I thought of a table of link list, but I dun know how to implement.How many pointers should I declare??
Thank you very much.
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Kyle AbrahamsSenior .Net Developer

Commented:
do it dynamically using the new operator.

make root or c:\ the first in your list.  When mkdir or md is invoked, create a new directory that's pointed to by it's parent.  If you wanted to, you can use a double linked list to support the cd ..

You should only need 2 pointers if you use a double linked list.

(You might want to create a new class for the directory structure.)
Commented:
Ok, I gave the thing a shot, but It turned out to be a rather largish solution. I'll post it anyway. Changing via cd .. up is a bit ugly since .. isn't a node anymore, but it works.

//FileNode.h
#ifndef FILENODE_H
#define FILENODE_H

#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::endl;


namespace f
{
      enum type
      {
            base,
            file,
            dir
      };

      class FileNode
      {
      public:
            string nName;
            type Type;
            FileNode *prev, *next, *subdir, *updir;
            
            FileNode( const string& f, type t );
            virtual ~FileNode(){}

            void PrintFlatList();
            void PrintDeepList();
            FileNode* FlatFind( const string& name );
            virtual FileNode* Find( const string& name )=0;
            void Append( FileNode* s, FileNode* t );
            void Append( FileNode* s ){ Append( s, this ); }
            bool Insert( FileNode* s, FileNode* t );
            bool Insert( FileNode* s ){ return Insert( s, this ); }
            void Remove( FileNode* n );
      };

      class File:public FileNode
      {
      public:
            File( const string& name ):FileNode( name, file ){}
            virtual FileNode* Find( const string& name );
      };

      class Dir: public FileNode
      {
      public:
            Dir( const string& name ):FileNode( name, dir ){}
            virtual ~Dir();
            virtual FileNode* Find( const string& name );
      };

      void PrintList(FileNode * list);
      bool Find( string Name, FileNode* start, FileNode*& prev, FileNode*& hit );
}//f

#endif //FILENODE_H

//FileNode.cpp
#include "FileNode.h"

namespace f
{

      FileNode::FileNode( const string& f, type t )
      {
            Type = t;
            nName = f;
            next = 0;
            prev = 0;
            updir = 0;
            subdir = 0;
      }


      FileNode* Dir::Find( const string& name )
      {
            FileNode* i, *t;
            if( nName == name ) return this;
            else
            {
                  for( i = this; i; i = i->next )
                  {
                        if( t = i->Find( name ) ) break;
                  }
            }
            return t;
      }

      FileNode* File::Find( const string& name )
      {
            if( nName == name ) return this;
            return 0;
      }

      FileNode* FileNode::FlatFind( const string& name )
      {
            FileNode* i;
            for( i = this->subdir; i; i = i->next )
            {
                  if( i->nName == name ) break;
            }
            return i;
      }

      void FileNode::Append( FileNode* s, FileNode* t )
      {
            s->prev = t;
            s->next = t->next;
            s->updir = t->updir;
            s->subdir = 0;
            if( t->next ) t->next->prev = s;
            t->next = s;
      }

      bool FileNode::Insert( FileNode* s, FileNode* t )
      {
            if( t->Type == dir )
            {
                  for( FileNode* i = t->subdir; i && i->next; i=i->next );
                  if( i )
                  {
                        i->Append( s, i );
                        return true;
                  }
                  else
                  {
                        t->subdir = s;
                        s->prev = 0;
                        s->next = 0;
                        s->updir = t;
                        s->subdir = 0;
                        return true;
                  }
            }
            return false;
      }

      void FileNode::PrintFlatList()
      {
            if( Type == dir )
                  for( FileNode* i=subdir;i;i = i->next )
                  {
                        if( i->Type == dir ) cout << "/" << i->nName << " \n";
                        else cout << i->nName << " \n";
                  }
      }

      void FileNode::PrintDeepList()
      {
      }

      void FileNode::Remove( FileNode* n )
      {

            if( n->prev ) n->prev->next = n->next;
            else n->updir->subdir = n->next;
            if( n->next ) n->next->prev = n->prev;
            delete n;
      }

      Dir::~Dir()
      {
            FileNode *t, *i;
            if( i=subdir )
            {
                  do
                  {
                        t = i;
                        i=i->next;
                        delete t;
                  }while( i );
            }
      }

}//f

//main.cpp
#include "FileNode.h"
#include <string>
using namespace std;

string instr, filename;

void main()
{
      
      
      f::FileNode *root = new f::Dir( "/" );
      f::FileNode *fp = root;
      f::FileNode *t;
      
      root->Insert( new f::Dir("tmp") );
      root->Insert( new f::Dir("test") );

      do
      {
            cout<<"[/]$";
            cin>>instr;

            if (instr == "ls")
                  fp->PrintFlatList();
            else if (instr == "touch")
            {
                  cin>>filename;
                  fp->Insert( new f::File( filename ) );
            }
            else if( instr == "mkdir" )
            {
                  cin>>filename;
                  fp->Insert( new f::Dir( filename ) );
            }
            else if (instr == "rm")
            {
                  
                  cin>>filename;
                  t = fp->FlatFind( filename );
                  if( t ) fp->Remove( t );
                  else
                        cout << filename << ": No File or Directory\n";
            }
            else if( instr == "cd" )
            {
                  cin>>filename;
                  if( filename == ".." && fp->updir )
                  {
                        fp = fp->updir;
                        continue;
                  }
                  else if( filename == "." )
                  {
                        continue;
                  }
                  else
                  {
                        t = fp->FlatFind( filename );
                        if( t && t->Type == f::dir )
                        {
                              fp = t;
                        }
                        else
                              cout << filename << ": No Directory\n";
                  }
            }
            else if( instr == "exit" )
            {
            }
            else
            {
                  cerr<<"Bad command or filename"<<endl;
            }

      }while(instr != "exit");
      delete root;
}

Author

Commented:
Why is there 2 cpp files, main.cpp and FileNode.cpp? I cannot compile it, gcc outputs the following errors.
temp3.cpp: In member function `bool f::FileNode::Insert(f::FileNode*,
   f::FileNode*)':
temp3.cpp:63: name lookup of `i' changed for new ISO `for' scoping
temp3.cpp:62:   using obsolete binding at `i'

also is it necessary to compile the header file?
Thank you very much.
Bootstrap 4: Exploring New Features

Learn how to use and navigate the new features included in Bootstrap 4, the most popular HTML, CSS, and JavaScript framework for developing responsive, mobile-first websites.

EOL

Commented:
I'v seperated the project into parsing and a suitable datastructure to use.

There are 3 files you need to make out of my listing. FileNode.h,FileNode.cpp and main.cpp.

Now it's important that you #include the right file into main, this is FileNode.h. FileNode.cpp has to include FileNode.h as well.

When you compile it you first compile FileNode.cpp, and then main.cpp, after that you link the two object files.

The error should go away if you replace the bad function with this:

     bool FileNode::Insert( FileNode* s, FileNode* t )
     {
          FileNode* i;
          if( t->Type == dir )
          {
               for( i = t->subdir; i && i->next; i=i->next );
               if( i )
               {
                    i->Append( s, i );
                    return true;
               }
               else
               {
                    t->subdir = s;
                    s->prev = 0;
                    s->next = 0;
                    s->updir = t;
                    s->subdir = 0;
                    return true;
               }
          }
          return false;
     }
EOL

Commented:
Hello? Is this the answer that helped you? Glad if you grade and close the topic.

Commented:
This question didn't show any activity for more than 21 days. I will ask Community Support to close it unless you finalize it yourself within 7 days.
You can always request to keep this question open. But remember, experts can only help if you provide feedback to their comments.
Unless there is objection or further activity,  I will suggest to accept

    "EOL"

comment(s) as an answer.

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!
========
Werner
Force accepted

** Mindphaser - Community Support Moderator **

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial