'쉘'에 해당되는 글 1건

  1. 2008/04/09 귀차니스트 Shell Program - 70% 정도 되는 버젼??

Shell Program - 70% 정도 되는 버젼??

Programming 2008/04/09 23:05 귀차니스트

  음 재미가 있는 관계로 코딩을 계속하다보니 어느새 프로토타입에서 벗어나 어느정도 구조를 갖추고 되었습니다. 리다이렉션을 비롯해서 Dir, Exit 등의 기능도 들어가게 되었습니다. 아직 미완성 적인 부분도 많이 존재하고 수정중인 버그도 존재합니다. 하지만 이런 진행과정을 남기고 싶어서 포스팅하게 되었습니다. 어느정도 되는 프로그램이 갑자기 어디서 뚝 떨어질리는 없지 않겠습니까?^^

shell.cpp (Language : cpp)
  1. #ifdef HAVE_CONFIG_H
  2. #include <config.h>
  3. #endif
  4. #include "tshell.h"
  5. int main( int argc, char **argv)
  6. {
  7.     TShell ShellObject;
  8.     ShellObject.Run();
  9.     return 0;
  10. }

  예전엔 Main코드 상에서 바로 측정을 진행하였지만 객체화를 안시켜놓으니 new를 통한 객체할당에 대한 해제가 이루어지지 않는 문제점이 존재한다고 생각하여 클래스화 하였습니다. 지금 생각중인 것은 TShell을 Singleton 인터페이스화 하여 alias 같은 명령어가 작동할 수 있도록 하는 것입니다.
  나중에 한 번 수정을 해봐야 겠네요..

tshell.h (Language : cpp)
  1. #pragma once
  2. #include <iostream>
  3. #include <iomanip>
  4. #include <string>
  5. #include <vector>
  6. #include <stack>
  7. #include <map>
  8. #include <termios.h>
  9. #include "cshellcommand.h"
  10. #include "cactionobject.h"
  11. #include "cfileobject.h"
  12. #include "cexitobject.h"
  13. #include "cdirobject.h"
  14. #include "cshobject.h"
  15. #include "ccdobject.h"
  16. typedef std::map< std::string, CActionObject * > CommandVector;
  17. class TShell : private CShellCommand
  18. {
  19. public:
  20.     TShell(void);
  21.     ~TShell(void);
  22.     void Run();
  23. private:
  24.     void InitializeCommandMap();
  25.     void TerminalizeCommandMap();
  26.     void DoInputWork(std::string &InputBuffer);
  27.     void PrintShellString(const std::string &CommandBuffer);
  28.     bool PrintNearestCommand( const std::string &Token );
  29.     void StringTokenizer( const std::string &Str, std::vector< std::string > &Token, const std::string &Delimiter );
  30.     char getch(void);
  31.     CommandVector CommandTable;
  32. };
