diff -r 000000000000 -r 96e5fb8b040d userlibandfileserver/fileserver/etshell/ts_edshl.cpp --- /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 +#include "ts_std.h" +#include "ts_clicomp.h" +#include "cleanuputils.h" + +CLineEdit* CShell::TheEditor; +CFileMan* CShell::TheFileMan; +TBuf 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(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() 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; iCount(); ++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("\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 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* 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 commandText; + TBool exit = EFalse; + + TInt tabCount = 0; + TBuf 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 knownPart; + TheCliCompleter->EstablishCompletionContext(commandText, TheEditor->Pos(), knownPart); + + TInt preCompletedLength = knownPart.Length(); + + newLine = EFalse; + + RPointerArray 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)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 readBuf; + + FOREVER + { +#ifdef _UNICODE + TBuf8 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 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 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 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 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; + }