--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/userlibandfileserver/fileserver/etshell/ts_edshl.cpp Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,1315 @@
+// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// f32\etshell\ts_edshl.cpp
+// CLineEdit and CShell code
+//
+//
+
+
+#include <e32hal.h>
+#include "ts_std.h"
+#include "ts_clicomp.h"
+#include "cleanuputils.h"
+
+CLineEdit* CShell::TheEditor;
+CFileMan* CShell::TheFileMan;
+TBuf<KMaxFileName> CShell::currentPath;
+RFs CShell::TheFs;
+CConsoleBase* CShell::TheConsole;
+CCliCompleter* CShell::TheCliCompleter;
+
+class CFileManObserver : public MFileManObserver
+ {
+ TControl NotifyFileManEnded();
+ };
+
+MFileManObserver::TControl CFileManObserver::NotifyFileManEnded()
+//
+// Print out what CFileMan is doing
+//
+ {
+
+ TInt err=CShell::TheFileMan->GetLastError();
+ TFileName srcfile;
+ CShell::TheFileMan->GetCurrentSource(srcfile);
+ if (err!=KErrNone)
+ {
+ if(err == KErrNotReady)
+ {
+ FOREVER
+ {
+ CShell::TheConsole->Printf(_L("Not ready - Retry? [y/n]\n"));
+ TChar key = CShell::TheConsole->Getch();
+ key.UpperCase();
+ if(key == 'Y')
+ {
+ return(MFileManObserver::ERetry);
+ }
+ if(key == 'N')
+ {
+ return(MFileManObserver::EAbort);
+ }
+ }
+ }
+ else
+ {
+ CShell::TheConsole->Printf(_L("Error %d\n"),err);
+ }
+ }
+ else
+ {
+ switch (CShell::TheFileMan->CurrentAction())
+ {
+ case CFileMan::ECopy:
+ CShell::TheConsole->Printf(_L("Copied %S\n"),&srcfile);
+ break;
+ case CFileMan::EAttribs:
+ CShell::TheConsole->Printf(_L("Setting Attributes for %S\n"),&srcfile);
+ break;
+ case CFileMan::EDelete:
+ CShell::TheConsole->Printf(_L("Deleted %S\n"),&srcfile);
+ break;
+ case CFileMan::EMove:
+ CShell::TheConsole->Printf(_L("Moved %S\n"),&srcfile);
+ break;
+ case CFileMan::ERename:
+ CShell::TheConsole->Printf(_L("Renamed %S\n"),&srcfile);
+ break;
+ case CFileMan::ERmDir:
+ CShell::TheConsole->Printf(_L("RmDir deleted %S\n"),&srcfile);
+ break;
+ default:
+ CShell::TheConsole->Printf(_L("Unknown action %S\n"),&srcfile);
+ break;
+ }
+ }
+ return(MFileManObserver::EContinue);
+ }
+
+LOCAL_C TInt charToDrive(TChar aChar,TInt& aDrive)
+//
+// Convert the drive character to a drive index.
+//
+ {
+
+ TInt r=RFs::CharToDrive(aChar,aDrive);
+ return(r);
+ }
+
+CLineEdit::CLineEdit()
+//
+// Constructor
+//
+ {
+ }
+
+
+CLineEdit::~CLineEdit()
+//
+// Destroy the line editor
+//
+ {
+
+ if (iHistory)
+ {
+ TInt count=iHistory->Count();
+ while (count--)
+ User::Free((*iHistory)[count]);
+ delete iHistory;
+ }
+ }
+
+CLineEdit* CLineEdit::NewL(CConsoleBase* aConsole,TInt aMaxHistory)
+//
+// Create a new line editor
+//
+ {
+
+ CLineEdit* pE=new(ELeave) CLineEdit;
+ CleanupStack::PushL(pE);
+ pE->iHistory=new(ELeave) CArrayFixFlat<HBufC*>(aMaxHistory+2);
+ pE->iConsole=aConsole;
+ pE->iMaxHistory=aMaxHistory;
+ pE->iWidth=CShell::TheConsole->ScreenSize().iWidth;
+ pE->iHeight=CShell::TheConsole->ScreenSize().iHeight;
+
+ // !E32WindowServer Text Shell Console has frame
+ // of 2 characters each vertically and horizontally.
+ // !Windowserver Shell Console does not.
+ // Assume no Frame is present !
+ TFindServer findServer;
+ TFullName wsName;
+ TInt err = KErrNone;
+
+ pE->iFrameSizeChar=TSize(0,0);
+
+ // Find: !E32WindowServer is running?
+ while (err=findServer.Next(wsName), err==KErrNone)
+ {
+ if(err=wsName.FindF(KE32WindowServer), err!=KErrNotFound)
+ {
+ // E32WindowServer is running.
+ // Frame is present ! Frame Size is (2,2) !
+ pE->iFrameSizeChar=TSize(2,2);
+ break;
+ }
+ }
+
+ CleanupStack::Pop();
+ return(pE);
+ }
+
+TInt CLineEdit::Lines()
+//
+// The number of lines being edited.
+//
+ {
+
+ TInt nL=1;
+ if (Buf().Length()>=iWidth-iFrameSizeChar.iWidth-iOrigin)
+ nL+=(Buf().Length()+iOrigin)/(iWidth-iFrameSizeChar.iWidth);
+ return(nL);
+ }
+
+TPoint CLineEdit::Where()
+//
+// Return the real cursor position.
+//
+ {
+
+ if (iPos>=(iWidth-iFrameSizeChar.iWidth-iOrigin))
+ return(TPoint((iPos+iOrigin)%(iWidth-iFrameSizeChar.iWidth),((iPos+iOrigin)/(iWidth-iFrameSizeChar.iWidth))+iLine));
+ return(TPoint(iPos+iOrigin,iLine));
+ }
+
+void CLineEdit::ClearLine()
+//
+// Clears the line being edited.
+//
+ {
+
+ if (Buf().Length())
+ {
+ TInt nL=Lines();
+ while (nL--)
+ {
+ iConsole->SetPos(nL ? 0 : iOrigin,iLine+nL);
+ iConsole->ClearToEndOfLine();
+ }
+ Buf().Zero();
+ iPos=0;
+ }
+ }
+
+void CLineEdit::ClearLast(TInt aCnt)
+//
+// Clears the last aCnt characters.
+//
+ {
+
+ TInt aPos=iPos;
+ iPos=((TInt)Buf().Length())-aCnt;
+ while (iPos<((TInt)Buf().Length()))
+ {
+ TPoint p=Where();
+ iConsole->SetCursorPosAbs(p);
+ iConsole->ClearToEndOfLine();
+ iPos+=(iWidth-p.iX);
+ }
+ iPos=aPos;
+ }
+
+void CLineEdit::Recall()
+//
+// Recall a line for editing.
+//
+ {
+
+ if (iRecall!=(-1))
+ {
+ ClearLine();
+ HBufC* pL=(*iHistory)[iRecall];
+ Buf()=(*pL);
+ iConsole->Write(Buf());
+ iPos=Buf().Length();
+ TInt nL=Lines();
+ if ((iLine+nL)>iHeight)
+ iLine -= iLine + nL - iHeight;
+
+ }
+ }
+
+TInt CLineEdit::WordLeft()
+//
+// Position the cursor to the next word left.
+//
+ {
+
+ TInt x=iPos-1;
+ while (x && TChar(Buf()[x]).IsSpace())
+ x--;
+ while (x && TChar(Buf()[x]).IsGraph())
+ x--;
+ if (TChar(Buf()[x]).IsSpace())
+ x++;
+ return(x);
+ }
+
+TInt CLineEdit::WordRight()
+//
+// Position the cursor to the next word right.
+//
+ {
+
+ TInt x=iPos;
+ while (x<(TInt)Buf().Length() && TChar(Buf()[x]).IsGraph())
+ x++;
+ while (x<(TInt)Buf().Length() && TChar(Buf()[x]).IsSpace())
+ x++;
+ return(x);
+ }
+
+void CLineEdit::Cursor()
+//
+// Position the cursor.
+//
+ {
+
+ iConsole->SetCursorPosAbs(Where());
+ }
+
+void CLineEdit::Refresh()
+//
+// Refresh the line.
+//
+ {
+
+ iConsole->SetCursorHeight(ECursorNone);
+ iConsole->SetPos(iOrigin,iLine);
+ iConsole->Write(Buf());
+ Cursor();
+ iConsole->SetCursorHeight(iMode==EEditOverWrite ? ECursorNormal : ECursorInsert);
+ }
+
+TLineEditAction CLineEdit::Edit(const TDesC& aPrompt, TDes* aBuf, TBool aNewLine)
+//
+// Start the editor or a single key fetch.
+//
+ {
+ iBuf = aBuf;
+
+ if(aNewLine)
+ {
+ iMode = EEditInsert;
+ iConsole->Write(aPrompt);
+ iConsole->SetCursorHeight(iMode == EEditOverWrite ? ECursorNormal : ECursorInsert);
+ iOrigin = iConsole->WhereX();
+ iLine = iConsole->WhereY();
+ }
+
+ if(iBuf->Length() == 0)
+ {
+ iPos = 0;
+ }
+
+ Refresh();
+
+ iRecall = (-1);
+ TInt hCount = iHistory->Count();
+
+ if (hCount > iMaxHistory)
+ {
+ hCount = iMaxHistory;
+ }
+
+ FOREVER
+ {
+ TChar gChar = iConsole->Getch();
+
+ switch (gChar)
+ {
+ case EKeyEscape:
+ ClearLine();
+ iRecall=(-1);
+ break;
+ case EKeyHome:
+ iPos=0;
+ Cursor();
+ break;
+ case EKeyLeftArrow:
+ if (iPos)
+ {
+ if(iConsole->KeyModifiers()==EModifierCtrl)
+ iPos=WordLeft();
+ else
+ iPos--;
+ Cursor();
+ }
+ break;
+ case EKeyRightArrow:
+ if (iPos<((TInt)Buf().Length()))
+ {
+ if(iConsole->KeyModifiers()==EModifierCtrl)
+ iPos=WordRight();
+ else
+ iPos++;
+ Cursor();
+ }
+ break;
+ case EKeyEnd:
+ iPos=((TInt)Buf().Length());
+ Cursor();
+ break;
+ case EKeyPageUp:
+ if (hCount==0)
+ break;
+ iRecall=hCount-1;
+ Recall();
+ break;
+ case EKeyUpArrow:
+ if (iRecall==(-1)) // Beginning of history
+ {
+ if (hCount==0)
+ break;
+ iRecall=0;
+ }
+ else if (iRecall>=(hCount-1)) // End
+ {
+ ClearLine();
+ iRecall=(-1);
+ break;
+ }
+ else
+ iRecall++;
+ Recall();
+ break;
+ case EKeyDownArrow:
+ if (iRecall==(-1))
+ {
+ if (hCount==0)
+ break;
+ iRecall=hCount-1;
+ }
+ else if (iRecall==0)
+ {
+ ClearLine();
+ iRecall=(-1);
+ break;
+ }
+ else
+ iRecall--;
+ Recall();
+ break;
+ case EKeyPageDown:
+ if (hCount==0)
+ break;
+ iRecall=0;
+ Recall();
+ break;
+
+ case EKeyEnter:
+ NewLine();
+ StoreBufferHistory();
+ return EShellCommand;
+
+ case EKeyBackspace:
+ if (iPos)
+ {
+ TInt iN=1;
+ if (iConsole->KeyModifiers()==EModifierCtrl)
+ iN=iPos-WordLeft();
+ ClearLast(iN);
+ iPos-=iN;
+ Buf().Delete(iPos,iN);
+ Refresh();
+ }
+ break;
+ case EKeyDelete:
+ if (iPos<((TInt)Buf().Length()))
+ {
+ TInt iN=1;
+ if (iConsole->KeyModifiers()==EModifierCtrl)
+ iN=WordRight()-iPos;
+ ClearLast(iN);
+ Buf().Delete(iPos,iN);
+ Refresh();
+ }
+ break;
+
+ case EKeyInsert:
+ iMode=(iMode==EEditOverWrite ? EEditInsert : EEditOverWrite);
+ iConsole->SetCursorHeight(iMode==EEditOverWrite ? ECursorNormal : ECursorInsert);
+ break;
+
+ case EKeyTab:
+ return ECommandCompletion;
+
+ default:
+ if (!gChar.IsPrint())
+ break;
+ if (iMode==EEditOverWrite && iPos<((TInt)Buf().Length()))
+ Buf()[iPos++]=(TText)gChar;
+ else if (Buf().Length()<KShellMaxCommandLine)
+ {
+ TInt oL=Lines();
+ TBuf<0x02> b;
+ b.Append(gChar);
+ Buf().Insert(iPos++,b);
+ TInt nL=Lines();
+ if (nL!=oL)
+ {
+ iConsole->SetCursorHeight(ECursorNone);
+ iConsole->SetPos(0,iLine+oL-1);
+ iConsole->Write(_L("\n"));
+ iConsole->SetPos(0,iLine);
+ if (iLine+nL>iHeight-iFrameSizeChar.iHeight)
+ iLine=iHeight-iFrameSizeChar.iHeight-nL;
+ }
+ }
+ else
+ {
+ iConsole->Write(_L("\7"));
+ iConsole->SetPos((iOrigin+iPos)%(iWidth-iFrameSizeChar.iWidth),iLine+Lines()-1);
+ break;
+ }
+ Refresh();
+ }
+ }
+ }
+
+void CLineEdit::NewLine()
+ {
+ iConsole->SetCursorHeight(ECursorNone);
+ iLine += (Lines() - 1);
+ iConsole->SetPos(0, iLine);
+ iConsole->Write(_L("\n")); // Just a line feed
+ iRecall = (-1);
+ }
+
+void CLineEdit::StoreBufferHistory()
+ {
+ Buf().TrimRight();
+
+ if (Buf().Length()>=1)
+ {
+
+ //-- find out if we already have exactly the same command in the history.
+ //-- if it is there, don't add a new item, just move it to the top
+ for(TInt i=0; i<iHistory->Count(); ++i)
+ {
+ HBufC* pCmd = iHistory->At(i);
+ const TDesC& cmdLine = pCmd->Des();
+ if(cmdLine == Buf())
+ {
+ iHistory->Delete(i);
+ TRAP_IGNORE(iHistory->InsertL(0, pCmd));
+ return;
+ }
+ }
+
+ if (iHistory->Count()==iMaxHistory+1)
+ {
+ User::Free((*iHistory)[iMaxHistory]);
+ iHistory->Delete(iMaxHistory);
+ }
+
+ HBufC* pB=Buf().Alloc();
+ if(pB != NULL)
+ {
+ TRAP_IGNORE(iHistory->InsertL(0, pB));
+ }
+ }
+ }
+
+//////////////////////////////////////
+//CShell
+//////////////////////////////////////
+TShellCommand::TShellCommand(const TDesC& aName,const TDesC& aHelp,const TDesC& aHelpDetail,TUint aSwitches,TInt (*aFunction)(TDes&,TUint))
+ :iName(aName),
+ iHelp(aHelp),
+ iHelpDetail(aHelpDetail),
+ iSwitchesSupported(aSwitches),
+ iFunction(aFunction)
+ {
+ }
+
+CShell* CShell::NewL()
+ {
+ CShell *pS = new(ELeave) CShell;
+ CleanupStack::PushL(pS);
+
+ // No need to PushL these, if CShell::NewL leaves then eshell
+ // fails in its entirety.
+ TheConsole = Console::NewL(_L("ESHELL"), TSize(KConsFullScreen, KConsFullScreen));
+ TheEditor = CLineEdit::NewL(TheConsole, KDefaultHistorySize);
+ TheCliCompleter = CCliCompleter::NewL();
+
+ CleanupStack::Pop();
+ return(pS);
+ }
+
+CShell::~CShell()
+ {
+ ShellFunction::TheShell=NULL;
+ TheFs.Close();
+ delete TheEditor;
+ delete TheFileMan;
+ delete TheConsole;
+ delete TheCliCompleter;
+ }
+
+void CShell::DoBanner()
+ {
+ TBuf<40> shlver=TheShellVersion.Name();
+ TheConsole->Printf(_L("ESHELL %S CFG="),&shlver);
+#ifdef _UNICODE
+ TheConsole->Printf(_L("U"));
+#endif
+#ifdef _DEBUG
+ TheConsole->Printf(_L("DEB\r\n"));
+#else
+ TheConsole->Printf(_L("REL\r\n"));
+#endif
+
+#if !defined(__WINS__)
+ TMachineStartupType reason;
+ UserHal::StartupReason(reason);
+
+ switch (reason)
+ {
+ case EStartupCold: TheConsole->Printf(_L("Cold Start\n")); break;
+ case EStartupColdReset: TheConsole->Printf(_L("Cold Reset\n")); break;
+ case EStartupNewOs: TheConsole->Printf(_L("New OS\n")); break;
+ case EStartupPowerFail: TheConsole->Printf(_L("Power failed\n")); break;
+ case EStartupWarmReset: TheConsole->Printf(_L("Warm Reset\n")); break;
+ case EStartupKernelFault:
+
+ TInt faultno;
+ UserHal::FaultReason(faultno);
+ if (faultno == 0x10000000)
+ {
+ TheConsole->Printf(_L("Kernel Exception\n"));
+ }
+ else
+ {
+ TExcInfo exceptInfo;
+ UserHal::ExceptionInfo(exceptInfo);
+ TUint32 decode[3];
+ decode[0]=TUint32(exceptInfo.iCodeAddress);
+ decode[1]=TUint32(exceptInfo.iDataAddress);
+ decode[2]=0;
+
+ // interpret decode as null-terminated string
+ TPtrC category((TText*)&decode[0]);
+
+ if (faultno >= 0x10000)
+ TheConsole->Printf(_L("Kernel PANIC: %S %d\n"),&category, faultno-0x10000);
+ else
+ TheConsole->Printf(_L("Kernel FAULT: %S %d\n"),&category, faultno);
+ }
+ break;
+ case EStartupSafeReset: TheConsole->Printf(_L("Safe Reset\n")); break;
+ default:
+ TheConsole->Printf(_L("<?reason=%d>\n"), reason);
+ break;
+ }
+
+ if (reason==EStartupWarmReset || reason==EStartupKernelFault)
+ {
+ TInt excId;
+ TExcInfo excInfo;
+ UserHal::ExceptionId(excId);
+ UserHal::ExceptionInfo(excInfo);
+ TheConsole->Printf(_L("(last exception %d: code %08x data %08x extra %08x) "),
+ excId, excInfo.iCodeAddress, excInfo.iDataAddress, excInfo.iExtraData);
+ }
+#endif
+ TheConsole->Printf(_L("\r\n\nCopyright (c) 1998 Symbian Ltd\r\n\n"));
+ }
+
+_LIT(KRootdir,"?:\\");
+void CShell::RunL()
+ {
+ DoBanner();
+ TBuf<sizeof(KRootdir)> rootdir(KRootdir);
+ rootdir[0] = (TUint8) RFs::GetSystemDriveChar();
+ __ASSERT_ALWAYS(TheFs.Connect()==KErrNone,User::Panic(_L("Connect"),0));
+ __ASSERT_ALWAYS(TheFs.SetSessionPath(rootdir) == KErrNone, User::Panic(_L("Set Session path"),0));
+ __ASSERT_ALWAYS(TheFs.SessionPath(currentPath)==KErrNone,User::Panic(_L("Session path"),0));
+ TInt drive;
+ __ASSERT_ALWAYS(charToDrive(currentPath[0],drive)==KErrNone,User::Panic(_L("Invalid Path"),0));
+ drivePaths[drive]=currentPath;
+//
+// going to creat the shell's private path here
+// TheFs.
+//
+ CFileManObserver* fileManObserver=new(ELeave) CFileManObserver;
+ CleanupStack::PushL(fileManObserver);
+ TheFileMan=CFileMan::NewL(TheFs,fileManObserver);
+//
+ TBuf<16> startupFile=_L("0:\\AUTOEXEC.BAT");
+ TEntry startEntry;
+
+// Search all drives for autoexec.bat starting y,x,...,a then z
+
+ const TInt KIndexDriveA=0;
+ const TInt KIndexDriveY=24;
+ const TInt KIndexDriveZ=25;
+ TBuf<KMaxFileName>* searchDrive;
+
+ for (searchDrive=&drivePaths[KIndexDriveY];searchDrive>=&drivePaths[KIndexDriveA];searchDrive--)
+ {
+ currentPath=*searchDrive;
+ startupFile[0]=currentPath[0];
+ if (TheFs.Entry(startupFile,startEntry)==KErrNone)
+ {
+#ifdef __X86__
+ if (startEntry.iSize != 0)
+#endif
+ {
+ RunBatch(startupFile);
+ break;
+ }
+ }
+ if (searchDrive==&drivePaths[KIndexDriveA])
+ {
+ currentPath=drivePaths[KIndexDriveZ];
+ startupFile[0]=currentPath[0];
+ if (TheFs.Entry(startupFile,startEntry)==KErrNone)
+ {
+ RunBatch(startupFile);
+ break;
+ }
+ }
+ }
+
+ TLineEditAction result;
+ TBuf<KShellMaxCommandLine> commandText;
+ TBool exit = EFalse;
+
+ TInt tabCount = 0;
+ TBuf<KMaxPath + 1> prompt;
+ TBool newLine = ETrue;
+
+ FOREVER
+ {
+ __ASSERT_ALWAYS(TheFs.SessionPath(currentPath)==KErrNone,User::Panic(_L("Session path"),0));
+ TInt drive;
+ __ASSERT_ALWAYS(charToDrive(currentPath[0],drive)==KErrNone,User::Panic(_L("Invalid Path"),0));
+ drivePaths[drive] = currentPath;
+
+ if(currentPath[currentPath.Length() - 2] == KDriveDelimiter)
+ {
+ prompt = currentPath;
+ }
+ else
+ {
+ TInt i = (currentPath.LocateReverse(KPathDelimiter));
+ prompt = currentPath.Left(i);
+ }
+ prompt.Append(_L(">"));
+
+ result = TheEditor->Edit(prompt, &commandText, newLine);
+
+ switch(result)
+ {
+ case EShellCommand:
+ tabCount = 0;
+
+#if !defined(_EPOC)
+ if(commandText.CompareF(_L("EXIT")) == 0)
+ {
+ exit = ETrue;
+ break;
+ }
+#endif
+ commandText.Trim();
+ DoCommand(commandText);
+ commandText.Zero();
+
+ newLine = ETrue;
+
+ break;
+
+ case ECommandCompletion:
+ {
+ tabCount++;
+
+ TBuf<KMaxPath> knownPart;
+ TheCliCompleter->EstablishCompletionContext(commandText, TheEditor->Pos(), knownPart);
+
+ TInt preCompletedLength = knownPart.Length();
+
+ newLine = EFalse;
+
+ RPointerArray<HBufC> alternatives;
+ CleanupResetAndDestroyPushL(alternatives);
+
+ if(TheCliCompleter->AttemptCompletionL(knownPart, alternatives))
+ { // We completed something successfully
+ tabCount = 0;
+ }
+
+ if(knownPart.Length() > preCompletedLength)
+ {
+ commandText.Delete(TheEditor->Pos() - preCompletedLength, preCompletedLength);
+
+ // Don't allow the completion to cause the line buffer length to be exceeded
+ TInt excess = ((TheEditor->Pos() - preCompletedLength) + knownPart.Length()) - KShellMaxCommandLine;
+ if(excess > 0)
+ {
+ knownPart.Delete(knownPart.Length() - excess, excess);
+ }
+ else
+ {
+ excess = (commandText.Length() + knownPart.Length()) - KShellMaxCommandLine;
+
+ if(excess > 0)
+ {
+ commandText.Delete(commandText.Length() - excess, excess);
+ }
+ }
+
+ commandText.Insert(TheEditor->Pos() - preCompletedLength, knownPart);
+ TheEditor->SetPos(TheEditor->Pos() + (knownPart.Length() - preCompletedLength));
+ }
+
+ if(alternatives.Count() > 0)
+ {
+ if(tabCount == 2)
+ {
+ tabCount = 0;
+
+ TheCliCompleter->DisplayAlternatives(alternatives);
+ newLine = ETrue;
+ }
+ }
+
+ CleanupStack::PopAndDestroy(&alternatives);
+
+ break;
+ }
+
+ case ENoAction:
+ default:
+ tabCount = 0;
+ break;
+ }
+
+ if(exit)
+ {
+ break;
+ }
+ }
+
+ CleanupStack::PopAndDestroy(fileManObserver);
+ }
+
+void CShell::DoCommand(TDes& aCommand)
+//
+// Evaluate the commandline and run the command or file
+//
+ {
+
+ aCommand.TrimAll();
+
+ const TShellCommand* commandPtr=&iCommand[0];
+ for (;commandPtr<=&iCommand[ENoShellCommands-1];commandPtr++)
+ {
+ TInt length=commandPtr->iName.Length();
+ if ((aCommand.Length()>length && aCommand.Left(length).CompareF(commandPtr->iName)==0 && !TChar(aCommand[length]).IsAlphaDigit())
+ || (aCommand.Length()==length && aCommand.CompareF(commandPtr->iName)==0))
+ {
+ aCommand.Delete(0,length);
+ break;
+ }
+ }
+
+ if (commandPtr<=&iCommand[ENoShellCommands-1])
+ {
+ if (aCommand.Find(_L("/?"))>=0)
+ PrintHelp(commandPtr);
+ else // No /? switch
+ {
+ TUint switchesSet=0;
+ TInt r;
+ while ((r=aCommand.Locate('/'))!=KErrNotFound)
+ {
+ TChar switchChar='\0';
+ TInt switchInt=switchChar;
+ if ((r+1)==aCommand.Length() || (switchChar=aCommand[r+1]).IsAlpha()==EFalse)
+ {
+ TheConsole->Printf(_L("Invalid switch - \"%c\".\n"),switchInt);
+ return;
+ }
+ switchChar.UpperCase();
+ switchesSet|=(1<<((TInt)switchChar-'A'));
+ TChar extraChar;
+ if ((r+2)<aCommand.Length() && (extraChar=aCommand[r+2])!=' ' && extraChar!='/')
+ {
+ TInt switchInt=switchChar;
+ TInt extraInt=extraChar; // Gcc debugger warning if pass TChar to ...
+ TheConsole->Printf(_L("Parameter format not correct - \"%c%c\".\n"),switchInt,extraInt);
+ return;
+ }
+ aCommand.Delete(r,2);
+ }
+ if (switchesSet&~commandPtr->iSwitchesSupported)
+ {
+ TheConsole->Printf(_L("Switch not supported\n"));
+ return;
+ }
+ aCommand.Trim();
+
+ // RUN SHELL FUNCTION
+ r=commandPtr->iFunction(aCommand,switchesSet);
+ if (r!=KErrNone)
+ {
+ PrintError(r);
+ }
+ }
+ }
+ else //Generic commands
+ {
+ TInt r;
+
+ if (aCommand.CompareF(_L("HELP"))==0)
+ PrintHelp();
+ else if (aCommand.CompareF(_L("CLS"))==0)
+ TheConsole->ClearScreen();
+ else if (aCommand.Length()==2 && TChar(aCommand[0]).IsAlpha() && aCommand[1]==':')
+ ChangeDrive(aCommand[0]);
+ else if (aCommand.Length()!=0)
+ {
+ r=RunBatch(aCommand);
+ if (r != KErrNone) // Typically KErrNotFound, KErrBadName, KErrLocked...
+ r=RunExecutable(aCommand,ETrue);
+ if (r!=KErrNone)
+ PrintError(r);
+ }
+ }
+ }
+
+void CShell::PrintHelp()
+ {
+
+ for(const TShellCommand* commandPtr=&iCommand[0];commandPtr<=&iCommand[ENoShellCommands-1];commandPtr++)
+ {
+ OutputStringToConsole(ETrue,_L("%- 10S%S\n"),&commandPtr->iName,&commandPtr->iHelp);
+ }
+
+ }
+
+void CShell::PrintHelp(const TShellCommand* aCommand)
+ {
+ OutputStringToConsole(ETrue,_L("%S\n\n %S "),&aCommand->iHelp,&aCommand->iName);
+ OutputStringToConsole(ETrue,_L("%S\n\n"),&aCommand->iHelpDetail);
+ }
+
+void CShell::PrintError(TInt aError)
+ {
+ switch (aError)
+ {
+ case KErrAlreadyExists:
+ TheConsole->Printf(_L("Already exists\n"));
+ break;
+ case KErrCorrupt:
+ TheConsole->Printf(_L("Corrupt or unformatted drive\n"));
+ break;
+ case KErrNotSupported:
+ TheConsole->Printf(_L("Not supported\n"));
+ break;
+ case KErrGeneral:
+ TheConsole->Printf(_L("General Error\n"));
+ break;
+ case KErrNotFound:
+ TheConsole->Printf(_L("Not found\n"));
+ break;
+ case KErrPathNotFound:
+ TheConsole->Printf(_L("Path not found\n"));
+ break;
+ case KErrBadName:
+ TheConsole->Printf(_L("Bad name\n"));
+ break;
+ case KErrNotReady:
+ TheConsole->Printf(_L("Drive not ready\n"));
+ break;
+ case KErrAccessDenied:
+ TheConsole->Printf(_L("Access denied\n"));
+ break;
+ case KErrEof:
+ TheConsole->Printf(_L("Unexpected end of file\n"));
+ break;
+ case KErrTooBig:
+ TheConsole->Printf(_L("Too Big\n"));
+ break;
+ default:
+ TheConsole->Printf(_L("Error %d\n"),aError);
+ }
+ }
+
+void CShell::ChangeDrive(TChar aDrive)
+ {
+
+ TInt drive;
+ __ASSERT_ALWAYS(charToDrive(aDrive,drive)==KErrNone,User::Panic(_L("Invalid drive letter"),0));
+ TDriveList driveList;
+ TheFs.DriveList(driveList);
+ if (driveList[drive])
+ {
+ TInt r=TheFs.SetSessionPath(drivePaths[drive]);
+ if (r!=KErrNone)
+ PrintError(r);
+ }
+ else
+ PrintError(KErrNotFound);
+ }
+
+TInt CShell::RunBatch(TDes& aCommand)
+ {
+ TBool appendedBat=EFalse;
+ if (aCommand.FindF(_L(".BAT"))<0 && (aCommand.Length()+4)<=KShellMaxCommandLine)
+ {
+ aCommand.Append(_L(".BAT"));
+ appendedBat=ETrue;
+ }
+ RFile file;
+ TInt r=file.Open(TheFs,aCommand,EFileStreamText);
+ if (r!=KErrNone)
+ {
+ if (appendedBat)
+ aCommand.Delete(aCommand.Length()-4,4);
+ return r;
+ }
+ __ASSERT_ALWAYS(TheFs.SessionPath(currentPath)==KErrNone,User::Panic(_L("Session path"),0));
+ TInt drive;
+ __ASSERT_ALWAYS(charToDrive(currentPath[0],drive)==KErrNone,User::Panic(_L("Invalid drive letter"),0));
+ drivePaths[drive]=currentPath;
+ TInt filePos=0;
+
+ TBuf<KShellMaxCommandLine> readBuf;
+
+ FOREVER
+ {
+#ifdef _UNICODE
+ TBuf8<KShellMaxCommandLine> buf8;
+ r=file.Read(filePos,buf8);
+ readBuf.Copy(buf8);
+#else
+ r=file.Read(filePos,readBuf);
+#endif
+ if (r!=KErrNone)
+ {
+ PrintError(r);
+ break;
+ }
+
+ r=readBuf.Locate('\n');
+ if (r==KErrNotFound)
+ {
+ r=readBuf.Length();
+ filePos+=r;
+ }
+
+ else if (r<=1) // Indicates /n before batch file instructions
+ {
+ TInt temp=readBuf.Length();
+ readBuf.TrimLeft(); // Removes initial /n
+ temp-=readBuf.Length();
+ r=readBuf.Locate('\n');
+ if(r==KErrNotFound)
+ {
+ r=readBuf.Length();
+ }
+ filePos+=r+1+temp; // Offsets filePos correctly in the file
+ }
+ else filePos+=r+1;
+
+ if (readBuf.Length()==0)
+ break;
+ readBuf.SetLength(r);
+
+ readBuf.Trim();
+ TheFs.SessionPath(currentPath);
+ TheConsole->Printf(currentPath);
+ TheConsole->Printf(_L(">%S\n"),&readBuf);
+
+ // If command was a drive change, reset the current path here
+ if (readBuf.Length()==2 && TChar(readBuf[0]).IsAlpha() && readBuf[1]==':')
+ {
+ TInt drive;
+ __ASSERT_ALWAYS(charToDrive(readBuf[0],drive)==KErrNone,User::Panic(_L("Invalid drive letter"),0));
+
+ TDriveList driveList;
+ TheFs.DriveList(driveList);
+ if (driveList[drive])
+ {
+ TInt r=TheFs.SetSessionPath(drivePaths[drive]);
+ if (r!=KErrNone)
+ PrintError(r);
+ currentPath=drivePaths[drive];
+ }
+ else
+ PrintError(KErrNotFound);
+ }
+
+ else if (readBuf.Length()<3 || readBuf.Left(3).CompareF(_L("REM"))!=0)
+ DoCommand(readBuf);
+ }
+ file.Close();
+ return KErrNone;
+ }
+
+
+
+TInt CShell::RunExecutable(TDes& aCommand,TBool aWaitForCompletion)
+ {
+ aCommand.Trim();
+ TBuf<KShellMaxCommandLine> parameters(0);
+ TInt r=aCommand.Locate(' '); // can't be the last character because of Trim()
+ if (r!=KErrNotFound)
+ {
+ parameters=aCommand.Mid(r+1);
+ aCommand.SetLength(r);
+ }
+ // aCommand is now just the executable
+ if (aCommand.FindF(_L(".EXE"))==KErrNotFound && (aCommand.Length()+4)<=KShellMaxCommandLine)
+ aCommand.Append(_L(".EXE"));
+ TInt specificExe=1;
+ if (aCommand.Length()>2 && aCommand[1]==':' && aCommand[2]!='\\')
+ {
+ if (TChar(aCommand[0]).IsAlpha())
+ {
+ TInt drive;
+ __ASSERT_ALWAYS(charToDrive(aCommand[0],drive)==KErrNone,User::Panic(_L("Invalid drive letter"),0));
+ currentPath=drivePaths[drive];
+ aCommand.Delete(0,2);
+ if (aCommand.Length()+currentPath.Length() <= KShellMaxCommandLine)
+ aCommand.Insert(0,currentPath);
+ }
+ else
+ return KErrNotFound;
+ }
+ if (aCommand.Length()>2 && aCommand[1]!=':')
+ {
+ if(aCommand[0]!='\\')
+ {
+ if (aCommand.Locate('\\')==KErrNotFound)
+ specificExe=0; // no drive, no path - be ready to let the system find it...
+ if (aCommand.Length()+currentPath.Length() <= KShellMaxCommandLine)
+ aCommand.Insert(0,currentPath);
+ }
+ else
+ if (aCommand.Length()+currentPath.Left(2).Length() <= KShellMaxCommandLine)
+ aCommand.Insert(0,currentPath.Left(2));
+ }
+
+ RFile file;
+ r=file.Open(CShell::TheFs,aCommand,EFileStream);
+ if (r!=KErrNone)
+ {
+ if (specificExe)
+ return(r);
+ r=aCommand.LocateReverse('\\'); // must exist because this is a full filename
+ aCommand.Delete(0,r+1);
+ }
+ else
+ {
+ // If the file can be opened, it *must* exist, and we'll assume that the user
+ // really intended this specific file.
+ specificExe=1;
+ file.Close();
+ }
+
+ RProcess newProcess;
+ r=newProcess.Create(aCommand,parameters);
+
+ if (r==KErrNone) // Executable can run OK
+ {
+ TRequestStatus status=KRequestPending;
+ if(aWaitForCompletion)
+ newProcess.Logon(status);
+ newProcess.Resume();
+ if (aWaitForCompletion)
+ User::WaitForRequest(status);
+ if (aWaitForCompletion && (newProcess.ExitType()!=EExitKill || status!=KErrNone))
+ {
+ TBuf<KMaxExitCategoryName> exitCat=newProcess.ExitCategory();
+ TheConsole->Printf(_L("\nExit type %d,%d,%S\n"),newProcess.ExitType(),newProcess.ExitReason(),&exitCat);
+ }
+
+ newProcess.Close(); // get rid of our handle
+ return KErrNone;
+ }
+
+ // Executable could not be run
+
+#if 0 //defined(__EPOC32__)
+ if (specificExe)
+ {
+ // Use class CDllChecker to check the dependencies
+ // for MARM exes only
+ CDllChecker check;
+
+ // Create an array to store each dependency's name, Uid and result
+ TRAPD(leaveCode,(check.ConstructL()));
+
+ if (leaveCode!=KErrNone) // If function leaves
+ {
+ TheConsole->Printf(_L("Dependency checking failed due to error %d\n"), leaveCode);
+ return(KErrNone);
+ }
+
+ TInt result=KErrNone;
+ TRAP(result,(check.GetImportDataL(aCommand,NULL)));
+
+ if (result==KErrNone)
+ {
+ check.ListArray(); // Print out the results of DllCheck
+ return(KErrNone);
+ }
+ }
+#endif
+ return (r);
+}
+
+void CShell::SetCurrentPath(const TDesC& aDes)
+//
+// Set the current Directory
+//
+ {
+
+ __ASSERT_DEBUG(currentPath.MaxLength()>=aDes.Length(),Panic(EShellFilePathTooBig));
+ currentPath=aDes;
+ }
+
+TDes& CShell::CurrentPath()
+//
+// Accessor function
+//
+ {
+ return currentPath;
+ }
+
+
+
+void CShell::SetDrivePath(const TDesC& aDrivePath)
+//
+// Set the drive path
+//
+ {
+
+ __ASSERT_DEBUG(aDrivePath.Length()>=3 && aDrivePath[1]==KDriveDelimiter,Panic(EShellBadDrivePath));
+ TChar drvLetter=aDrivePath[0];
+ __ASSERT_DEBUG(drvLetter.IsAlpha(),Panic(EShellBadDrivePath));
+ TInt drvNum;
+ __ASSERT_ALWAYS(charToDrive(drvLetter,drvNum)==KErrNone,User::Panic(_L("Invalid drive letter"),0));
+ drivePaths[drvNum]=aDrivePath;
+ }
+
+
+TKeyCode CShell::OutputStringToConsole(TBool aPageSwitch,TRefByValue<const TDesC> aFmt,... )
+//function for output of a sring to console
+//aPageSwitch flag indicates that output should be page-by-page
+ {
+ //create an object to truncate argument list substitution
+ SimpleOverflowTruncate overflow;
+ VA_LIST list;
+ VA_START(list,aFmt);
+
+ TBuf<0x140> aBuf;
+ //format output string using argument list
+
+ //coverity[uninit_use_in_call]
+ TRAP_IGNORE(aBuf.AppendFormatList(aFmt,list,&overflow)); // ignore leave in TTimeOverflowLeave::Overflow()
+
+ _LIT(KPrompt , "Press any key to continue\n");
+
+ return OutputStringToConsole(KPrompt,aPageSwitch,_L("%S"),&aBuf);
+ }
+
+TKeyCode CShell::OutputStringToConsole(const TDesC& aNotification,TBool aPageSwitch,TRefByValue<const TDesC> aFmt,...)
+ //function for output of a string to console aPageSwitch flag indicates that output should be page-by-page
+ //if aPageSwitch==ETrue user will be prompted with the message passed as aNotification
+ //code of key pressed will be returned as a return value
+ {
+ //create variable to store code of the key pressed by the user
+ TKeyCode key=EKeyNull;
+ //create an object to truncate argument list substitution
+ SimpleOverflowTruncate overflow;
+
+ VA_LIST list;
+ VA_START(list,aFmt);
+
+ TBuf<0x140> aBuf;
+ //format output string using argumen list
+
+ //coverity[uninit_use_in_call]
+ TRAP_IGNORE(aBuf.AppendFormatList(aFmt,list,&overflow)); // ignore leave in TTimeOverflowLeave::Overflow()
+ //if we are requested to wait for the user input at the end of each page, we check whether output of next piece of text will fit into the screen
+ if (aPageSwitch)
+ {
+ key=PageSwitchDisplay(aNotification);
+ }
+ //output current string
+ TheConsole->Write(aBuf);
+ return key;
+ }
+
+TKeyCode CShell::OutputStringToConsole(TBool aPageSwitch, const TDesC& aBuf)
+ {
+ _LIT(KPrompt , "Press any key to continue\n");
+
+ TKeyCode key=EKeyNull;
+
+ //if we are requested to wait for the user input at the end of each page, we check whether output of next piece of text will fit into the screen
+ if (aPageSwitch)
+ {
+ key = PageSwitchDisplay(KPrompt);
+ }
+ //output current string
+ TheConsole->Write(aBuf);
+
+ return key;
+ }
+
+TKeyCode CShell::PageSwitchDisplay(const TDesC& aNotification)
+ {
+ //create variable to store code of the key pressed by the user
+ TKeyCode key=EKeyNull;
+ //obtain a current cursor position
+ TInt line_count=TheConsole->WhereY();
+ //calculate how many lines is needed to output current string in the current screen rect
+ TInt add=(TheConsole->WhereX()+aNotification.Length())/(TheConsole->ScreenSize().iWidth-2);
+ if ((TheConsole->WhereX()+aNotification.Length())%(TheConsole->ScreenSize().iWidth-2))
+ {
+ add+=1;
+ }
+ //if we will not fit into the screen after output of the current string, then we should prompt for the user input to start new page
+ TInt notification_height=aNotification.Length()/(TheConsole->ScreenSize().iWidth-2);//we provide 2 additional characters for the frame
+ if (aNotification.Length()%(TheConsole->ScreenSize().iWidth-2))
+ {
+ notification_height+=1;
+ }
+ if (add<(TheConsole->ScreenSize().iHeight-2))
+ if ((line_count+add+notification_height)>=(TheConsole->ScreenSize().iHeight-4))
+ {
+ TInt previous_cursor_pos_x=TheConsole->WhereX();
+ TheConsole->Printf(_L("%S"),&aNotification);
+ key=TheConsole->Getch();
+ TheConsole->ClearScreen();
+ TheConsole->SetCursorPosAbs(TPoint (previous_cursor_pos_x,0)) ;
+ }
+ return key;
+ }