tshell.cpp (Language : cpp)
  1. #include "tshell.h"
  2. TShell::TShell(void)
  3. {
  4.     InitializeCommandMap();
  5. }
  6. TShell::~TShell(void)
  7. {
  8.     TerminalizeCommandMap();
  9. }
  10. void TShell::InitializeCommandMap()
  11. {
  12.     try {
  13.         CommandTable.insert( std::make_pair( "exit", new CExitObject ) );
  14.         CommandTable.insert( std::make_pair( "dir", new CDirObject ) );
  15.         CommandTable.insert( std::make_pair( "sh", new CShObject ) );
  16.         CommandTable.insert( std::make_pair( "cd", new CCdObject ) );
  17.     }
  18.     catch( ... )    {
  19.     }
  20. }
  21. void TShell::TerminalizeCommandMap()
  22. {
  23.     for( CommandVector::const_iterator Iter = CommandTable.begin(); Iter != CommandTable.end(); ++Iter )    {
  24.         try {
  25.             delete Iter->second;
  26.         }
  27.         catch( ... )    {
  28.         }
  29.     }
  30. }
  31. void TShell::Run()
  32. {
  33.     std::string InputBuffer;
  34.     while( true )    {
  35.         InputBuffer.clear();
  36.         DoInputWork( InputBuffer );
  37.         std::vector< std::string > PipeVector;
  38.         StringTokenizer( InputBuffer, PipeVector, "|" );
  39.         for( std::vector< std::string >::const_iterator Iter = PipeVector.begin(); Iter != PipeVector.end(); ++Iter )   {
  40.             std::vector< std::string > ArgumentTable;
  41.             StringTokenizer( *Iter, ArgumentTable, " \t\r\n" );
  42.             if( ArgumentTable.size() != 0 ) {
  43.                 CommandVector::const_iterator Accessor = CommandTable.find( ArgumentTable[ 0 ] );
  44.                 if( Accessor != CommandTable.end() )    {
  45.                     if( !Accessor->second->DoAction( ArgumentTable ) )
  46.                         return;
  47.                 }
  48.                 else    {
  49.                     CFileObject CFObject;
  50.                     CFObject.DoAction( ArgumentTable );
  51.                 }
  52.             }
  53.         }
  54.     }
  55. }
  56. void TShell::DoInputWork(std::string &InputBuffer )
  57. {
  58.     std::stack< std::string > TokenStack;
  59.     std::string CurrentToken;
  60.     PrintShellString( "" );
  61.     int InputChar;
  62.     while( ( InputChar = getch() ) != '\n' )    {
  63.         switch( InputChar ) {
  64.             case '\t':
  65.                 if( TokenStack.empty() || TokenStack.top() == "|" ) {
  66.                     if( PrintNearestCommand(CurrentToken) )
  67.                         PrintShellString(InputBuffer);
  68.                 }
  69.                 break;
  70.             case 127://'\b'
  71.                 {
  72.                     std::string::size_type SizeIndex = InputBuffer.length();
  73.                     if( SizeIndex-- > 0 )   {
  74.                         if( InputBuffer[ SizeIndex ] == ' ' )   {
  75.                             CurrentToken = TokenStack.top();
  76.                             TokenStack.pop();
  77.                         }
  78.                         else    {
  79.                             CurrentToken.erase( CurrentToken.length() - 1, 1 );
  80.                         }
  81.                         InputBuffer.erase( SizeIndex, 1 );
  82.                         std::cout << "\b \b";
  83.                     }
  84.                 }
  85.                 break;
  86.             case ' ':
  87.                 InputBuffer += InputChar;
  88.                 TokenStack.push(CurrentToken);
  89.                 CurrentToken.clear();
  90.                 std::cout.put(InputChar);
  91.                 break;
  92.             default:
  93.                 InputBuffer += InputChar;
  94.                 CurrentToken += InputChar;
  95.                 std::cout.put(InputChar);
  96.                 break;
  97.         }
  98.     }
  99.     std::cout << std::endl;
  100. }
  101. void TShell::PrintShellString(const std::string &CommandBuffer)
  102. {
  103.     std::cout << "[" + GetCurrentWorkingDirectory() + "]$" << CommandBuffer;
  104. }
  105. bool TShell::PrintNearestCommand( const std::string &Token )
  106. {
  107.     bool IsPrinted = false;
  108.     unsigned int Count = 0, TokenLength = Token.length();
  109.     for( CommandVector::const_iterator Iter = CommandTable.begin(); Iter != CommandTable.end(); ++Iter )    {
  110.         const std::string &KeyString = Iter->first;
  111.         if( KeyString.length() >= TokenLength ) {
  112.             if( KeyString.substr( 0, TokenLength ) == Token )   {
  113.                 if( Count % 5 == 0 )
  114.                     std::cout << std::endl;
  115.                 std::cout << "[" << KeyString << "]" << std::setw(6) << "\t";
  116.                 Count++;
  117.                 IsPrinted = true;
  118.             }
  119.         }
  120.     }
  121.     if( IsPrinted )
  122.         std::cout << std::endl;
  123.     return IsPrinted;
  124. }
  125. char TShell::getch(void)
  126. {
  127.     struct termios oldt, newt;
  128.     int ch;
  129.     tcgetattr(STDIN_FILENO, &oldt);
  130.     newt = oldt;
  131.     newt.c_lflag &= ~(ICANON | ECHO);
  132.     tcsetattr(STDIN_FILENO, TCSANOW, &newt);
  133.     ch = getchar();
  134.     tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  135.     return ch;
  136. }
  137. void TShell::StringTokenizer( const std::string &Str, std::vector< std::string > &Token, const std::string &Delimiter )
  138. {
  139.     std::string::size_type LastPos = Str.find_first_not_of( Delimiter, 0 );
  140.     std::string::size_type Pos     = Str.find_first_of( Delimiter, LastPos );
  141.     while( std::string::npos != Pos || std::string::npos != LastPos )
  142.     {
  143.         Token.push_back( Str.substr( LastPos, Pos - LastPos ) );
  144.         LastPos = Str.find_first_not_of( Delimiter, Pos );
  145.         Pos = Str.find_first_of( Delimiter, LastPos );
  146.     }
  147. }

  음 여기서 다른 부분은 예전 버젼과 동일하지만 getch 함수가 C 표준함수가 아니다보니 실질적으로 프로그램에 문제가 있었고 그로인해 glibc환경에서 동작하는 getch소스를 가져와서 구현하게 되었습니다. getch는 아마도 CShellCommand 클래스로 자리를 이동해야 할 것 같군요. 어차피 private 상속이니까요.
  그리고 키 입력을 통한 처리를 DoInputWork라는 함수 안에서 getch를 통하여 구현을 하게 되었는데, 아직 화살표키 등의 처리를 진행하지 않았기 때문에 그에 따른 처리가 추가적으로 등록되어야 할 것같습니다.

