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