os/kernelhwsrv/userlibandfileserver/fileserver/etshell/ts_edshl.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // f32\etshell\ts_edshl.cpp
    15 // CLineEdit and CShell code
    16 // 
    17 //
    18 
    19 
    20 #include <e32hal.h>
    21 #include "ts_std.h"
    22 #include "ts_clicomp.h"
    23 #include "cleanuputils.h"
    24 
    25 CLineEdit* CShell::TheEditor;
    26 CFileMan* CShell::TheFileMan;
    27 TBuf<KMaxFileName> CShell::currentPath;
    28 RFs CShell::TheFs;
    29 CConsoleBase* CShell::TheConsole;
    30 CCliCompleter* CShell::TheCliCompleter;
    31 
    32 class CFileManObserver : public MFileManObserver
    33 	{
    34 	TControl NotifyFileManEnded();
    35 	};
    36 
    37 MFileManObserver::TControl CFileManObserver::NotifyFileManEnded()
    38 //
    39 // Print out what CFileMan is doing
    40 //
    41 	{
    42 
    43 	TInt err=CShell::TheFileMan->GetLastError();
    44 	TFileName srcfile;
    45 	CShell::TheFileMan->GetCurrentSource(srcfile);
    46 	if (err!=KErrNone)
    47 		{
    48 		if(err == KErrNotReady)
    49 			{
    50 			FOREVER
    51 				{
    52 				CShell::TheConsole->Printf(_L("Not ready - Retry? [y/n]\n"));
    53 				TChar key = CShell::TheConsole->Getch();
    54 				key.UpperCase();
    55 				if(key == 'Y')
    56 					{
    57 					return(MFileManObserver::ERetry);
    58 					}
    59 				if(key == 'N')
    60 					{
    61 					return(MFileManObserver::EAbort);
    62 					}
    63 				}
    64 			}
    65 		else
    66 			{
    67 			CShell::TheConsole->Printf(_L("Error %d\n"),err);
    68 			}
    69 		}
    70 	else
    71 		{			
    72 		switch (CShell::TheFileMan->CurrentAction())
    73 			{
    74 			case CFileMan::ECopy:
    75 				CShell::TheConsole->Printf(_L("Copied %S\n"),&srcfile);
    76 				break;
    77 			case CFileMan::EAttribs:
    78 				CShell::TheConsole->Printf(_L("Setting Attributes for %S\n"),&srcfile);
    79 				break;
    80 			case CFileMan::EDelete:
    81 				CShell::TheConsole->Printf(_L("Deleted %S\n"),&srcfile);
    82 				break;
    83 			case CFileMan::EMove:
    84 				CShell::TheConsole->Printf(_L("Moved %S\n"),&srcfile);
    85 				break;
    86 			case CFileMan::ERename:
    87 				CShell::TheConsole->Printf(_L("Renamed %S\n"),&srcfile);
    88 				break;
    89 			case CFileMan::ERmDir:
    90 				CShell::TheConsole->Printf(_L("RmDir deleted %S\n"),&srcfile);
    91 				break;
    92 			default:
    93 				CShell::TheConsole->Printf(_L("Unknown action %S\n"),&srcfile);
    94 				break;
    95 				}
    96 		}
    97 	return(MFileManObserver::EContinue);
    98 	}
    99 
   100 LOCAL_C TInt charToDrive(TChar aChar,TInt& aDrive)
   101 //
   102 // Convert the drive character to a drive index.
   103 //
   104 	{
   105 
   106 	TInt r=RFs::CharToDrive(aChar,aDrive);
   107 	return(r);
   108 	}
   109 
   110 CLineEdit::CLineEdit()
   111 //
   112 // Constructor
   113 //
   114 	{
   115 	}
   116 
   117 
   118 CLineEdit::~CLineEdit()
   119 //
   120 // Destroy the line editor
   121 //
   122 	{
   123 
   124     if (iHistory)
   125         {
   126         TInt count=iHistory->Count();
   127         while (count--)
   128             User::Free((*iHistory)[count]);
   129         delete iHistory;
   130         }
   131 	}
   132 
   133 CLineEdit* CLineEdit::NewL(CConsoleBase* aConsole,TInt aMaxHistory)
   134 //
   135 // Create a new line editor
   136 //
   137 	{
   138 
   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;
   146 	
   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;
   152 	TFullName wsName;
   153 	TInt err = KErrNone;
   154 	
   155 	pE->iFrameSizeChar=TSize(0,0);
   156 	
   157 	// Find: !E32WindowServer is running?
   158 	while (err=findServer.Next(wsName), err==KErrNone)
   159 		{
   160 		if(err=wsName.FindF(KE32WindowServer), err!=KErrNotFound)
   161 			{
   162 			// E32WindowServer is running. 
   163 			// Frame is present ! Frame Size is (2,2) !
   164 			pE->iFrameSizeChar=TSize(2,2);
   165 			break;
   166 			}
   167 		}
   168 	
   169     CleanupStack::Pop();
   170 	return(pE);
   171 	}
   172 
   173 TInt CLineEdit::Lines()
   174 //
   175 // The number of lines being edited.
   176 //
   177     {
   178 
   179     TInt nL=1;
   180     if (Buf().Length()>=iWidth-iFrameSizeChar.iWidth-iOrigin)
   181 		nL+=(Buf().Length()+iOrigin)/(iWidth-iFrameSizeChar.iWidth);
   182     return(nL);
   183     }
   184 
   185 TPoint CLineEdit::Where()
   186 //
   187 // Return the real cursor position.
   188 //
   189     {
   190 
   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));
   194     }
   195 
   196 void CLineEdit::ClearLine()
   197 //
   198 // Clears the line being edited.
   199 //
   200     {
   201 
   202     if (Buf().Length())
   203 		{
   204 		TInt nL=Lines();
   205 		while (nL--)
   206 	    	{
   207 	    	iConsole->SetPos(nL ? 0 : iOrigin,iLine+nL);
   208 	    	iConsole->ClearToEndOfLine();
   209 	    	}
   210 		Buf().Zero();
   211 		iPos=0;
   212 		}
   213     }
   214 
   215 void CLineEdit::ClearLast(TInt aCnt)
   216 //
   217 // Clears the last aCnt characters.
   218 //
   219     {
   220 
   221     TInt aPos=iPos;
   222     iPos=((TInt)Buf().Length())-aCnt;
   223     while (iPos<((TInt)Buf().Length()))
   224 		{
   225 		TPoint p=Where();
   226 		iConsole->SetCursorPosAbs(p);
   227 		iConsole->ClearToEndOfLine();
   228 		iPos+=(iWidth-p.iX);
   229 		}
   230     iPos=aPos;
   231     }
   232 
   233 void CLineEdit::Recall()
   234 //
   235 // Recall a line for editing.
   236 //
   237     {
   238 
   239 	if (iRecall!=(-1))
   240 		{
   241 		ClearLine();
   242 		HBufC* pL=(*iHistory)[iRecall];
   243 		Buf()=(*pL);
   244 		iConsole->Write(Buf());
   245 		iPos=Buf().Length();
   246 		TInt nL=Lines();
   247 		if ((iLine+nL)>iHeight)
   248 			iLine -= iLine + nL - iHeight;	
   249 
   250 		}
   251     }
   252 
   253 TInt CLineEdit::WordLeft()
   254 //
   255 // Position the cursor to the next word left.
   256 //
   257     {
   258 
   259     TInt x=iPos-1;
   260     while (x && TChar(Buf()[x]).IsSpace())
   261 		x--;
   262     while (x && TChar(Buf()[x]).IsGraph())
   263 		x--;
   264     if (TChar(Buf()[x]).IsSpace())
   265 		x++;
   266     return(x);
   267     }
   268 
   269 TInt CLineEdit::WordRight()
   270 //
   271 // Position the cursor to the next word right.
   272 //
   273     {
   274 
   275     TInt x=iPos;
   276     while (x<(TInt)Buf().Length() && TChar(Buf()[x]).IsGraph())
   277 		x++;
   278     while (x<(TInt)Buf().Length() && TChar(Buf()[x]).IsSpace())
   279 		x++;
   280     return(x);
   281     }
   282 
   283 void CLineEdit::Cursor()
   284 //
   285 // Position the cursor.
   286 //
   287     {
   288 
   289     iConsole->SetCursorPosAbs(Where());
   290     }
   291 
   292 void CLineEdit::Refresh()
   293 //
   294 // Refresh the line.
   295 //
   296     {
   297 
   298 	iConsole->SetCursorHeight(ECursorNone);
   299     iConsole->SetPos(iOrigin,iLine);
   300     iConsole->Write(Buf());
   301 	Cursor();
   302 	iConsole->SetCursorHeight(iMode==EEditOverWrite ? ECursorNormal : ECursorInsert);
   303     }
   304        
   305 TLineEditAction CLineEdit::Edit(const TDesC& aPrompt, TDes* aBuf, TBool aNewLine)
   306 //
   307 // Start the editor or a single key fetch.
   308 //
   309 	{
   310 	iBuf = aBuf;
   311 	
   312 	if(aNewLine)
   313 		{
   314 		iMode = EEditInsert;
   315 		iConsole->Write(aPrompt);
   316 		iConsole->SetCursorHeight(iMode == EEditOverWrite ? ECursorNormal : ECursorInsert);
   317 		iOrigin = iConsole->WhereX();
   318 		iLine = iConsole->WhereY();  
   319 		}
   320 
   321 	if(iBuf->Length() == 0)
   322 		{			
   323 		iPos = 0;
   324 		}
   325 	
   326 	Refresh();
   327 		
   328 	iRecall = (-1);
   329 	TInt hCount = iHistory->Count();
   330 	
   331 	if (hCount > iMaxHistory)
   332 		{
   333 		hCount = iMaxHistory;
   334 		}
   335 	
   336 	FOREVER
   337 		{
   338 		TChar gChar = iConsole->Getch();
   339 		
   340 		switch (gChar)
   341 	    	{
   342 		case EKeyEscape:
   343 	    	ClearLine();
   344 			iRecall=(-1);
   345 	    	break;
   346 		case EKeyHome:
   347 	    	iPos=0;
   348 	    	Cursor();
   349 	    	break;
   350 		case EKeyLeftArrow:
   351 	    	if (iPos)
   352                 {
   353                 if(iConsole->KeyModifiers()==EModifierCtrl)
   354                     iPos=WordLeft();
   355                 else
   356     				iPos--;
   357                 Cursor();
   358                 }
   359 	    	break;
   360 		case EKeyRightArrow:
   361 	    	if (iPos<((TInt)Buf().Length()))
   362                 {
   363                 if(iConsole->KeyModifiers()==EModifierCtrl)
   364                     iPos=WordRight();
   365                 else
   366     				iPos++;
   367                 Cursor();
   368                 }
   369 	    	break;
   370 		case EKeyEnd:
   371 	    	iPos=((TInt)Buf().Length());
   372 	    	Cursor();
   373 	    	break;
   374 		case EKeyPageUp:
   375 	    	if (hCount==0)
   376 				break;
   377 	    	iRecall=hCount-1;
   378 	    	Recall();
   379 	    	break;
   380 		case EKeyUpArrow:
   381 	    	if (iRecall==(-1))	//	Beginning of history
   382 				{
   383 				if (hCount==0)
   384 		    		break;
   385 				iRecall=0;
   386 				}
   387 	    	else if (iRecall>=(hCount-1))	//	End
   388 				{
   389 				ClearLine();
   390 				iRecall=(-1);
   391 				break;
   392 				}
   393 	    	else
   394 				iRecall++;
   395 	    	Recall();
   396 	    	break;
   397 		case EKeyDownArrow:
   398 	    	if (iRecall==(-1))
   399 				{
   400 				if (hCount==0)
   401 		    		break;
   402 				iRecall=hCount-1;
   403 				}
   404 	    	else if (iRecall==0)
   405 				{
   406 				ClearLine();
   407 				iRecall=(-1);
   408 				break;
   409 				}
   410 	    	else
   411 				iRecall--;
   412 	    	Recall();
   413 	    	break;
   414 		case EKeyPageDown:
   415 	    	if (hCount==0)
   416 				break;
   417 	    	iRecall=0;
   418 	    	Recall();
   419 	    	break;
   420 	    	
   421 		case EKeyEnter:
   422 			NewLine();
   423 			StoreBufferHistory();		
   424 	    	return EShellCommand;
   425 	    	
   426 		case EKeyBackspace:
   427 	    	if (iPos)
   428 				{
   429 				TInt iN=1;
   430 				if (iConsole->KeyModifiers()==EModifierCtrl)
   431 		    		iN=iPos-WordLeft();
   432 				ClearLast(iN);
   433 				iPos-=iN;
   434 				Buf().Delete(iPos,iN);
   435 				Refresh();
   436 				}
   437 	    	break;
   438 		case EKeyDelete:
   439 	    	if (iPos<((TInt)Buf().Length()))
   440 				{
   441 				TInt iN=1;
   442 				if (iConsole->KeyModifiers()==EModifierCtrl)
   443 		    		iN=WordRight()-iPos;
   444 				ClearLast(iN);
   445 				Buf().Delete(iPos,iN);
   446 				Refresh();
   447 				}
   448 	    	break;
   449 	    	
   450 		case EKeyInsert:
   451 	    	iMode=(iMode==EEditOverWrite ? EEditInsert : EEditOverWrite);
   452 			iConsole->SetCursorHeight(iMode==EEditOverWrite ? ECursorNormal : ECursorInsert);
   453 	    	break;
   454 
   455 		case EKeyTab:
   456 			return ECommandCompletion;
   457 
   458 		default:
   459    	    	if (!gChar.IsPrint())
   460 				break;
   461 	    	if (iMode==EEditOverWrite && iPos<((TInt)Buf().Length()))
   462 				Buf()[iPos++]=(TText)gChar;
   463 	    	else if (Buf().Length()<KShellMaxCommandLine)
   464 				{
   465 				TInt oL=Lines();
   466 				TBuf<0x02> b;
   467 				b.Append(gChar);
   468 				Buf().Insert(iPos++,b);
   469 				TInt nL=Lines();
   470 				if (nL!=oL)
   471 		    		{
   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;
   478 		    		}
   479 				}
   480 			else
   481 				{
   482 				iConsole->Write(_L("\7"));
   483 				iConsole->SetPos((iOrigin+iPos)%(iWidth-iFrameSizeChar.iWidth),iLine+Lines()-1);
   484 				break;
   485 				}
   486 			Refresh();
   487 			}
   488 		}
   489 	}
   490 	
   491 void CLineEdit::NewLine()
   492 	{
   493  	iConsole->SetCursorHeight(ECursorNone);
   494  	iLine += (Lines() - 1);
   495  	iConsole->SetPos(0, iLine);
   496  	iConsole->Write(_L("\n")); // Just a line feed
   497  	iRecall = (-1);
   498 	}
   499 
   500 void CLineEdit::StoreBufferHistory()
   501 	{
   502     Buf().TrimRight(); 
   503 
   504 	if (Buf().Length()>=1)
   505 		{
   506 		
   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)
   510         {
   511             HBufC* pCmd = iHistory->At(i);    
   512             const TDesC& cmdLine = pCmd->Des();
   513             if(cmdLine == Buf())
   514             {
   515                 iHistory->Delete(i);
   516                 TRAP_IGNORE(iHistory->InsertL(0, pCmd));
   517                 return;
   518             }
   519         }
   520 
   521         if (iHistory->Count()==iMaxHistory+1)
   522 			{
   523 			User::Free((*iHistory)[iMaxHistory]);
   524     		iHistory->Delete(iMaxHistory);
   525 			}
   526 		
   527         HBufC* pB=Buf().Alloc();
   528 		if(pB != NULL)
   529 			{
   530 			TRAP_IGNORE(iHistory->InsertL(0, pB));
   531 			}
   532 		}
   533 	}
   534 
   535 //////////////////////////////////////
   536 //CShell
   537 //////////////////////////////////////
   538 TShellCommand::TShellCommand(const TDesC& aName,const TDesC& aHelp,const TDesC& aHelpDetail,TUint aSwitches,TInt (*aFunction)(TDes&,TUint))
   539 	:iName(aName),
   540 	iHelp(aHelp),
   541 	iHelpDetail(aHelpDetail),
   542 	iSwitchesSupported(aSwitches),
   543 	iFunction(aFunction)
   544 	{
   545 	}
   546 
   547 CShell* CShell::NewL()
   548 	{
   549 	CShell *pS = new(ELeave) CShell;
   550 	CleanupStack::PushL(pS);
   551 	
   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();
   557    
   558 	CleanupStack::Pop();
   559 	return(pS);
   560 	}
   561 
   562 CShell::~CShell()
   563 	{
   564 	ShellFunction::TheShell=NULL;
   565 	TheFs.Close();
   566 	delete TheEditor;
   567   	delete TheFileMan;
   568   	delete TheConsole;
   569   	delete TheCliCompleter;
   570  	}
   571 
   572 void CShell::DoBanner()
   573 	{
   574 	TBuf<40> shlver=TheShellVersion.Name();
   575 	TheConsole->Printf(_L("ESHELL %S   CFG="),&shlver);
   576 #ifdef _UNICODE
   577 	TheConsole->Printf(_L("U"));
   578 #endif
   579 #ifdef _DEBUG
   580 	TheConsole->Printf(_L("DEB\r\n"));
   581 #else
   582 	TheConsole->Printf(_L("REL\r\n"));
   583 #endif
   584 
   585 #if !defined(__WINS__)
   586 	TMachineStartupType reason;
   587 	UserHal::StartupReason(reason);
   588 	
   589 	switch (reason)
   590 		{
   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:	
   597 			
   598 			TInt faultno;
   599 			UserHal::FaultReason(faultno);
   600 			if (faultno == 0x10000000)
   601 				{
   602 				TheConsole->Printf(_L("Kernel Exception\n"));
   603 				}
   604 			else 
   605 				{
   606 				TExcInfo exceptInfo;
   607 				UserHal::ExceptionInfo(exceptInfo);
   608 				TUint32 decode[3];
   609 				decode[0]=TUint32(exceptInfo.iCodeAddress);
   610 				decode[1]=TUint32(exceptInfo.iDataAddress);
   611 				decode[2]=0;
   612 			
   613 			//	interpret decode as null-terminated string
   614 				TPtrC category((TText*)&decode[0]);
   615 			
   616 				if (faultno >= 0x10000)
   617 					TheConsole->Printf(_L("Kernel PANIC: %S %d\n"),&category, faultno-0x10000);
   618 				else
   619 					TheConsole->Printf(_L("Kernel FAULT: %S %d\n"),&category, faultno);
   620 				}
   621 			break;
   622 		case EStartupSafeReset:		TheConsole->Printf(_L("Safe Reset\n")); break;
   623 		default:
   624 			TheConsole->Printf(_L("<?reason=%d>\n"), reason);
   625 			break;
   626 		}
   627 
   628 	if (reason==EStartupWarmReset || reason==EStartupKernelFault)
   629 		{
   630 		TInt excId;
   631 		TExcInfo excInfo;
   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);
   636 		}
   637 #endif
   638 	TheConsole->Printf(_L("\r\n\nCopyright (c) 1998 Symbian Ltd\r\n\n"));
   639 	}
   640 
   641 _LIT(KRootdir,"?:\\");
   642 void CShell::RunL()
   643 	{
   644 	DoBanner();
   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));
   650 	TInt drive;
   651 	__ASSERT_ALWAYS(charToDrive(currentPath[0],drive)==KErrNone,User::Panic(_L("Invalid Path"),0));
   652 	drivePaths[drive]=currentPath;
   653 //
   654 //	going to creat the shell's private path here
   655 //	TheFs.
   656 //
   657 	CFileManObserver* fileManObserver=new(ELeave) CFileManObserver;
   658 	CleanupStack::PushL(fileManObserver);
   659 	TheFileMan=CFileMan::NewL(TheFs,fileManObserver);
   660 //
   661 	TBuf<16> startupFile=_L("0:\\AUTOEXEC.BAT");
   662 	TEntry startEntry;
   663 	
   664 //	Search all drives for autoexec.bat starting y,x,...,a then z
   665 	
   666 	const TInt KIndexDriveA=0;
   667 	const TInt KIndexDriveY=24;
   668 	const TInt KIndexDriveZ=25;
   669 	TBuf<KMaxFileName>* searchDrive;
   670 
   671 	for (searchDrive=&drivePaths[KIndexDriveY];searchDrive>=&drivePaths[KIndexDriveA];searchDrive--)
   672 		{
   673 		currentPath=*searchDrive;
   674 		startupFile[0]=currentPath[0];
   675 		if (TheFs.Entry(startupFile,startEntry)==KErrNone)
   676 			{
   677 #ifdef __X86__
   678 			if (startEntry.iSize != 0)
   679 #endif
   680 				{
   681 				RunBatch(startupFile);
   682 				break;
   683 				}
   684 			}
   685 		if (searchDrive==&drivePaths[KIndexDriveA])
   686 			{
   687 			currentPath=drivePaths[KIndexDriveZ];
   688 			startupFile[0]=currentPath[0];
   689 			if (TheFs.Entry(startupFile,startEntry)==KErrNone)
   690 				{
   691 				RunBatch(startupFile);
   692 				break;
   693 				}
   694 			}
   695 		}
   696 
   697 	TLineEditAction result;
   698 	TBuf<KShellMaxCommandLine> commandText;
   699 	TBool exit = EFalse;
   700 	
   701 	TInt tabCount = 0;
   702 	TBuf<KMaxPath + 1> prompt;
   703 	TBool newLine = ETrue;
   704 
   705 	FOREVER
   706 		{
   707 		__ASSERT_ALWAYS(TheFs.SessionPath(currentPath)==KErrNone,User::Panic(_L("Session path"),0));
   708       TInt drive;
   709        __ASSERT_ALWAYS(charToDrive(currentPath[0],drive)==KErrNone,User::Panic(_L("Invalid Path"),0));
   710 		drivePaths[drive] = currentPath;
   711 
   712 		if(currentPath[currentPath.Length() - 2] == KDriveDelimiter)
   713 			{
   714 			prompt = currentPath;		
   715 			}
   716 		else 
   717 			{
   718 			TInt i = (currentPath.LocateReverse(KPathDelimiter));
   719 			prompt = currentPath.Left(i);
   720 			}
   721 		prompt.Append(_L(">"));
   722 
   723 		result = TheEditor->Edit(prompt, &commandText, newLine);
   724 		
   725 		switch(result)
   726 			{
   727 			case EShellCommand:
   728 				tabCount = 0;
   729 				
   730 #if !defined(_EPOC)
   731 				if(commandText.CompareF(_L("EXIT")) == 0)
   732 					{
   733 					exit = ETrue;
   734 					break;
   735 					}
   736 #endif
   737 				commandText.Trim();
   738 				DoCommand(commandText);
   739 				commandText.Zero();
   740 				
   741 				newLine = ETrue;
   742 				
   743 				break;
   744 			
   745 			case ECommandCompletion:
   746 				{
   747 				tabCount++;
   748 				
   749 				TBuf<KMaxPath> knownPart;
   750 				TheCliCompleter->EstablishCompletionContext(commandText, TheEditor->Pos(), knownPart);
   751 
   752 				TInt preCompletedLength = knownPart.Length();
   753 				
   754 				newLine = EFalse;
   755 				
   756 				RPointerArray<HBufC> alternatives;
   757  				CleanupResetAndDestroyPushL(alternatives);
   758 				
   759 				if(TheCliCompleter->AttemptCompletionL(knownPart, alternatives))
   760 					{ // We completed something successfully
   761 					tabCount = 0;
   762 					}
   763 					
   764 				if(knownPart.Length() > preCompletedLength) 
   765 					{
   766 					commandText.Delete(TheEditor->Pos() - preCompletedLength, preCompletedLength);
   767 
   768 					// Don't allow the completion to cause the line buffer length to be exceeded
   769 					TInt excess = ((TheEditor->Pos() - preCompletedLength) + knownPart.Length()) - KShellMaxCommandLine;
   770 					if(excess > 0)
   771 						{
   772 						knownPart.Delete(knownPart.Length() - excess, excess);
   773 						}						
   774 					else
   775 						{
   776 						excess = (commandText.Length() + knownPart.Length()) - KShellMaxCommandLine;
   777 						
   778 						if(excess > 0)
   779 							{
   780 							commandText.Delete(commandText.Length() - excess, excess);
   781 							}
   782 						}
   783 
   784 					commandText.Insert(TheEditor->Pos() - preCompletedLength, knownPart);
   785 					TheEditor->SetPos(TheEditor->Pos() + (knownPart.Length() - preCompletedLength));
   786 					}
   787 				
   788 				if(alternatives.Count() > 0)
   789 					{
   790 					if(tabCount == 2)
   791 						{
   792 						tabCount = 0;
   793 						
   794 						TheCliCompleter->DisplayAlternatives(alternatives);
   795 						newLine = ETrue;
   796 						}
   797 					}
   798 				
   799 				CleanupStack::PopAndDestroy(&alternatives);
   800 				
   801 				break;
   802 				}
   803 
   804 			case ENoAction:
   805 			default:
   806 				tabCount = 0;
   807 				break;
   808 			}
   809 		
   810 		if(exit) 
   811 			{
   812 			break;
   813 			}
   814 		}
   815 	
   816 	CleanupStack::PopAndDestroy(fileManObserver);
   817 	}
   818 
   819 void CShell::DoCommand(TDes& aCommand)
   820 //
   821 // Evaluate the commandline and run the command or file
   822 //
   823 	{
   824 
   825 	aCommand.TrimAll();
   826 	
   827 	const TShellCommand* commandPtr=&iCommand[0];
   828 	for (;commandPtr<=&iCommand[ENoShellCommands-1];commandPtr++)
   829 		{
   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))
   833 				{
   834 				aCommand.Delete(0,length);
   835 				break;
   836 				}
   837 		}
   838 
   839 	if (commandPtr<=&iCommand[ENoShellCommands-1])
   840 		{
   841 		if (aCommand.Find(_L("/?"))>=0)
   842 			PrintHelp(commandPtr);
   843 		else // No /? switch
   844 			{
   845 			TUint switchesSet=0;
   846 			TInt r;
   847 			while ((r=aCommand.Locate('/'))!=KErrNotFound)
   848 				{
   849 				TChar switchChar='\0';
   850                 TInt switchInt=switchChar;
   851 				if ((r+1)==aCommand.Length() || (switchChar=aCommand[r+1]).IsAlpha()==EFalse)
   852 					{
   853 					TheConsole->Printf(_L("Invalid switch - \"%c\".\n"),switchInt);
   854 					return;
   855 					}
   856 				switchChar.UpperCase();
   857 				switchesSet|=(1<<((TInt)switchChar-'A'));
   858 				TChar extraChar;
   859 				if ((r+2)<aCommand.Length() && (extraChar=aCommand[r+2])!=' ' && extraChar!='/')
   860 					{
   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);
   864 					return;
   865 					}
   866 				aCommand.Delete(r,2); 
   867 				}
   868 			if (switchesSet&~commandPtr->iSwitchesSupported)
   869 				{
   870 				TheConsole->Printf(_L("Switch not supported\n"));
   871 				return;
   872 				}
   873 			aCommand.Trim();
   874 		
   875 		//	RUN SHELL FUNCTION	
   876 			r=commandPtr->iFunction(aCommand,switchesSet);
   877 			if (r!=KErrNone) 
   878 				{
   879 				PrintError(r);
   880 				}
   881 			}
   882 		}
   883 	else //Generic commands
   884 		{
   885 		TInt r;
   886 		
   887 		if (aCommand.CompareF(_L("HELP"))==0)
   888 			PrintHelp();
   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)
   894 			{
   895 			r=RunBatch(aCommand);
   896 			if (r != KErrNone)		// Typically KErrNotFound, KErrBadName, KErrLocked...
   897 				r=RunExecutable(aCommand,ETrue);
   898 			if (r!=KErrNone)
   899 				PrintError(r);
   900 			}
   901 		}
   902 	}
   903 
   904 void CShell::PrintHelp()
   905 	{
   906 			
   907 	for(const TShellCommand* commandPtr=&iCommand[0];commandPtr<=&iCommand[ENoShellCommands-1];commandPtr++)
   908 		{
   909 		OutputStringToConsole(ETrue,_L("%- 10S%S\n"),&commandPtr->iName,&commandPtr->iHelp);			
   910 		}
   911 	
   912 	}
   913 
   914 void CShell::PrintHelp(const TShellCommand* aCommand)
   915 	{
   916 	OutputStringToConsole(ETrue,_L("%S\n\n  %S "),&aCommand->iHelp,&aCommand->iName);
   917 	OutputStringToConsole(ETrue,_L("%S\n\n"),&aCommand->iHelpDetail);
   918 	}
   919 
   920 void CShell::PrintError(TInt aError)
   921 	{
   922 	switch (aError)
   923 		{
   924 	case KErrAlreadyExists:
   925 		TheConsole->Printf(_L("Already exists\n"));
   926 		break;
   927 	case KErrCorrupt:
   928 		TheConsole->Printf(_L("Corrupt or unformatted drive\n"));
   929 		break;
   930 	case KErrNotSupported:
   931 		TheConsole->Printf(_L("Not supported\n"));
   932 		break;
   933 	case KErrGeneral:
   934 		TheConsole->Printf(_L("General Error\n"));
   935 		break;
   936 	case KErrNotFound:
   937 		TheConsole->Printf(_L("Not found\n"));
   938 		break;
   939 	case KErrPathNotFound:
   940 		TheConsole->Printf(_L("Path not found\n"));
   941 		break;
   942 	case KErrBadName:
   943 		TheConsole->Printf(_L("Bad name\n"));
   944 		break;
   945 	case KErrNotReady:
   946 		TheConsole->Printf(_L("Drive not ready\n"));
   947 		break;
   948 	case KErrAccessDenied:
   949 		TheConsole->Printf(_L("Access denied\n"));
   950 		break;
   951 	case KErrEof:
   952 		TheConsole->Printf(_L("Unexpected end of file\n"));
   953 		break;
   954 	case KErrTooBig:
   955 		TheConsole->Printf(_L("Too Big\n"));
   956 		break;
   957 	default:
   958 		TheConsole->Printf(_L("Error %d\n"),aError);
   959 		}
   960 	}
   961 
   962 void CShell::ChangeDrive(TChar aDrive)
   963 	{
   964 
   965     TInt drive;
   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]) 
   970 		{
   971 		TInt r=TheFs.SetSessionPath(drivePaths[drive]);
   972 		if (r!=KErrNone)
   973 			PrintError(r);
   974 		}
   975 	else 
   976 		PrintError(KErrNotFound);
   977 	}  
   978 
   979 TInt CShell::RunBatch(TDes& aCommand)
   980 	{
   981 	TBool appendedBat=EFalse;
   982 	if (aCommand.FindF(_L(".BAT"))<0 && (aCommand.Length()+4)<=KShellMaxCommandLine)
   983 		{
   984 		aCommand.Append(_L(".BAT"));
   985 		appendedBat=ETrue;
   986 		}
   987 	RFile file;
   988 	TInt r=file.Open(TheFs,aCommand,EFileStreamText);
   989 	if (r!=KErrNone)
   990 		{
   991 		if (appendedBat)
   992 			aCommand.Delete(aCommand.Length()-4,4);		
   993 		return r;
   994 		}
   995 	__ASSERT_ALWAYS(TheFs.SessionPath(currentPath)==KErrNone,User::Panic(_L("Session path"),0));
   996     TInt drive;
   997     __ASSERT_ALWAYS(charToDrive(currentPath[0],drive)==KErrNone,User::Panic(_L("Invalid drive letter"),0));
   998 	drivePaths[drive]=currentPath;
   999 	TInt filePos=0;
  1000 	
  1001 	TBuf<KShellMaxCommandLine> readBuf;
  1002 	
  1003 	FOREVER
  1004 		{
  1005 #ifdef _UNICODE
  1006 		TBuf8<KShellMaxCommandLine> buf8;
  1007 		r=file.Read(filePos,buf8);
  1008 		readBuf.Copy(buf8);		
  1009 #else
  1010 		r=file.Read(filePos,readBuf);
  1011 #endif
  1012 		if (r!=KErrNone)
  1013 			{
  1014 			PrintError(r);
  1015 			break;
  1016 			}
  1017 
  1018 		r=readBuf.Locate('\n');
  1019 		if (r==KErrNotFound)
  1020 			{
  1021 			r=readBuf.Length();
  1022 			filePos+=r;
  1023 			}
  1024 		
  1025 		else if (r<=1)					//	Indicates /n before batch file instructions
  1026 			{
  1027 			TInt temp=readBuf.Length();	
  1028 			readBuf.TrimLeft();			//	Removes initial /n
  1029 			temp-=readBuf.Length();		
  1030 			r=readBuf.Locate('\n');
  1031 			if(r==KErrNotFound)
  1032 				{
  1033 				r=readBuf.Length();
  1034 				}
  1035 			filePos+=r+1+temp;			//	Offsets filePos correctly in the file
  1036 			}
  1037 		else filePos+=r+1;
  1038 		
  1039 		if (readBuf.Length()==0)
  1040 			break;
  1041 		readBuf.SetLength(r);
  1042 		
  1043 		readBuf.Trim();
  1044 		TheFs.SessionPath(currentPath);
  1045 		TheConsole->Printf(currentPath);		
  1046 		TheConsole->Printf(_L(">%S\n"),&readBuf);
  1047 
  1048 	//	If command was a drive change, reset the current path here		
  1049 		if (readBuf.Length()==2 && TChar(readBuf[0]).IsAlpha() && readBuf[1]==':')
  1050 			{
  1051 			TInt drive;
  1052 			__ASSERT_ALWAYS(charToDrive(readBuf[0],drive)==KErrNone,User::Panic(_L("Invalid drive letter"),0));
  1053 			
  1054 			TDriveList driveList;
  1055 			TheFs.DriveList(driveList);
  1056 			if (driveList[drive]) 
  1057 				{
  1058 				TInt r=TheFs.SetSessionPath(drivePaths[drive]);
  1059 				if (r!=KErrNone)
  1060 					PrintError(r);
  1061 				currentPath=drivePaths[drive];
  1062 				}
  1063 			else 
  1064 			PrintError(KErrNotFound);
  1065 			}
  1066 			
  1067 		else if (readBuf.Length()<3 || readBuf.Left(3).CompareF(_L("REM"))!=0)
  1068 			DoCommand(readBuf);
  1069 		}
  1070 	file.Close();
  1071 	return KErrNone;
  1072 	}
  1073 
  1074 
  1075 
  1076 TInt CShell::RunExecutable(TDes& aCommand,TBool aWaitForCompletion)
  1077 	{
  1078 	aCommand.Trim();
  1079 	TBuf<KShellMaxCommandLine> parameters(0);
  1080    	TInt r=aCommand.Locate(' ');	// can't be the last character because of Trim()
  1081    	if (r!=KErrNotFound)
  1082 		{
  1083 		parameters=aCommand.Mid(r+1);
  1084    		aCommand.SetLength(r);
  1085 		}
  1086 	// aCommand is now just the executable
  1087 	if (aCommand.FindF(_L(".EXE"))==KErrNotFound && (aCommand.Length()+4)<=KShellMaxCommandLine)
  1088 		aCommand.Append(_L(".EXE"));
  1089 	TInt specificExe=1;
  1090 	if (aCommand.Length()>2 && aCommand[1]==':' && aCommand[2]!='\\')
  1091 		{
  1092 		if (TChar(aCommand[0]).IsAlpha())
  1093 			{
  1094 			TInt drive;
  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);
  1100 			}
  1101 		else
  1102 			return KErrNotFound;
  1103 		}
  1104 	if (aCommand.Length()>2 && aCommand[1]!=':')
  1105 		{
  1106 		if(aCommand[0]!='\\')
  1107 			{
  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);
  1112 			}
  1113 		else
  1114             if (aCommand.Length()+currentPath.Left(2).Length() <= KShellMaxCommandLine)
  1115     			aCommand.Insert(0,currentPath.Left(2));
  1116 		}
  1117 
  1118 	RFile file;
  1119 	r=file.Open(CShell::TheFs,aCommand,EFileStream);
  1120 	if (r!=KErrNone)
  1121 		{
  1122 		if (specificExe)
  1123 			return(r);
  1124 		r=aCommand.LocateReverse('\\');	// must exist because this is a full filename
  1125 		aCommand.Delete(0,r+1);
  1126 		}
  1127 	else
  1128 		{
  1129 		// If the file can be opened, it *must* exist, and we'll assume that the user
  1130 		// really intended this specific file.
  1131 		specificExe=1;
  1132 		file.Close();
  1133 		}
  1134 
  1135 	RProcess newProcess;
  1136 	r=newProcess.Create(aCommand,parameters);
  1137 	
  1138 	if (r==KErrNone)	//	Executable can run OK
  1139 		{
  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))
  1147 			{
  1148 			TBuf<KMaxExitCategoryName> exitCat=newProcess.ExitCategory();
  1149 			TheConsole->Printf(_L("\nExit type %d,%d,%S\n"),newProcess.ExitType(),newProcess.ExitReason(),&exitCat);
  1150 			}
  1151 			
  1152 		newProcess.Close(); // get rid of our handle
  1153 		return KErrNone;
  1154 		}
  1155 
  1156 	//	Executable could not be run
  1157 
  1158 #if 0	//defined(__EPOC32__)
  1159 	if (specificExe)		
  1160 		{	
  1161 	//	Use class CDllChecker to check the dependencies
  1162 	//	for MARM exes only
  1163 		CDllChecker check;
  1164 	
  1165 	//	Create an array to store each dependency's name, Uid and result
  1166 		TRAPD(leaveCode,(check.ConstructL()));	
  1167 	
  1168 		if (leaveCode!=KErrNone)	//	If function leaves
  1169 			{
  1170 			TheConsole->Printf(_L("Dependency checking failed due to error %d\n"), leaveCode);
  1171 			return(KErrNone);
  1172 			}
  1173 
  1174 		TInt result=KErrNone;
  1175 		TRAP(result,(check.GetImportDataL(aCommand,NULL)));
  1176 		
  1177 		if (result==KErrNone)
  1178 			{
  1179 			check.ListArray();	//	Print out the results of DllCheck		
  1180 			return(KErrNone);
  1181 			}
  1182 		}
  1183 #endif
  1184 	return (r);
  1185 }
  1186 
  1187 void CShell::SetCurrentPath(const TDesC& aDes)
  1188 //
  1189 // Set the current Directory
  1190 //
  1191 	{
  1192 
  1193 	__ASSERT_DEBUG(currentPath.MaxLength()>=aDes.Length(),Panic(EShellFilePathTooBig));
  1194 	currentPath=aDes;
  1195 	}
  1196 
  1197 TDes& CShell::CurrentPath()
  1198 //
  1199 // Accessor function
  1200 //
  1201 	{
  1202 	return currentPath;
  1203 	}
  1204 
  1205 
  1206 
  1207 void CShell::SetDrivePath(const TDesC& aDrivePath)
  1208 //
  1209 // Set the drive path
  1210 //
  1211 	{
  1212 
  1213 	__ASSERT_DEBUG(aDrivePath.Length()>=3 && aDrivePath[1]==KDriveDelimiter,Panic(EShellBadDrivePath));
  1214 	TChar drvLetter=aDrivePath[0];
  1215 	__ASSERT_DEBUG(drvLetter.IsAlpha(),Panic(EShellBadDrivePath));
  1216 	TInt drvNum;
  1217     __ASSERT_ALWAYS(charToDrive(drvLetter,drvNum)==KErrNone,User::Panic(_L("Invalid drive letter"),0));
  1218 	drivePaths[drvNum]=aDrivePath;
  1219 	}
  1220 
  1221 
  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 
  1225 	{
  1226 	//create an object to truncate argument list substitution 
  1227 	SimpleOverflowTruncate overflow;	
  1228 	VA_LIST list;
  1229 	VA_START(list,aFmt);
  1230 	
  1231 	TBuf<0x200> aBuf;
  1232 	//format output string using argument list
  1233 	
  1234 	//coverity[uninit_use_in_call]
  1235 	TRAP_IGNORE(aBuf.AppendFormatList(aFmt,list,&overflow)); // ignore leave in TTimeOverflowLeave::Overflow()
  1236 	
  1237 	_LIT(KPrompt , "Press any key to continue\n");		
  1238 	
  1239 	return OutputStringToConsole(KPrompt,aPageSwitch,_L("%S"),&aBuf);
  1240 	}
  1241 
  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
  1246 	{
  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;
  1251 	
  1252 	VA_LIST list;
  1253 	VA_START(list,aFmt);
  1254 	
  1255 	TBuf<0x200> aBuf;
  1256 	//format output string using argumen list
  1257 	
  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
  1261 	if (aPageSwitch)
  1262 		{
  1263 		key=PageSwitchDisplay(aNotification);				
  1264 		}
  1265 	//output current string
  1266 	TheConsole->Write(aBuf);
  1267 	return key;			
  1268 	}
  1269 
  1270 TKeyCode CShell::OutputStringToConsole(TBool aPageSwitch, const TDesC& aBuf)
  1271 	{
  1272 	_LIT(KPrompt , "Press any key to continue\n");
  1273 	
  1274     TKeyCode key=EKeyNull;	
  1275 
  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
  1277 	if (aPageSwitch)
  1278 		{
  1279 		key = PageSwitchDisplay(KPrompt);				
  1280 		}
  1281 	//output current string
  1282 	TheConsole->Write(aBuf);
  1283 	
  1284     return key;
  1285 	}
  1286 
  1287 TKeyCode CShell::PageSwitchDisplay(const TDesC& aNotification)
  1288 	{
  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)) 
  1296 		{
  1297 		add+=1;				
  1298 		}	
  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)) 
  1302 		{
  1303 		notification_height+=1;	
  1304 		}
  1305 	if (add<(TheConsole->ScreenSize().iHeight-2))
  1306 	if ((line_count+add+notification_height)>=(TheConsole->ScreenSize().iHeight-4))
  1307 		{
  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)) ;			
  1313 		}						
  1314 	return key;			
  1315 	}