CActionObject.h (Language : cpp)
  1. #pragma once
  2. #include <string>
  3. #include <vector>
  4. #include <fcntl.h>
  5. class CActionObject
  6. {
  7. public:
  8.     CActionObject(void);
  9.     virtual ~CActionObject(void);
  10.     virtual bool DoAction( std::vector< std::string > &Argument ) = 0;
  11.     void SetRedirection( std::vector< std::string > &Argument );
  12.     void ResetRedirection();
  13. private:
  14.     int STDOUTFileDesc, STDINFileDesc;
  15.     int OldSTDOUT, OldSTDIN;
  16.     bool STDOUTRedirection, STDINRedirection;
  17.     static const int STDOUT = 1;
  18.     static const int STDIN = 0;
  19. };
CActionObject.cpp (Language : cpp)
  1. #include "cactionobject.h"
  2. CActionObject::CActionObject()
  3.     :   STDINRedirection( false ), STDOUTRedirection( false )
  4. {
  5. }
  6. CActionObject::~CActionObject()
  7. {
  8. }
  9. void CActionObject::SetRedirection( std::vector< std::string > &Argument )
  10. {
  11.     std::vector< std::string >::const_iterator End = Argument.end();
  12.     for( std::vector< std::string >::const_iterator Iter = Argument.begin();
  13.         Iter != Argument.end(); ++Iter )    {
  14.         if( *Iter == ">" && ++Iter != End ) {
  15.             STDOUTRedirection = true;
  16.             STDOUTFileDesc = open( Iter->c_str(), O_CREAT | O_RDWR | S_IREAD | S_IWRITE );
  17.             OldSTDOUT = dup( STDOUT );
  18.             dup2( STDOUTFileDesc, STDOUT );  
  19.         }
  20.         else if( *Iter == "<" && ++Iter != End )    {
  21.             STDINRedirection = true;
  22.             STDINFileDesc = open( Iter->c_str(), O_RDONLY );
  23.             OldSTDIN = dup( STDIN );
  24.             dup2( STDINFileDesc, STDIN );
  25.         }
  26.     }
  27. }
  28. void CActionObject::ResetRedirection()
  29. {
  30.     if( STDOUTRedirection ) {
  31.         close( STDOUTFileDesc );
  32.         dup2( OldSTDOUT, STDOUT );
  33.         close( OldSTDOUT );
  34.         STDOUTRedirection = false;
  35.     }
  36.     if( STDINRedirection )  {
  37.         close( STDINFileDesc );
  38.         dup2( OldSTDIN, STDIN );
  39.         close( OldSTDIN );
  40.         STDINRedirection = false;
  41.     }
  42. }

  SetRedirection 과 ResetRedirection 함수를 통하여 만약 > 파일명, < 파일명이 있다면 리다이렉션 기능이 수행 되게 하였습니다. dup함수와 dup2함수를 통하여 제작을 하였습니다. 실질적으로 CActionObject 클래스가 하는 역할은 거의 없다고 봐도 무방하죠^^;

