networkingtestandutils/exampleinternetutilities/TRACERT/TRACERT.CPP
changeset 0 af10295192d8
child 37 052078dda061
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 2001-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 "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 // T_TraceRt.CPP
       
    15 // Started by MWT, June 1997
       
    16 // 
       
    17 //
       
    18 
       
    19 #include <treng.h>
       
    20 #include <e32cons.h>
       
    21 #include <c32comm.h>
       
    22 #include <nifman.h>
       
    23 #include <f32file.h>
       
    24 
       
    25 #ifdef __WINS__
       
    26 #define CDRV1_PATH _L("ECDRV")
       
    27 #define COMM_PATH _L("ECOMM")
       
    28 #endif
       
    29 
       
    30 LOCAL_C TInt Program();
       
    31 
       
    32 const TInt  KHistoryBufferSize = 20;
       
    33 
       
    34 #define KPrompt Command>
       
    35 const TInt KPromptLength = 8;
       
    36 
       
    37 class CHBufCirBuf : public CCirBuf<HBufC*>
       
    38 	{
       
    39 public:
       
    40 	static CHBufCirBuf* NewL(TInt aLength);
       
    41 	~CHBufCirBuf();
       
    42 	TInt Add(const TDesC& aLine);
       
    43 	HBufC*& operator[](TInt anIndex) const;
       
    44 	};
       
    45 
       
    46 class CTraceRtTestKeyStroke;
       
    47 class CTraceRtTestUi : public CTraceRtEng, public MTraceRtNotificationHandler
       
    48 	{
       
    49 public:
       
    50 	static CTraceRtTestUi* NewL();
       
    51 	void ConstructL();
       
    52 	void InitialiseL();
       
    53 	~CTraceRtTestUi();
       
    54 
       
    55 	virtual void Starting(const TNameRecord& aTo, TInt aTtl, TInt aDataLen);
       
    56 	virtual void Probe(TInt aTtl);
       
    57 	virtual void Reply(TInt aNo, TInt aDelta, TUint aId);
       
    58 	virtual void FromHost(const TNameRecord& aHost);
       
    59 	virtual void Finished(TInt aError);
       
    60 
       
    61 	void SetKeyStrokeActive();
       
    62 	void KeyStroke();
       
    63 	void KeyStrokeDoCancel();
       
    64 	void AddToHistory(const TDesC& aLine);
       
    65 	void DisplayHistory(TInt aLine, TInt aPromptLen, TDes& aDes) const;
       
    66 	inline CConsoleBase& Console() { return *iConsole; }
       
    67 
       
    68 private:
       
    69 	CConsoleBase* iConsole;
       
    70 	CTraceRtTestKeyStroke* iKeyHandler;
       
    71 	CHBufCirBuf* iHistory;
       
    72 	};
       
    73 
       
    74 class CTraceRtTestKeyStroke : public CActive
       
    75 	{
       
    76 friend class CTraceRtTestUi;
       
    77 public:
       
    78 	CTraceRtTestKeyStroke(CTraceRtTestUi& aUi);
       
    79 	~CTraceRtTestKeyStroke();
       
    80 	void RunL();
       
    81 	void DoCancel();
       
    82 private:
       
    83 	CTraceRtTestUi* iUi;
       
    84 	};
       
    85 
       
    86 class TTestTraceRtOptions : public TTraceRtOptions
       
    87 	{
       
    88 public:
       
    89 	TInt ParseCommandLine(CTraceRtTestUi& aUI);
       
    90 	};
       
    91 
       
    92 
       
    93 GLDEF_C TInt E32Main()
       
    94 	{
       
    95 
       
    96 	__UHEAP_MARK;
       
    97 	// Stardard stuff
       
    98 	CTrapCleanup* cleanupStack = CTrapCleanup::New();
       
    99 	if(!cleanupStack)
       
   100 		{
       
   101 		return KErrNoMemory;
       
   102 		}
       
   103 
       
   104 	TRAPD(err, Program());
       
   105 
       
   106 	delete cleanupStack;
       
   107 	__UHEAP_MARKEND;
       
   108 	return err;
       
   109 	}
       
   110 
       
   111 LOCAL_C TInt Program()
       
   112 	{
       
   113 
       
   114 	TInt ret = 0;
       
   115 
       
   116 	CActiveScheduler* as = new(ELeave) CActiveScheduler;
       
   117 	CleanupStack::PushL(as);
       
   118 	CActiveScheduler::Install(as);
       
   119 
       
   120 	CTraceRtTestUi* ui = CTraceRtTestUi::NewL();
       
   121 	CleanupStack::PushL(ui);
       
   122 
       
   123 	FOREVER
       
   124 		{
       
   125 
       
   126 		TTestTraceRtOptions options;
       
   127 		if((ret=options.ParseCommandLine(*ui))!=KErrNone)
       
   128 			{
       
   129 			break;
       
   130 			}
       
   131 	
       
   132 		ui->SetKeyStrokeActive();
       
   133 		ui->Start(options);
       
   134 		CActiveScheduler::Start();
       
   135 		}
       
   136 
       
   137 	CleanupStack::PopAndDestroy(ui);
       
   138 	CleanupStack::PopAndDestroy(as);
       
   139 
       
   140 	return ret;
       
   141 	}
       
   142 
       
   143 CTraceRtTestUi* CTraceRtTestUi::NewL()
       
   144 //
       
   145 // Create new test UI
       
   146 //
       
   147 	{
       
   148 
       
   149 	CTraceRtTestUi* ui = new (ELeave) CTraceRtTestUi;
       
   150 	CleanupStack::PushL(ui);
       
   151 	ui->ConstructL();
       
   152 	CleanupStack::Pop();
       
   153 	return ui;
       
   154 	}
       
   155 
       
   156 void CTraceRtTestUi::InitialiseL()
       
   157 //
       
   158 // Ensure stuff is loaded etc
       
   159 //
       
   160 	{
       
   161 
       
   162 #ifdef __WINS__
       
   163     User::LoadPhysicalDevice(CDRV1_PATH);    
       
   164     User::LoadLogicalDevice(COMM_PATH);
       
   165 #endif
       
   166 //	User::LeaveIfError(Nifman::CheckIniConfig());
       
   167 	}
       
   168 
       
   169 
       
   170 void CTraceRtTestUi::ConstructL()
       
   171 //
       
   172 // Contruct base object and console
       
   173 //
       
   174 	{
       
   175 	
       
   176 	iKeyHandler = new (ELeave) CTraceRtTestKeyStroke(*this);
       
   177 	iHistory = CHBufCirBuf::NewL(KHistoryBufferSize);
       
   178 	iConsole = Console::NewL(_L("Trace Route"),TSize(KConsFullScreen,KConsFullScreen));
       
   179 	InitialiseL();
       
   180 	CTraceRtEng::ConstructL(*this);
       
   181 	}
       
   182 
       
   183 CTraceRtTestUi::~CTraceRtTestUi()
       
   184 //
       
   185 // Delete console
       
   186 //
       
   187 	{
       
   188 	 
       
   189 	delete iHistory;
       
   190 	delete iKeyHandler;
       
   191 	delete iConsole;
       
   192 	}
       
   193 	
       
   194 void CTraceRtTestUi::AddToHistory(const TDesC& aLine)
       
   195 //
       
   196 // Add line to history buffer
       
   197 //
       
   198 	{
       
   199 	
       
   200 	iHistory->Add(aLine);
       
   201 	}
       
   202 	
       
   203 void CTraceRtTestUi::DisplayHistory(TInt aLine, TInt aPromptLen, TDes& aDes) const
       
   204 	{
       
   205 	
       
   206 	aDes.SetLength(0);
       
   207 	if(!iHistory->Count())
       
   208 		{
       
   209 		return;
       
   210 		}
       
   211 	const HBufC* line=(*iHistory)[aLine];
       
   212 	iConsole->SetPos(aPromptLen);
       
   213 	iConsole->ClearToEndOfLine();
       
   214 	iConsole->Write(*line);
       
   215 	aDes.Append(*line);
       
   216 	}
       
   217 
       
   218 void CTraceRtTestUi::Starting(const TNameRecord& aTo, TInt aTtl, TInt)
       
   219 //
       
   220 // Starting trace route to remote host
       
   221 //
       
   222 	{
       
   223 
       
   224 	TName ipaddr;
       
   225 	TInetAddr& addr = (TInetAddr&)aTo.iAddr;
       
   226 	addr.Output(ipaddr);
       
   227 	
       
   228 	if(aTo.iName.Length())
       
   229 		{
       
   230 		iConsole->Printf(_L("Tracing route to %S [%S]\n\r"), &aTo.iName, &ipaddr);
       
   231 		}
       
   232 	else
       
   233 		{
       
   234 		iConsole->Printf(_L("Tracing route to %S\n\r"), &ipaddr);
       
   235 		}
       
   236 	iConsole->Printf(_L("Over a maximum of %d hops\n\r\n\r"), aTtl);
       
   237 	}
       
   238 
       
   239 void CTraceRtTestUi::Probe(TInt aTtl)
       
   240 //
       
   241 // First line of output
       
   242 //
       
   243 	{
       
   244 	
       
   245 	iConsole->Printf(_L("%3d "), aTtl);
       
   246 	}
       
   247 
       
   248 void CTraceRtTestUi::Reply(TInt, TInt aDelta, TUint aId)
       
   249 //
       
   250 // A reply from a remote host
       
   251 //
       
   252 	{
       
   253 
       
   254 	TName buf;
       
   255 
       
   256 	if(aId==KTraceRtCodeTimeout)
       
   257 		{
       
   258 		buf.Append(_L("     "));
       
   259 		}
       
   260 	else if(aDelta<10)
       
   261 		{
       
   262 		buf.Append(_L(" <10 "));
       
   263 		}
       
   264 	else
       
   265 		{
       
   266 		buf.AppendFormat(_L("%4d "), aDelta);
       
   267 		}
       
   268 
       
   269 	switch(aId)
       
   270 		{
       
   271 	case KTraceRtCodeUnreachNet: buf.AppendFormat(_L("!N ")); break;
       
   272 	case KTraceRtCodeUnreachHost:  buf.AppendFormat(_L("!H ")); break;
       
   273 	case KTraceRtCodeUnreachProtocol:  buf.AppendFormat(_L("!@ ")); break;
       
   274 	case KTraceRtCodeUnreachPort:  buf.AppendFormat(_L("!?  ")); break;
       
   275 	case KTraceRtCodeUnreachNeedFrag:  buf.AppendFormat(_L("!F ")); break;
       
   276 	case KTraceRtCodeUnreachSrcRouteFail:  buf.AppendFormat(_L("!R ")); break;
       
   277 	case KTraceRtCodeUnreachNetUnknown:  buf.AppendFormat(_L("!U ")); break;
       
   278 	case KTraceRtCodeUnreachHostUnknown:  buf.AppendFormat(_L("!J ")); break;
       
   279 	case KTraceRtCodeUnreachSrcHostIsolated:  buf.AppendFormat(_L("!I ")); break;
       
   280 	case KTraceRtCodeUnreachNetProhibited:  buf.AppendFormat(_L("!X ")); break;
       
   281 	case KTraceRtCodeUnreachHostProhibited:  buf.AppendFormat(_L("!Z ")); break;
       
   282 	case KTraceRtCodeUnreachNetTOS:  buf.AppendFormat(_L("!T ")); break;
       
   283 	case KTraceRtCodeUnreachHostTOS:  buf.AppendFormat(_L("!Q ")); break;
       
   284 	case KTraceRtCodeUnreachProhibited:  buf.AppendFormat(_L("!Y ")); break;
       
   285 	case KTraceRtCodeUnreachPrecVolation:  buf.AppendFormat(_L("!V ")); break;
       
   286 	case KTraceRtCodeUnreachPrecCutoff:  buf.AppendFormat(_L("!N ")); break;
       
   287 	case KTraceRtCodeTimeout:  buf.AppendFormat(_L("*  ")); break;
       
   288 	default:  buf.AppendFormat(_L("   ")); break;
       
   289 		}
       
   290 	iConsole->Printf(buf);
       
   291 	}
       
   292 
       
   293 void CTraceRtTestUi::FromHost(const TNameRecord& aHost)
       
   294 //
       
   295 // End of line output with host name
       
   296 //
       
   297 	{
       
   298 
       
   299 	TInetAddr& a=TInetAddr::Cast(aHost.iAddr);
       
   300 	TName ip;
       
   301 	a.Output(ip);
       
   302 
       
   303 	if(a.Address()==0)
       
   304 		{
       
   305 		iConsole->Printf(_L("\n"));
       
   306 		}
       
   307 	else if(aHost.iName.Length()==0)
       
   308 		{
       
   309 		iConsole->Printf(_L("%S\n\r"), &ip);
       
   310 		}
       
   311 	else
       
   312 		{
       
   313 		iConsole->Printf(_L("%S [%S]\n\r"), &aHost.iName, &ip);
       
   314 		}
       
   315 	}
       
   316 
       
   317 void CTraceRtTestUi::Finished(TInt aError)
       
   318 //
       
   319 // Trace Complete
       
   320 //
       
   321 	{
       
   322 
       
   323 	if(aError)
       
   324 		{
       
   325 		iConsole->Printf(_L("\n\rTrace complete %d\n\r"), aError);
       
   326 		}
       
   327 	else
       
   328 		{
       
   329 		iConsole->Printf(_L("\n\rTrace complete\n\r"));
       
   330 		}
       
   331 	iKeyHandler->Cancel();
       
   332 	CActiveScheduler::Stop();
       
   333 	}
       
   334 
       
   335 void CTraceRtTestUi::KeyStroke()
       
   336 //
       
   337 // Key was pressed
       
   338 //
       
   339 	{
       
   340 	
       
   341 	if(iKeyHandler->iStatus==KErrNone)
       
   342 		{
       
   343 
       
   344 		if(iConsole->KeyCode()==EKeyEscape)
       
   345 			{
       
   346 			iConsole->Printf(_L("\nAborted\n"));
       
   347 			CancelAndFinished();
       
   348 			return;
       
   349 			}
       
   350 
       
   351 		}
       
   352 	SetKeyStrokeActive();
       
   353 	}
       
   354 
       
   355 void CTraceRtTestUi::SetKeyStrokeActive()
       
   356 //
       
   357 //
       
   358 //
       
   359 	{
       
   360 	
       
   361 	iConsole->Read(iKeyHandler->iStatus);
       
   362 	iKeyHandler->SetActive();
       
   363 	}
       
   364 
       
   365 void CTraceRtTestUi::KeyStrokeDoCancel()
       
   366 //
       
   367 // Cancel the read
       
   368 //
       
   369 	{
       
   370 
       
   371 	iConsole->ReadCancel();
       
   372 	}
       
   373 
       
   374 CTraceRtTestKeyStroke::CTraceRtTestKeyStroke(CTraceRtTestUi& aUi)
       
   375 //
       
   376 // Key reader
       
   377 //
       
   378 	: CActive(0)
       
   379 	{
       
   380 	
       
   381 	iUi = &aUi;
       
   382 	CActiveScheduler::Add(this);
       
   383 	}
       
   384 
       
   385 CTraceRtTestKeyStroke::~CTraceRtTestKeyStroke()
       
   386 //
       
   387 // Destruct means cancel
       
   388 //
       
   389 	{
       
   390 
       
   391 	Cancel();
       
   392 	}
       
   393 	
       
   394 void CTraceRtTestKeyStroke::RunL()
       
   395 //
       
   396 // Key pressed
       
   397 //
       
   398 	{
       
   399 
       
   400 	iUi->KeyStroke();
       
   401 	}
       
   402 
       
   403 void CTraceRtTestKeyStroke::DoCancel()
       
   404 //
       
   405 // Cancel key stroke
       
   406 //
       
   407 	{
       
   408 
       
   409 	iUi->KeyStrokeDoCancel();
       
   410 	}
       
   411 
       
   412 TInt TTestTraceRtOptions::ParseCommandLine(CTraceRtTestUi& aUi)
       
   413 //
       
   414 //
       
   415 //
       
   416 	{
       
   417 
       
   418 	TInt res;
       
   419 	TBool help;
       
   420 	do
       
   421 		{
       
   422 		TBuf<0x100> command;
       
   423 		aUi.Console().Printf(_L("KPrompt"));
       
   424 		TKeyCode key, was=EKeyNull;
       
   425 		TInt histpos=-1;
       
   426 		while((key=aUi.Console().Getch())!=EKeyEnter)
       
   427 			{
       
   428 			if(command.Length()>=0x100)
       
   429 				{
       
   430 				User::Beep(440, 500000);
       
   431 				}
       
   432 			else if(key==EKeyBackspace || key==EKeyLeftArrow || key==EKeyDelete)
       
   433 				{
       
   434 				if(command.Length())
       
   435 					{
       
   436 					aUi.Console().Printf(_L("\b \b"));
       
   437 					command.SetLength(command.Length()-1);
       
   438 					}
       
   439 				}
       
   440 			else if(key == EKeyUpArrow)
       
   441 				{
       
   442 				if(was==EKeyDownArrow)
       
   443 					{
       
   444 					++histpos;
       
   445 					}
       
   446 				was=key;
       
   447 				aUi.DisplayHistory(++histpos, KPromptLength, command);
       
   448 				}
       
   449 			else if(key == EKeyDownArrow)
       
   450 				{
       
   451 				if(was==EKeyUpArrow)
       
   452 					{
       
   453 					histpos--;
       
   454 					}
       
   455 				was=key;
       
   456 				aUi.DisplayHistory(histpos--, KPromptLength, command);
       
   457 				}
       
   458 			else if(key>=EKeySpace && key<=EKeyDelete)
       
   459 				{
       
   460 				aUi.Console().Printf(_L("%c"), key);
       
   461 				command.Append(TChar(key));
       
   462 				}
       
   463 			}
       
   464 		aUi.Console().Printf(_L("\n"));
       
   465 		aUi.AddToHistory(command);
       
   466 
       
   467 		(*this) = TTestTraceRtOptions();
       
   468 		iDestname = _L("127.0.0.1");
       
   469 		TLex lex(command);
       
   470 		res=KErrNone;
       
   471 		help=EFalse;
       
   472 
       
   473 		TPtrC ptr;
       
   474 		for(ptr.Set(lex.NextToken()) ; ptr.Length() ; ptr.Set(lex.NextToken()))
       
   475 			{
       
   476 
       
   477 			if(!ptr.CompareF(_L("q")) || !ptr.CompareF(_L("quit")) || !ptr.CompareF(_L("exit")))
       
   478 				{
       
   479 				return KErrEof;
       
   480 				}
       
   481 			if(!ptr.CompareF(_L("help")))
       
   482 				{
       
   483 				help=ETrue;
       
   484 				}
       
   485 			else if(ptr.Length()==2)
       
   486 				{
       
   487 				if(!ptr.CompareF(_L("-D")))
       
   488 					{
       
   489 					iResolveAddress=EFalse;
       
   490 					}
       
   491 				else if(!ptr.CompareF(_L("-H")))
       
   492 					{
       
   493 					help=ETrue;
       
   494 					}
       
   495 				else
       
   496 					{
       
   497 					iDestname=ptr;
       
   498 					}
       
   499 				if(!ptr.CompareF(_L("-C")))
       
   500 					{
       
   501 					iPrompt = ETrue;
       
   502 					}
       
   503 				else
       
   504 					{
       
   505 					iPrompt = EFalse;
       
   506 					}
       
   507 				}
       
   508 			else if(ptr.Length()>2)
       
   509 				{
       
   510 
       
   511 				TLex val(ptr.Mid(2));
       
   512 				TInt num;
       
   513 
       
   514 				TPtrC cmd = ptr.Mid(0,2);
       
   515 
       
   516 				if(!cmd.CompareF(_L("-M")))
       
   517 					{
       
   518 					if(val.Val(iMaxTtl) != KErrNone)
       
   519 						{
       
   520 						res=KErrArgument;
       
   521 						}
       
   522 					else if(iMaxTtl<1)
       
   523 						{
       
   524 						res=KErrUnderflow;
       
   525 						}
       
   526 					}
       
   527 				else if(!cmd.CompareF(_L("-W")))
       
   528 					{
       
   529 					if(val.Val(num) != KErrNone)
       
   530 						{
       
   531 						res=KErrArgument;
       
   532 						}
       
   533 					else if(num<0)
       
   534 						{
       
   535 						res=KErrUnderflow;
       
   536 						}
       
   537 					else
       
   538 						{
       
   539 						iWait=num;
       
   540 						}
       
   541 					}
       
   542 				else if(!cmd.CompareF(_L("-V")))
       
   543 					{
       
   544 					if(val.Val(iTos) != KErrNone)
       
   545 						{
       
   546 						res=KErrArgument;
       
   547 						}
       
   548 					else if(iTos<1)
       
   549 						{
       
   550 						res=KErrUnderflow;
       
   551 						}
       
   552 					else if(iTos>255)
       
   553 						{
       
   554 						res=KErrOverflow;
       
   555 						}
       
   556 					}
       
   557 				else if(!cmd.CompareF(_L("-P")))
       
   558 					{
       
   559 					if(val.Val(iNrProbes) != KErrNone)
       
   560 						{
       
   561 						res=KErrArgument;
       
   562 						}
       
   563 					else if(iNrProbes<0)
       
   564 						{
       
   565 						res=KErrUnderflow;
       
   566 						}
       
   567 					}
       
   568 				else
       
   569 					{
       
   570 					iDestname = ptr;
       
   571 					}
       
   572 				}
       
   573 			else
       
   574 				{
       
   575 				iDestname = ptr;
       
   576 				}
       
   577 
       
   578 			if(res!=KErrNone || help)
       
   579 				{
       
   580 				
       
   581 				if(!help)
       
   582 					{
       
   583 				    	aUi.Console().Printf(_L("Incorrect option %S - result %d\n"), &ptr, res);
       
   584 					}
       
   585 				aUi.Console().Printf(_L("Usage: [options] destination\n\nwhere options are\n"));
       
   586 				aUi.Console().Printf(_L("    -d         do not resolve addresses to hostnames\n"));
       
   587 				aUi.Console().Printf(_L("    -c         prompt for interface choice\n"));
       
   588 				aUi.Console().Printf(_L("    -h         print out this screen\n"));
       
   589 				aUi.Console().Printf(_L("    -m<number> maximum number of hops\n"));
       
   590 				aUi.Console().Printf(_L("    -w<number> time to wait for replies\n"));
       
   591 				aUi.Console().Printf(_L("    -v<number> tos\n"));
       
   592 				aUi.Console().Printf(_L("    -p<number> number of probes\n"));
       
   593 				aUi.Console().Printf(_L("    quit, q or exit to finish\n\n"));
       
   594 				
       
   595 				break;
       
   596 				}
       
   597 			}
       
   598 		} while (res!=KErrNone || help);
       
   599 
       
   600     return KErrNone;
       
   601 	}
       
   602 
       
   603 CHBufCirBuf* CHBufCirBuf::NewL(TInt aLength)
       
   604 //
       
   605 // Create new circular buffer for command line history
       
   606 //
       
   607 	{
       
   608 
       
   609 	CHBufCirBuf*p = new (ELeave) CHBufCirBuf;
       
   610 	CleanupStack::PushL(p);
       
   611 	p->SetLengthL(aLength);
       
   612 	CleanupStack::Pop();
       
   613 	return p;
       
   614 	}
       
   615 
       
   616 CHBufCirBuf::~CHBufCirBuf()
       
   617 //
       
   618 // Delete contents
       
   619 //
       
   620 	{
       
   621 	
       
   622 	while(Count())
       
   623 		{
       
   624 		HBufC* buf;
       
   625 		Remove(&buf);
       
   626 		delete buf;
       
   627 		}
       
   628 	}
       
   629 
       
   630 TInt CHBufCirBuf::Add(const TDesC& aLine)
       
   631 //
       
   632 // Add a new line to the buffer
       
   633 //
       
   634 	{
       
   635 
       
   636 	if(!aLine.Length())
       
   637 		{
       
   638 		return KErrNotFound;
       
   639 		}
       
   640 
       
   641 	TInt i;
       
   642 	HBufC* buf=0;
       
   643 	for(i=Count()-1; i>=0 ; --i)
       
   644 		{
       
   645 		if(!buf)
       
   646 			{
       
   647 			if(!(*this)[i]->Compare(aLine))
       
   648 				{
       
   649 				buf=(*this)[i];
       
   650 				}
       
   651 			}
       
   652 		if(buf)
       
   653 			{
       
   654 			if(i==0)
       
   655 				{
       
   656 				(*this)[0]=buf;
       
   657 				return KErrNone;
       
   658 				}
       
   659 			else
       
   660 				{
       
   661 				(*this)[i]=(*this)[i-1];
       
   662 				}
       
   663 			}
       
   664 		}
       
   665 
       
   666 	if(Count()==Length())
       
   667 		{
       
   668 		Remove(&buf);
       
   669 		delete buf;
       
   670 		}
       
   671 
       
   672 	buf=aLine.Alloc();
       
   673 	if(!buf)
       
   674 		{
       
   675 		return KErrNoMemory;
       
   676 		}
       
   677 	
       
   678 	return CCirBuf<HBufC*>::Add(&buf);
       
   679 	}
       
   680 
       
   681 HBufC*& CHBufCirBuf::operator[](TInt aIndex) const
       
   682 //
       
   683 // Return index relative to last element added
       
   684 // doesn't matter if index is out of range because it is wrapped
       
   685 //
       
   686 	{
       
   687 
       
   688 	aIndex=aIndex%iCount;
       
   689 	if(aIndex<0)
       
   690 		{
       
   691 		aIndex=iCount+aIndex;
       
   692 		}
       
   693 	++aIndex;
       
   694 
       
   695 	// Offset to required element
       
   696 	// Made static to remove GCC warnings.
       
   697 	static TUint8* offset = iHead-aIndex*iSize;
       
   698 	if(offset<iPtr)
       
   699 		{
       
   700 		offset=PtrSub(iPtrE,iPtr-offset);
       
   701 		}
       
   702 
       
   703 	return *(HBufC**)offset;
       
   704 	}