First public contribution.
1 // Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // f32\etshell\ts_edshl.cpp
15 // CLineEdit and CShell code
22 #include "ts_clicomp.h"
23 #include "cleanuputils.h"
25 CLineEdit* CShell::TheEditor;
26 CFileMan* CShell::TheFileMan;
27 TBuf<KMaxFileName> CShell::currentPath;
29 CConsoleBase* CShell::TheConsole;
30 CCliCompleter* CShell::TheCliCompleter;
32 class CFileManObserver : public MFileManObserver
34 TControl NotifyFileManEnded();
37 MFileManObserver::TControl CFileManObserver::NotifyFileManEnded()
39 // Print out what CFileMan is doing
43 TInt err=CShell::TheFileMan->GetLastError();
45 CShell::TheFileMan->GetCurrentSource(srcfile);
48 if(err == KErrNotReady)
52 CShell::TheConsole->Printf(_L("Not ready - Retry? [y/n]\n"));
53 TChar key = CShell::TheConsole->Getch();
57 return(MFileManObserver::ERetry);
61 return(MFileManObserver::EAbort);
67 CShell::TheConsole->Printf(_L("Error %d\n"),err);
72 switch (CShell::TheFileMan->CurrentAction())
75 CShell::TheConsole->Printf(_L("Copied %S\n"),&srcfile);
77 case CFileMan::EAttribs:
78 CShell::TheConsole->Printf(_L("Setting Attributes for %S\n"),&srcfile);
80 case CFileMan::EDelete:
81 CShell::TheConsole->Printf(_L("Deleted %S\n"),&srcfile);
84 CShell::TheConsole->Printf(_L("Moved %S\n"),&srcfile);
86 case CFileMan::ERename:
87 CShell::TheConsole->Printf(_L("Renamed %S\n"),&srcfile);
89 case CFileMan::ERmDir:
90 CShell::TheConsole->Printf(_L("RmDir deleted %S\n"),&srcfile);
93 CShell::TheConsole->Printf(_L("Unknown action %S\n"),&srcfile);
97 return(MFileManObserver::EContinue);
100 LOCAL_C TInt charToDrive(TChar aChar,TInt& aDrive)
102 // Convert the drive character to a drive index.
106 TInt r=RFs::CharToDrive(aChar,aDrive);
110 CLineEdit::CLineEdit()
118 CLineEdit::~CLineEdit()
120 // Destroy the line editor
126 TInt count=iHistory->Count();
128 User::Free((*iHistory)[count]);
133 CLineEdit* CLineEdit::NewL(CConsoleBase* aConsole,TInt aMaxHistory)
135 // Create a new line editor
139 CLineEdit* pE=new(ELeave) CLineEdit;
140 CleanupStack::PushL(pE);
141 pE->iHistory=new(ELeave) CArrayFixFlat<HBufC*>(aMaxHistory+2);
142 pE->iConsole=aConsole;
143 pE->iMaxHistory=aMaxHistory;
144 pE->iWidth=CShell::TheConsole->ScreenSize().iWidth;
145 pE->iHeight=CShell::TheConsole->ScreenSize().iHeight;
147 // !E32WindowServer Text Shell Console has frame
148 // of 2 characters each vertically and horizontally.
149 // !Windowserver Shell Console does not.
150 // Assume no Frame is present !
151 TFindServer findServer;
155 pE->iFrameSizeChar=TSize(0,0);
157 // Find: !E32WindowServer is running?
158 while (err=findServer.Next(wsName), err==KErrNone)
160 if(err=wsName.FindF(KE32WindowServer), err!=KErrNotFound)
162 // E32WindowServer is running.
163 // Frame is present ! Frame Size is (2,2) !
164 pE->iFrameSizeChar=TSize(2,2);
173 TInt CLineEdit::Lines()
175 // The number of lines being edited.
180 if (Buf().Length()>=iWidth-iFrameSizeChar.iWidth-iOrigin)
181 nL+=(Buf().Length()+iOrigin)/(iWidth-iFrameSizeChar.iWidth);
185 TPoint CLineEdit::Where()
187 // Return the real cursor position.
191 if (iPos>=(iWidth-iFrameSizeChar.iWidth-iOrigin))
192 return(TPoint((iPos+iOrigin)%(iWidth-iFrameSizeChar.iWidth),((iPos+iOrigin)/(iWidth-iFrameSizeChar.iWidth))+iLine));
193 return(TPoint(iPos+iOrigin,iLine));
196 void CLineEdit::ClearLine()
198 // Clears the line being edited.
207 iConsole->SetPos(nL ? 0 : iOrigin,iLine+nL);
208 iConsole->ClearToEndOfLine();
215 void CLineEdit::ClearLast(TInt aCnt)
217 // Clears the last aCnt characters.
222 iPos=((TInt)Buf().Length())-aCnt;
223 while (iPos<((TInt)Buf().Length()))
226 iConsole->SetCursorPosAbs(p);
227 iConsole->ClearToEndOfLine();
233 void CLineEdit::Recall()
235 // Recall a line for editing.
242 HBufC* pL=(*iHistory)[iRecall];
244 iConsole->Write(Buf());
247 if ((iLine+nL)>iHeight)
248 iLine -= iLine + nL - iHeight;
253 TInt CLineEdit::WordLeft()
255 // Position the cursor to the next word left.
260 while (x && TChar(Buf()[x]).IsSpace())
262 while (x && TChar(Buf()[x]).IsGraph())
264 if (TChar(Buf()[x]).IsSpace())
269 TInt CLineEdit::WordRight()
271 // Position the cursor to the next word right.
276 while (x<(TInt)Buf().Length() && TChar(Buf()[x]).IsGraph())
278 while (x<(TInt)Buf().Length() && TChar(Buf()[x]).IsSpace())
283 void CLineEdit::Cursor()
285 // Position the cursor.
289 iConsole->SetCursorPosAbs(Where());
292 void CLineEdit::Refresh()
298 iConsole->SetCursorHeight(ECursorNone);
299 iConsole->SetPos(iOrigin,iLine);
300 iConsole->Write(Buf());
302 iConsole->SetCursorHeight(iMode==EEditOverWrite ? ECursorNormal : ECursorInsert);
305 TLineEditAction CLineEdit::Edit(const TDesC& aPrompt, TDes* aBuf, TBool aNewLine)
307 // Start the editor or a single key fetch.
315 iConsole->Write(aPrompt);
316 iConsole->SetCursorHeight(iMode == EEditOverWrite ? ECursorNormal : ECursorInsert);
317 iOrigin = iConsole->WhereX();
318 iLine = iConsole->WhereY();
321 if(iBuf->Length() == 0)
329 TInt hCount = iHistory->Count();
331 if (hCount > iMaxHistory)
333 hCount = iMaxHistory;
338 TChar gChar = iConsole->Getch();
353 if(iConsole->KeyModifiers()==EModifierCtrl)
361 if (iPos<((TInt)Buf().Length()))
363 if(iConsole->KeyModifiers()==EModifierCtrl)
371 iPos=((TInt)Buf().Length());
381 if (iRecall==(-1)) // Beginning of history
387 else if (iRecall>=(hCount-1)) // End
423 StoreBufferHistory();
424 return EShellCommand;
430 if (iConsole->KeyModifiers()==EModifierCtrl)
434 Buf().Delete(iPos,iN);
439 if (iPos<((TInt)Buf().Length()))
442 if (iConsole->KeyModifiers()==EModifierCtrl)
445 Buf().Delete(iPos,iN);
451 iMode=(iMode==EEditOverWrite ? EEditInsert : EEditOverWrite);
452 iConsole->SetCursorHeight(iMode==EEditOverWrite ? ECursorNormal : ECursorInsert);
456 return ECommandCompletion;
459 if (!gChar.IsPrint())
461 if (iMode==EEditOverWrite && iPos<((TInt)Buf().Length()))
462 Buf()[iPos++]=(TText)gChar;
463 else if (Buf().Length()<KShellMaxCommandLine)
468 Buf().Insert(iPos++,b);
472 iConsole->SetCursorHeight(ECursorNone);
473 iConsole->SetPos(0,iLine+oL-1);
474 iConsole->Write(_L("\n"));
475 iConsole->SetPos(0,iLine);
476 if (iLine+nL>iHeight-iFrameSizeChar.iHeight)
477 iLine=iHeight-iFrameSizeChar.iHeight-nL;
482 iConsole->Write(_L("\7"));
483 iConsole->SetPos((iOrigin+iPos)%(iWidth-iFrameSizeChar.iWidth),iLine+Lines()-1);
491 void CLineEdit::NewLine()
493 iConsole->SetCursorHeight(ECursorNone);
494 iLine += (Lines() - 1);
495 iConsole->SetPos(0, iLine);
496 iConsole->Write(_L("\n")); // Just a line feed
500 void CLineEdit::StoreBufferHistory()
504 if (Buf().Length()>=1)
507 //-- find out if we already have exactly the same command in the history.
508 //-- if it is there, don't add a new item, just move it to the top
509 for(TInt i=0; i<iHistory->Count(); ++i)
511 HBufC* pCmd = iHistory->At(i);
512 const TDesC& cmdLine = pCmd->Des();
516 TRAP_IGNORE(iHistory->InsertL(0, pCmd));
521 if (iHistory->Count()==iMaxHistory+1)
523 User::Free((*iHistory)[iMaxHistory]);
524 iHistory->Delete(iMaxHistory);
527 HBufC* pB=Buf().Alloc();
530 TRAP_IGNORE(iHistory->InsertL(0, pB));
535 //////////////////////////////////////
537 //////////////////////////////////////
538 TShellCommand::TShellCommand(const TDesC& aName,const TDesC& aHelp,const TDesC& aHelpDetail,TUint aSwitches,TInt (*aFunction)(TDes&,TUint))
541 iHelpDetail(aHelpDetail),
542 iSwitchesSupported(aSwitches),
547 CShell* CShell::NewL()
549 CShell *pS = new(ELeave) CShell;
550 CleanupStack::PushL(pS);
552 // No need to PushL these, if CShell::NewL leaves then eshell
553 // fails in its entirety.
554 TheConsole = Console::NewL(_L("ESHELL"), TSize(KConsFullScreen, KConsFullScreen));
555 TheEditor = CLineEdit::NewL(TheConsole, KDefaultHistorySize);
556 TheCliCompleter = CCliCompleter::NewL();
564 ShellFunction::TheShell=NULL;
569 delete TheCliCompleter;
572 void CShell::DoBanner()
574 TBuf<40> shlver=TheShellVersion.Name();
575 TheConsole->Printf(_L("ESHELL %S CFG="),&shlver);
577 TheConsole->Printf(_L("U"));
580 TheConsole->Printf(_L("DEB\r\n"));
582 TheConsole->Printf(_L("REL\r\n"));
585 #if !defined(__WINS__)
586 TMachineStartupType reason;
587 UserHal::StartupReason(reason);
591 case EStartupCold: TheConsole->Printf(_L("Cold Start\n")); break;
592 case EStartupColdReset: TheConsole->Printf(_L("Cold Reset\n")); break;
593 case EStartupNewOs: TheConsole->Printf(_L("New OS\n")); break;
594 case EStartupPowerFail: TheConsole->Printf(_L("Power failed\n")); break;
595 case EStartupWarmReset: TheConsole->Printf(_L("Warm Reset\n")); break;
596 case EStartupKernelFault:
599 UserHal::FaultReason(faultno);
600 if (faultno == 0x10000000)
602 TheConsole->Printf(_L("Kernel Exception\n"));
607 UserHal::ExceptionInfo(exceptInfo);
609 decode[0]=TUint32(exceptInfo.iCodeAddress);
610 decode[1]=TUint32(exceptInfo.iDataAddress);
613 // interpret decode as null-terminated string
614 TPtrC category((TText*)&decode[0]);
616 if (faultno >= 0x10000)
617 TheConsole->Printf(_L("Kernel PANIC: %S %d\n"),&category, faultno-0x10000);
619 TheConsole->Printf(_L("Kernel FAULT: %S %d\n"),&category, faultno);
622 case EStartupSafeReset: TheConsole->Printf(_L("Safe Reset\n")); break;
624 TheConsole->Printf(_L("<?reason=%d>\n"), reason);
628 if (reason==EStartupWarmReset || reason==EStartupKernelFault)
632 UserHal::ExceptionId(excId);
633 UserHal::ExceptionInfo(excInfo);
634 TheConsole->Printf(_L("(last exception %d: code %08x data %08x extra %08x) "),
635 excId, excInfo.iCodeAddress, excInfo.iDataAddress, excInfo.iExtraData);
638 TheConsole->Printf(_L("\r\n\nCopyright (c) 1998 Symbian Ltd\r\n\n"));
641 _LIT(KRootdir,"?:\\");
645 TBuf<sizeof(KRootdir)> rootdir(KRootdir);
646 rootdir[0] = (TUint8) RFs::GetSystemDriveChar();
647 __ASSERT_ALWAYS(TheFs.Connect()==KErrNone,User::Panic(_L("Connect"),0));
648 __ASSERT_ALWAYS(TheFs.SetSessionPath(rootdir) == KErrNone, User::Panic(_L("Set Session path"),0));
649 __ASSERT_ALWAYS(TheFs.SessionPath(currentPath)==KErrNone,User::Panic(_L("Session path"),0));
651 __ASSERT_ALWAYS(charToDrive(currentPath[0],drive)==KErrNone,User::Panic(_L("Invalid Path"),0));
652 drivePaths[drive]=currentPath;
654 // going to creat the shell's private path here
657 CFileManObserver* fileManObserver=new(ELeave) CFileManObserver;
658 CleanupStack::PushL(fileManObserver);
659 TheFileMan=CFileMan::NewL(TheFs,fileManObserver);
661 TBuf<16> startupFile=_L("0:\\AUTOEXEC.BAT");
664 // Search all drives for autoexec.bat starting y,x,...,a then z
666 const TInt KIndexDriveA=0;
667 const TInt KIndexDriveY=24;
668 const TInt KIndexDriveZ=25;
669 TBuf<KMaxFileName>* searchDrive;
671 for (searchDrive=&drivePaths[KIndexDriveY];searchDrive>=&drivePaths[KIndexDriveA];searchDrive--)
673 currentPath=*searchDrive;
674 startupFile[0]=currentPath[0];
675 if (TheFs.Entry(startupFile,startEntry)==KErrNone)
678 if (startEntry.iSize != 0)
681 RunBatch(startupFile);
685 if (searchDrive==&drivePaths[KIndexDriveA])
687 currentPath=drivePaths[KIndexDriveZ];
688 startupFile[0]=currentPath[0];
689 if (TheFs.Entry(startupFile,startEntry)==KErrNone)
691 RunBatch(startupFile);
697 TLineEditAction result;
698 TBuf<KShellMaxCommandLine> commandText;
702 TBuf<KMaxPath + 1> prompt;
703 TBool newLine = ETrue;
707 __ASSERT_ALWAYS(TheFs.SessionPath(currentPath)==KErrNone,User::Panic(_L("Session path"),0));
709 __ASSERT_ALWAYS(charToDrive(currentPath[0],drive)==KErrNone,User::Panic(_L("Invalid Path"),0));
710 drivePaths[drive] = currentPath;
712 if(currentPath[currentPath.Length() - 2] == KDriveDelimiter)
714 prompt = currentPath;
718 TInt i = (currentPath.LocateReverse(KPathDelimiter));
719 prompt = currentPath.Left(i);
721 prompt.Append(_L(">"));
723 result = TheEditor->Edit(prompt, &commandText, newLine);
731 if(commandText.CompareF(_L("EXIT")) == 0)
738 DoCommand(commandText);
745 case ECommandCompletion:
749 TBuf<KMaxPath> knownPart;
750 TheCliCompleter->EstablishCompletionContext(commandText, TheEditor->Pos(), knownPart);
752 TInt preCompletedLength = knownPart.Length();
756 RPointerArray<HBufC> alternatives;
757 CleanupResetAndDestroyPushL(alternatives);
759 if(TheCliCompleter->AttemptCompletionL(knownPart, alternatives))
760 { // We completed something successfully
764 if(knownPart.Length() > preCompletedLength)
766 commandText.Delete(TheEditor->Pos() - preCompletedLength, preCompletedLength);
768 // Don't allow the completion to cause the line buffer length to be exceeded
769 TInt excess = ((TheEditor->Pos() - preCompletedLength) + knownPart.Length()) - KShellMaxCommandLine;
772 knownPart.Delete(knownPart.Length() - excess, excess);
776 excess = (commandText.Length() + knownPart.Length()) - KShellMaxCommandLine;
780 commandText.Delete(commandText.Length() - excess, excess);
784 commandText.Insert(TheEditor->Pos() - preCompletedLength, knownPart);
785 TheEditor->SetPos(TheEditor->Pos() + (knownPart.Length() - preCompletedLength));
788 if(alternatives.Count() > 0)
794 TheCliCompleter->DisplayAlternatives(alternatives);
799 CleanupStack::PopAndDestroy(&alternatives);
816 CleanupStack::PopAndDestroy(fileManObserver);
819 void CShell::DoCommand(TDes& aCommand)
821 // Evaluate the commandline and run the command or file
827 const TShellCommand* commandPtr=&iCommand[0];
828 for (;commandPtr<=&iCommand[ENoShellCommands-1];commandPtr++)
830 TInt length=commandPtr->iName.Length();
831 if ((aCommand.Length()>length && aCommand.Left(length).CompareF(commandPtr->iName)==0 && !TChar(aCommand[length]).IsAlphaDigit())
832 || (aCommand.Length()==length && aCommand.CompareF(commandPtr->iName)==0))
834 aCommand.Delete(0,length);
839 if (commandPtr<=&iCommand[ENoShellCommands-1])
841 if (aCommand.Find(_L("/?"))>=0)
842 PrintHelp(commandPtr);
847 while ((r=aCommand.Locate('/'))!=KErrNotFound)
849 TChar switchChar='\0';
850 TInt switchInt=switchChar;
851 if ((r+1)==aCommand.Length() || (switchChar=aCommand[r+1]).IsAlpha()==EFalse)
853 TheConsole->Printf(_L("Invalid switch - \"%c\".\n"),switchInt);
856 switchChar.UpperCase();
857 switchesSet|=(1<<((TInt)switchChar-'A'));
859 if ((r+2)<aCommand.Length() && (extraChar=aCommand[r+2])!=' ' && extraChar!='/')
861 TInt switchInt=switchChar;
862 TInt extraInt=extraChar; // Gcc debugger warning if pass TChar to ...
863 TheConsole->Printf(_L("Parameter format not correct - \"%c%c\".\n"),switchInt,extraInt);
866 aCommand.Delete(r,2);
868 if (switchesSet&~commandPtr->iSwitchesSupported)
870 TheConsole->Printf(_L("Switch not supported\n"));
875 // RUN SHELL FUNCTION
876 r=commandPtr->iFunction(aCommand,switchesSet);
883 else //Generic commands
887 if (aCommand.CompareF(_L("HELP"))==0)
889 else if (aCommand.CompareF(_L("CLS"))==0)
890 TheConsole->ClearScreen();
891 else if (aCommand.Length()==2 && TChar(aCommand[0]).IsAlpha() && aCommand[1]==':')
892 ChangeDrive(aCommand[0]);
893 else if (aCommand.Length()!=0)
895 r=RunBatch(aCommand);
896 if (r != KErrNone) // Typically KErrNotFound, KErrBadName, KErrLocked...
897 r=RunExecutable(aCommand,ETrue);
904 void CShell::PrintHelp()
907 for(const TShellCommand* commandPtr=&iCommand[0];commandPtr<=&iCommand[ENoShellCommands-1];commandPtr++)
909 OutputStringToConsole(ETrue,_L("%- 10S%S\n"),&commandPtr->iName,&commandPtr->iHelp);
914 void CShell::PrintHelp(const TShellCommand* aCommand)
916 OutputStringToConsole(ETrue,_L("%S\n\n %S "),&aCommand->iHelp,&aCommand->iName);
917 OutputStringToConsole(ETrue,_L("%S\n\n"),&aCommand->iHelpDetail);
920 void CShell::PrintError(TInt aError)
924 case KErrAlreadyExists:
925 TheConsole->Printf(_L("Already exists\n"));
928 TheConsole->Printf(_L("Corrupt or unformatted drive\n"));
930 case KErrNotSupported:
931 TheConsole->Printf(_L("Not supported\n"));
934 TheConsole->Printf(_L("General Error\n"));
937 TheConsole->Printf(_L("Not found\n"));
939 case KErrPathNotFound:
940 TheConsole->Printf(_L("Path not found\n"));
943 TheConsole->Printf(_L("Bad name\n"));
946 TheConsole->Printf(_L("Drive not ready\n"));
948 case KErrAccessDenied:
949 TheConsole->Printf(_L("Access denied\n"));
952 TheConsole->Printf(_L("Unexpected end of file\n"));
955 TheConsole->Printf(_L("Too Big\n"));
958 TheConsole->Printf(_L("Error %d\n"),aError);
962 void CShell::ChangeDrive(TChar aDrive)
966 __ASSERT_ALWAYS(charToDrive(aDrive,drive)==KErrNone,User::Panic(_L("Invalid drive letter"),0));
967 TDriveList driveList;
968 TheFs.DriveList(driveList);
969 if (driveList[drive])
971 TInt r=TheFs.SetSessionPath(drivePaths[drive]);
976 PrintError(KErrNotFound);
979 TInt CShell::RunBatch(TDes& aCommand)
981 TBool appendedBat=EFalse;
982 if (aCommand.FindF(_L(".BAT"))<0 && (aCommand.Length()+4)<=KShellMaxCommandLine)
984 aCommand.Append(_L(".BAT"));
988 TInt r=file.Open(TheFs,aCommand,EFileStreamText);
992 aCommand.Delete(aCommand.Length()-4,4);
995 __ASSERT_ALWAYS(TheFs.SessionPath(currentPath)==KErrNone,User::Panic(_L("Session path"),0));
997 __ASSERT_ALWAYS(charToDrive(currentPath[0],drive)==KErrNone,User::Panic(_L("Invalid drive letter"),0));
998 drivePaths[drive]=currentPath;
1001 TBuf<KShellMaxCommandLine> readBuf;
1006 TBuf8<KShellMaxCommandLine> buf8;
1007 r=file.Read(filePos,buf8);
1010 r=file.Read(filePos,readBuf);
1018 r=readBuf.Locate('\n');
1019 if (r==KErrNotFound)
1025 else if (r<=1) // Indicates /n before batch file instructions
1027 TInt temp=readBuf.Length();
1028 readBuf.TrimLeft(); // Removes initial /n
1029 temp-=readBuf.Length();
1030 r=readBuf.Locate('\n');
1035 filePos+=r+1+temp; // Offsets filePos correctly in the file
1039 if (readBuf.Length()==0)
1041 readBuf.SetLength(r);
1044 TheFs.SessionPath(currentPath);
1045 TheConsole->Printf(currentPath);
1046 TheConsole->Printf(_L(">%S\n"),&readBuf);
1048 // If command was a drive change, reset the current path here
1049 if (readBuf.Length()==2 && TChar(readBuf[0]).IsAlpha() && readBuf[1]==':')
1052 __ASSERT_ALWAYS(charToDrive(readBuf[0],drive)==KErrNone,User::Panic(_L("Invalid drive letter"),0));
1054 TDriveList driveList;
1055 TheFs.DriveList(driveList);
1056 if (driveList[drive])
1058 TInt r=TheFs.SetSessionPath(drivePaths[drive]);
1061 currentPath=drivePaths[drive];
1064 PrintError(KErrNotFound);
1067 else if (readBuf.Length()<3 || readBuf.Left(3).CompareF(_L("REM"))!=0)
1076 TInt CShell::RunExecutable(TDes& aCommand,TBool aWaitForCompletion)
1079 TBuf<KShellMaxCommandLine> parameters(0);
1080 TInt r=aCommand.Locate(' '); // can't be the last character because of Trim()
1081 if (r!=KErrNotFound)
1083 parameters=aCommand.Mid(r+1);
1084 aCommand.SetLength(r);
1086 // aCommand is now just the executable
1087 if (aCommand.FindF(_L(".EXE"))==KErrNotFound && (aCommand.Length()+4)<=KShellMaxCommandLine)
1088 aCommand.Append(_L(".EXE"));
1090 if (aCommand.Length()>2 && aCommand[1]==':' && aCommand[2]!='\\')
1092 if (TChar(aCommand[0]).IsAlpha())
1095 __ASSERT_ALWAYS(charToDrive(aCommand[0],drive)==KErrNone,User::Panic(_L("Invalid drive letter"),0));
1096 currentPath=drivePaths[drive];
1097 aCommand.Delete(0,2);
1098 if (aCommand.Length()+currentPath.Length() <= KShellMaxCommandLine)
1099 aCommand.Insert(0,currentPath);
1102 return KErrNotFound;
1104 if (aCommand.Length()>2 && aCommand[1]!=':')
1106 if(aCommand[0]!='\\')
1108 if (aCommand.Locate('\\')==KErrNotFound)
1109 specificExe=0; // no drive, no path - be ready to let the system find it...
1110 if (aCommand.Length()+currentPath.Length() <= KShellMaxCommandLine)
1111 aCommand.Insert(0,currentPath);
1114 if (aCommand.Length()+currentPath.Left(2).Length() <= KShellMaxCommandLine)
1115 aCommand.Insert(0,currentPath.Left(2));
1119 r=file.Open(CShell::TheFs,aCommand,EFileStream);
1124 r=aCommand.LocateReverse('\\'); // must exist because this is a full filename
1125 aCommand.Delete(0,r+1);
1129 // If the file can be opened, it *must* exist, and we'll assume that the user
1130 // really intended this specific file.
1135 RProcess newProcess;
1136 r=newProcess.Create(aCommand,parameters);
1138 if (r==KErrNone) // Executable can run OK
1140 TRequestStatus status=KRequestPending;
1141 if(aWaitForCompletion)
1142 newProcess.Logon(status);
1143 newProcess.Resume();
1144 if (aWaitForCompletion)
1145 User::WaitForRequest(status);
1146 if (aWaitForCompletion && (newProcess.ExitType()!=EExitKill || status!=KErrNone))
1148 TBuf<KMaxExitCategoryName> exitCat=newProcess.ExitCategory();
1149 TheConsole->Printf(_L("\nExit type %d,%d,%S\n"),newProcess.ExitType(),newProcess.ExitReason(),&exitCat);
1152 newProcess.Close(); // get rid of our handle
1156 // Executable could not be run
1158 #if 0 //defined(__EPOC32__)
1161 // Use class CDllChecker to check the dependencies
1162 // for MARM exes only
1165 // Create an array to store each dependency's name, Uid and result
1166 TRAPD(leaveCode,(check.ConstructL()));
1168 if (leaveCode!=KErrNone) // If function leaves
1170 TheConsole->Printf(_L("Dependency checking failed due to error %d\n"), leaveCode);
1174 TInt result=KErrNone;
1175 TRAP(result,(check.GetImportDataL(aCommand,NULL)));
1177 if (result==KErrNone)
1179 check.ListArray(); // Print out the results of DllCheck
1187 void CShell::SetCurrentPath(const TDesC& aDes)
1189 // Set the current Directory
1193 __ASSERT_DEBUG(currentPath.MaxLength()>=aDes.Length(),Panic(EShellFilePathTooBig));
1197 TDes& CShell::CurrentPath()
1199 // Accessor function
1207 void CShell::SetDrivePath(const TDesC& aDrivePath)
1209 // Set the drive path
1213 __ASSERT_DEBUG(aDrivePath.Length()>=3 && aDrivePath[1]==KDriveDelimiter,Panic(EShellBadDrivePath));
1214 TChar drvLetter=aDrivePath[0];
1215 __ASSERT_DEBUG(drvLetter.IsAlpha(),Panic(EShellBadDrivePath));
1217 __ASSERT_ALWAYS(charToDrive(drvLetter,drvNum)==KErrNone,User::Panic(_L("Invalid drive letter"),0));
1218 drivePaths[drvNum]=aDrivePath;
1222 TKeyCode CShell::OutputStringToConsole(TBool aPageSwitch,TRefByValue<const TDesC> aFmt,... )
1223 //function for output of a sring to console
1224 //aPageSwitch flag indicates that output should be page-by-page
1226 //create an object to truncate argument list substitution
1227 SimpleOverflowTruncate overflow;
1229 VA_START(list,aFmt);
1232 //format output string using argument list
1234 //coverity[uninit_use_in_call]
1235 TRAP_IGNORE(aBuf.AppendFormatList(aFmt,list,&overflow)); // ignore leave in TTimeOverflowLeave::Overflow()
1237 _LIT(KPrompt , "Press any key to continue\n");
1239 return OutputStringToConsole(KPrompt,aPageSwitch,_L("%S"),&aBuf);
1242 TKeyCode CShell::OutputStringToConsole(const TDesC& aNotification,TBool aPageSwitch,TRefByValue<const TDesC> aFmt,...)
1243 //function for output of a string to console aPageSwitch flag indicates that output should be page-by-page
1244 //if aPageSwitch==ETrue user will be prompted with the message passed as aNotification
1245 //code of key pressed will be returned as a return value
1247 //create variable to store code of the key pressed by the user
1248 TKeyCode key=EKeyNull;
1249 //create an object to truncate argument list substitution
1250 SimpleOverflowTruncate overflow;
1253 VA_START(list,aFmt);
1256 //format output string using argumen list
1258 //coverity[uninit_use_in_call]
1259 TRAP_IGNORE(aBuf.AppendFormatList(aFmt,list,&overflow)); // ignore leave in TTimeOverflowLeave::Overflow()
1260 //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
1263 key=PageSwitchDisplay(aNotification);
1265 //output current string
1266 TheConsole->Write(aBuf);
1270 TKeyCode CShell::OutputStringToConsole(TBool aPageSwitch, const TDesC& aBuf)
1272 _LIT(KPrompt , "Press any key to continue\n");
1274 TKeyCode key=EKeyNull;
1276 //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
1279 key = PageSwitchDisplay(KPrompt);
1281 //output current string
1282 TheConsole->Write(aBuf);
1287 TKeyCode CShell::PageSwitchDisplay(const TDesC& aNotification)
1289 //create variable to store code of the key pressed by the user
1290 TKeyCode key=EKeyNull;
1291 //obtain a current cursor position
1292 TInt line_count=TheConsole->WhereY();
1293 //calculate how many lines is needed to output current string in the current screen rect
1294 TInt add=(TheConsole->WhereX()+aNotification.Length())/(TheConsole->ScreenSize().iWidth-2);
1295 if ((TheConsole->WhereX()+aNotification.Length())%(TheConsole->ScreenSize().iWidth-2))
1299 //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
1300 TInt notification_height=aNotification.Length()/(TheConsole->ScreenSize().iWidth-2);//we provide 2 additional characters for the frame
1301 if (aNotification.Length()%(TheConsole->ScreenSize().iWidth-2))
1303 notification_height+=1;
1305 if (add<(TheConsole->ScreenSize().iHeight-2))
1306 if ((line_count+add+notification_height)>=(TheConsole->ScreenSize().iHeight-4))
1308 TInt previous_cursor_pos_x=TheConsole->WhereX();
1309 TheConsole->Printf(_L("%S"),&aNotification);
1310 key=TheConsole->Getch();
1311 TheConsole->ClearScreen();
1312 TheConsole->SetCursorPosAbs(TPoint (previous_cursor_pos_x,0)) ;