CCdObject.h (Language : cpp)
  1. #pragma once
  2. #include <iostream>
  3. #include <vector>
  4. #include <string>
  5. #include "cactionobject.h"
  6. #include "cshellcommand.h"
  7. class CCdObject
  8.     : public CActionObject, private CShellCommand   {
  9. public:
  10.     CCdObject();
  11.     ~CCdObject();
  12.     bool DoAction( std::vector< std::string > &Argument );
  13. };
CCdObject.cpp (Language : cpp)
  1. #include "ccdobject.h"
  2. CCdObject::CCdObject()
  3. {
  4. }
  5. CCdObject::~CCdObject()
  6. {
  7. }
  8. bool CCdObject::DoAction( std::vector< std::string > &Argument )
  9. {
  10.     SetRedirection( Argument );
  11.     std::vector< std::string >::size_type ArgumentSize = Argument.size();
  12.     if( ArgumentSize == 1 ) {
  13.         std::cout << GetCurrentWorkingDirectory() << std::endl;
  14.     }
  15.     else if( ArgumentSize == 2 )    {
  16.         chdir( Argument[ 1 ].c_str() );
  17.     }
  18.     ResetRedirection();
  19.     return true;
  20. }

  cd 를 통한 디렉토리 이동 기능을 구현해놓은 클래스입니다. CShellCommand 클래스를 private 상속 받은 것은 아시다시피 GetCurrentWorkingDirectory 함수를 사용하기 위해서 입니다. 보시면 cd .. 을 하지 않고 cd . 했을때 현재의 프로젝트를 출력하기만 하기에 이렇게 구현할 수 밖에 없었죠.
  디렉토리 들어가지 못했을 때의 경우를 chdir 리턴값을 체크하여 에러메시지 출력을 따로 해야겠습니다.

CExitObject.h (Language : cpp)
  1. #pragma once
  2. #include <iostream>
  3. #include "cactionobject.h"
  4. class CExitObject
  5.     : public CActionObject
  6. {
  7. public:
  8.     CExitObject(void);
  9.     ~CExitObject(void);
  10.     bool DoAction( std::vector< std::string > &Argument );
  11. };
CExitObject.cpp (Language : cpp)
  1. #include "cexitobject.h"
  2. CExitObject::CExitObject(void)
  3. {
  4. }
  5. CExitObject::~CExitObject(void)
  6. {
  7. }
  8. bool CExitObject::DoAction( std::vector< std::string > &Argument )
  9. {
  10.     return false;
  11. }

  exit 명령을 통하여 쉘을 종료하기 위하여 제작한 클래스인데, 실질적으로 tshell.cpp 구현부에서 해당 DoAction함수의 실행 리턴값을 체크하여 프로그램을 종료할 것인가 결정하는 부분이 존재하다보니 그냥 false를 리턴하는 코드만 넣게 되었습니다.

CDirObject.h (Language : cpp)
  1. #pragma once
  2. #include <iostream>
  3. #include <sstream>
  4. #include <vector>
  5. #include <iterator>
  6. #include <algorithm>
  7. #include <iomanip.h>
  8. #include <time.h>
  9. #include <dirent.h>
  10. #include <sys/stat.h>
  11. #include "cshellcommand.h"
  12. #include "cactionobject.h"
  13. namespace Option    {
  14.     enum OptionMode {
  15.         Simple,
  16.         Page,
  17.         Wide,
  18.         Recursive
  19.     };
  20. }
  21. struct FileInformation  {
  22.     std::string Time;
  23.     bool IsDirectory;
  24.     std::string Name;
  25.     long long Size;
  26. };
  27. class CDirObject
  28.     : public CActionObject, private CShellCommand
  29. {
  30. public:
  31.     CDirObject(void);
  32.     ~CDirObject(void);
  33.     bool DoAction( std::vector< std::string > &Argument );
  34. };
  35. struct SimplePrint  {
  36.     SimplePrint( bool IsPagePrint )
  37.         : IsPage( IsPagePrint ), RowNumber( 0 ) {
  38.     }
  39.     void operator()( FileInformation &FileInfo )    {
  40.         std::cout << FileInfo.Time;
  41.         if( FileInfo.IsDirectory )  {
  42.             std::cout << "<DIR>        ";
  43.         }
  44.         else    {
  45.             std::cout << setw( 12 ) << setfill(' ') << FileInfo.Size << " ";
  46.         }
  47.         std::cout << setw( 30 ) << ( FileInfo.Name.length() > 30 ? FileInfo.Name.substr( 0, 28 ) + ".." : FileInfo.Name )
  48.             << std::endl;
  49.         if( IsPage )    {
  50.             if( ( ++RowNumber % 10 ) == 0 ) {
  51.                 std::cout << "계속하려면 엔터키를 누르십시오.";
  52.                 std::cin.get();
  53.             }
  54.         }
  55.     }
  56. private:
  57.     bool IsPage;
  58.     int RowNumber;
  59. };
  60. struct WidePrint    {
  61.     WidePrint()
  62.         : ColNumber( 0 )    {
  63.     }
  64.     void operator()( FileInformation &FileInfo )    {
  65.         std::cout << "[" << setw( 10 ) << ( FileInfo.Name.length() > 10 ? FileInfo.Name.substr( 0, 8 ) + ".." : FileInfo.Name )
  66.             << "]";
  67.         if( ( ++ColNumber % 5 ) == 0 )
  68.             std::cout << std::endl;
  69.         else
  70.             std::cout << "\t";
  71.     }
  72. private:
  73.     int ColNumber;
  74. };
  75. struct RecursivePrint   {
  76.     RecursivePrint( std::string &CurrentDirectory, std::vector< std::string > &Argument )
  77.         : DummyCurrentDirectory( CurrentDirectory ), DummyArgument( Argument )  {
  78.     }
  79.     void operator()( std::string &DirectoryName )   {
  80.         std::string CurrentDirectory( DummyCurrentDirectory );
  81.         CurrentDirectory += "/";
  82.         CurrentDirectory += DirectoryName;
  83.         DummyArgument.push_back( CurrentDirectory );
  84.         TempObject.DoAction( DummyArgument );
  85.         DummyArgument.erase( --DummyArgument.end() );
  86.     }
  87. private:
  88.     std::string &DummyCurrentDirectory;
  89.     std::vector< std::string > &DummyArgument;
  90.     CDirObject TempObject;
  91. };
CDirObject.cpp (Language : cpp)
  1. #include "cdirobject.h"
  2. CDirObject::CDirObject(void)
  3. {
  4. }
  5. CDirObject::~CDirObject(void)
  6. {
  7. }
  8. bool CDirObject::DoAction( std::vector< std::string > &Argument )
  9. {
  10.     SetRedirection( Argument );
  11.     std::string &Command = Argument[ 0 ];
  12.     Option::OptionMode ArgumentOptionMode = Option::Simple;
  13.     std::vector< std::string > DirectoryTable;
  14.     std::vector< std::string > OptionTable;
  15.     for( std::vector< std::string >::const_iterator Iter = ++Argument.begin();
  16.         Iter != Argument.end();
  17.         ++Iter )
  18.     {
  19.         if( *Iter == "/?" ) {
  20.             std::cout << "Command : " << Command << "( 디렉토리 나열 명령어 ) 사용 예는 아래와 같습니다." << std::endl
  21.                 << "ex ) " << Command << "      - 조건없이 단순히 나열합니다." << std::endl
  22.                 << "     " << Command << " /w         - 파일명을 Wide형태로 나열합니다." << std::endl
  23.                 << "     " << Command << " /p         - 페이지 형태로 나열합니다." << std::endl
  24.                 << "     " << Command << " /s         - 하위 디렉토리를 포함하여 나열합니다." << std::endl
  25.                 << "     " << Command << " [디렉토리명 ... ]   - 해당 디렉토리의 내용을 나열합니다." << std::endl
  26.                 << "     " << Command << " - 옵션은 마지막 옵션만 사용됩니다. 다른 옵션은 무시됩니다." << std::endl;
  27.             return true;
  28.         }
  29.         else if( *Iter == "/w" )    {
  30.             ArgumentOptionMode = Option::Wide;
  31.         }
  32.         else if( *Iter == "/p" )    {
  33.             ArgumentOptionMode = Option::Page;
  34.         }
  35.         else if( *Iter == "/s" )    {
  36.             ArgumentOptionMode = Option::Recursive;
  37.         }
  38.         else    {
  39.             DirectoryTable.push_back( *Iter );
  40.             continue;
  41.         }
  42.         OptionTable.push_back( *Iter );
  43.     }
  44.     std::string::size_type DirectoryNumber = DirectoryTable.size();
  45.     std::string CWDirectory;
  46.     if( DirectoryNumber == 0 )  {
  47.          CWDirectory = GetCurrentWorkingDirectory();
  48.     }
  49.     if( DirectoryNumber == 1 )  {
  50.         CWDirectory = GetCurrentWorkingDirectory();
  51.         CWDirectory += "/";
  52.         CWDirectory += DirectoryTable.front();
  53.         DirectoryTable.clear();
  54.     }
  55.     else if( DirectoryNumber > 1 )  {
  56.         std::vector< std::string > TempVector;
  57.         TempVector.push_back(Argument.front());
  58.         std::copy( OptionTable.begin(), OptionTable.end(), std::back_insert_iterator< std::vector< std::string > >( TempVector ) );
  59.         std::for_each( DirectoryTable.begin(), DirectoryTable.end(), RecursivePrint( CWDirectory, TempVector ) );
  60.         return true;
  61.     }
  62.     long long int m_TotalFileSize = 0;
  63.     int m_TotalFileNum = 0;
  64.     int m_TotalDirectoryNum = 0;
  65.     std::vector< FileInformation > StatList;
  66.     std::string m_DirectoryParent( "." );
  67.     std::string m_DirectoryCurrent( ".." );
  68.     struct tm *GmTime;
  69.     struct stat Fstat;
  70.     struct dirent **items;
  71.     int filenum = scandir( CWDirectory.c_str(), &items, NULL, alphasort);
  72.     std::cout << std::endl << "  현재 디렉토리 : " << CWDirectory << std::endl << std::endl;
  73.     for ( int i = 0; i < filenum; i++)    {
  74.         FileInformation FileInfo;
  75.         lstat( items[i]->d_name, &Fstat);
  76.         GmTime = gmtime( static_cast< const time_t* >( &Fstat.st_atime ) );
  77.         std::ostringstream StringFormatter;
  78.         StringFormatter << 1900 + GmTime->tm_year << "-" << setw(2) << setfill('0')
  79.             << GmTime->tm_mon << "-" << setw(2)
  80.             << GmTime->tm_mday << "  "
  81.             << ( GmTime->tm_hour > 12 ? "오후" : "오전" ) << " "
  82.             << setw(2) << (GmTime->tm_hour%12) << ":"
  83.             << setw(2) << (GmTime->tm_min) << ":"
  84.             << setw(2) << (GmTime->tm_sec) << "   ";
  85.         FileInfo.Time = StringFormatter.str();
  86.         FileInfo.Name = items[i]->d_name;
  87.         if( !S_ISREG(Fstat.st_mode) )   {
  88.             if( m_DirectoryParent != items[i]->d_name && m_DirectoryCurrent != items[i]->d_name )   {
  89.                 DirectoryTable.push_back( items[i]->d_name );
  90.             }
  91.             FileInfo.IsDirectory = true;
  92.             FileInfo.Size = 0;
  93.             m_TotalDirectoryNum++;
  94.         }
  95.         else    {
  96.             FileInfo.IsDirectory = false;
  97.             FileInfo.Size = Fstat.st_size;
  98.             m_TotalFileNum++;
  99.             m_TotalFileSize += Fstat.st_size;
  100.         }
  101.         StatList.push_back( FileInfo );
  102.     }
  103.     switch( ArgumentOptionMode )    {
  104.         case Option::Simple:
  105.             std::for_each( StatList.begin(), StatList.end(), SimplePrint( false ) );
  106.             break;
  107.         case Option::Wide:
  108.             std::for_each( StatList.begin(), StatList.end(), WidePrint() );
  109.             break;
  110.         case Option::Page:
  111.             std::for_each( StatList.begin(), StatList.end(), SimplePrint( true ) );
  112.             break;
  113.         case Option::Recursive:
  114.             std::vector< std::string > TempVector;
  115.             TempVector.push_back(Argument.front());
  116.             std::copy( OptionTable.begin(), OptionTable.end(), std::back_insert_iterator< std::vector< std::string > >( TempVector ) );
  117.             std::for_each( StatList.begin(), StatList.end(), SimplePrint( false ) );
  118.             std::for_each( DirectoryTable.begin(), DirectoryTable.end(), RecursivePrint( CWDirectory, TempVector ) );
  119.             break;
  120.     }
  121.     std::cout << std::endl << setfill(' ')
  122.         << setw( 30 ) << m_TotalDirectoryNum << "개 디렉토리" << std::endl
  123.         << setw( 30 ) << m_TotalFileNum << "개 파일"
  124.         << setw( 30 ) << m_TotalFileSize << " 바이트" << std::endl << std::endl;
  125.     ResetRedirection();
  126.     return true;
  127. }

  주력 기능으로 제작하기 위하여 많은 코딩량이 들어간 CDirObject 입니다. 기능은 /w /p /s 디렉토리 나열 등이 있는데, 현재 /s 버젼 및, 디렉토리 나열 기능에 대하여는 버그가 존재합니다. S_ISDIR 부분이 왠일인지 이상하게 파일인데도 불구하고 DIR로 인식하는지 true가 리턴되더군요. 만약 해결 된다면 문제가 어느정도 괜찮을 것 같습니다.
  디렉토리 내용의 출력은 함수 객체를 사용하였는데, CDirObject.h 파일에 존재하는 ???Print 구조체의 ()연산자를 오버로딩하여 출력을 구성했습니다. 역시 편리한 점이 없지않아 있더군요. 출력 형식은 윈도우즈 cmd.exe 에서 dir 했을 때와 비슷하게 구현했습니다.

CShellCommand.h (Language : cpp)
  1. #pragma once
  2. #include <string>
  3. class CShellCommand{
  4. public:
  5.     CShellCommand();
  6.     ~CShellCommand();
  7.     std::string GetCurrentWorkingDirectory();
  8. };
CShellCommand.cpp (Language : cpp)
  1. #include "cshellcommand.h"
  2. CShellCommand::CShellCommand()
  3. {
  4. }
  5. CShellCommand::~CShellCommand()
  6. {
  7. }
  8. std::string CShellCommand::GetCurrentWorkingDirectory()
  9. {
  10.     const int BufferSize = 500;
  11.     char CurrentWorkingDirectoryBuffer[ BufferSize ] = { 0,};
  12.     return getcwd( CurrentWorkingDirectoryBuffer, BufferSize - 1 );
  13. }

  private 상속을 위한 Shell과 관련된 기능 구현 CShellCommand 클래스이다 보니 마지막으로 밀리게 되었군요. 지금 현재는 GetCurrentWorkingDirectory 함수만 존재하지만 getch 함수도 이동하고 그러면 어느정도 채워 지겠군요. 또한 기능이 복잡해지고 한다면 여러모로 많이 복잡할 것 같이 보입니다^^;

  이 외에도 쉘 스크립트 기능, 파일 실행 기능들도 넣으려고 하는데 아직 작업을 진행하지 못하였군요. 버그를 수정하여 완벽한 쉘이 될 수 있도록 개정해봐야 겠습니다.^^; 다른 것도 아니고 스스로 사용할 것인데요. 그럼 오늘도 즐거운 하루 되시길.

=뱀다리=
그나저나 이번에도 올려놓고 보니 + 연산으로 임시객체를 남발하는 코드가 몇 군데 있고 효율을 떨어트리는 코드가 존재하는군요. 다음버젼엔 수정하여 올려야 겠습니다.

크리에이티브 커먼즈 라이센스
Creative Commons License
2008/04/09 23:05 2008/04/09 23:05
TAG , , ,

댓글을 달아 주세요