srcanamdw_os/leavescan/source/leavescan.cpp
changeset 0 83f4b4db085c
child 1 d4b442d23379
equal deleted inserted replaced
-1:000000000000 0:83f4b4db085c
       
     1 // Copyright (c) 1997-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 // Limitations:
       
    15 // Leavescan will attempt to avoid comments, strings and char literals which it
       
    16 // finds within the code. It is also capable of recognising escaped quotes,
       
    17 // but complex combinations of escaping e.g. "\\\"\"\'" may fool the parser and
       
    18 // result in false positives, or cause parsing to terminate prematurely (resulting
       
    19 // in possible unreported problems.
       
    20 // Leavescan can only parse what it sees, and is therefore oblivious to any 
       
    21 // non-trivial attempt to call a leaving function (i.e. by function pointer)
       
    22 // Macros can also fool the parser (as is), but leavscan will now indicate
       
    23 // whether the leaving invocation may, in fact, be a macro.
       
    24 // Multiple files are now supported on the command-line, along with some basic
       
    25 // options such as '-v' which will dump the version. Invoking with no 
       
    26 // parameters will dump the version & help, so that automated build systems can
       
    27 // check the version and cater for enhanced behaviour.
       
    28 // Local Version:
       
    29 // $Id: leavescan2.cpp,v 1.6 2003/02/19 12:59:00 AndrewHa Exp $
       
    30 // 
       
    31 //
       
    32 
       
    33 
       
    34 #include <fstream>
       
    35 #include <iostream>
       
    36 #include <sstream>   
       
    37 #include <string>
       
    38 #include <assert.h>
       
    39 #include <list>
       
    40 
       
    41 #define FOREVER for(;;)
       
    42 
       
    43 //static const char Kversion[] = "0.06"; // Version updated 07 March 08
       
    44 static const char Kversion[] = "0.07";  // suprrot L class, fix some defects.Version updated 07/2008
       
    45 // Shorthand
       
    46 typedef unsigned int uint;
       
    47 
       
    48 // Set of match types. E_Last must be at the end of the list.
       
    49 enum TMatchTypes { 
       
    50   E_LCleanedUp=0,
       
    51   E_LString,
       
    52   E_LManaged,
       
    53   E_LData,
       
    54   E_Ell , 
       
    55   E_Trap, 
       
    56   E_BlockComment, 
       
    57   E_LineComment, 
       
    58   E_Eleave, 
       
    59   E_UserEleave, 
       
    60   E_String,
       
    61   E_Quote,
       
    62   E_OpenBrace,
       
    63   E_CloseBrace,
       
    64   E_OrLeave,
       
    65   E_Last };
       
    66 
       
    67 // Set of return values of GetFunc().
       
    68 enum TReturnTypes {
       
    69   E_False = 0,
       
    70   E_True,
       
    71   E_Continue };
       
    72   
       
    73 enum TPPState { 
       
    74    PPSTATE_NORMAL=0,
       
    75    PPSTATE_ESCAPED_LINE ,
       
    76    PPSTATE_SINGLE_COMMENT,
       
    77    PPSTATE_MUL_COMMENT,
       
    78    PPSTATE_STRING_LITERAL,
       
    79    PPSTATE_SHARP_COMMENT
       
    80   };
       
    81 
       
    82 enum TClassMemberTypes { 
       
    83     E_NA= 0, 
       
    84     E_MemberData, 
       
    85     E_MemberFunctionDecl, 
       
    86     E_MemberFunctionDef, 
       
    87     E_Enum
       
    88     };
       
    89 
       
    90 using namespace std;
       
    91 struct ClassMeta {
       
    92 	 string className ;
       
    93 	 int startPos;
       
    94 	 int endPos;
       
    95 };
       
    96 
       
    97 class TLeaveScanModel
       
    98 {
       
    99 public:
       
   100   bool  Scan(ifstream& aStream);
       
   101   void  SetFileName(char* aName);
       
   102   char* FileName();
       
   103   int   Verbose;
       
   104   bool OnlyPrePrecess;
       
   105 
       
   106 private:	
       
   107   void  FileToText(ifstream& aStream, string& aText);
       
   108   enum  TReturnTypes  GetFunc(const string& aFile, string &name, uint &start, uint &end);
       
   109   bool  CheckFunc(const string& aFile, string& aName, uint start, uint end, bool& aIsLeaver);
       
   110   bool  MoveToEndOfTrapHarness(const string& aStr, uint& aIndex, uint aLen);
       
   111   void  MoveToEndOfComment(const string& aStr, uint& aIndex, uint aLen);
       
   112   void  MoveToEndOfLine(const string& aStr, uint& aIndex, uint aLen);
       
   113   void  MoveToEndOfString(const string& aStr, uint& aIndex, uint aLen, char aQuote);
       
   114   uint  GetRealStartPosition(const string& aFile, uint aStart, uint aIsvalidDoublecolon);
       
   115   void  Peek(const string aStr, uint aPos);
       
   116   uint  SmartFind(const string& aStr, const string& aTarget, uint aStart);
       
   117   uint  SmartFindEndOfString(const string& aStr, uint aPos, char aQuote);
       
   118   bool  IsInCommentScopeOrKeyword(const string& aFile, string &aName, uint aStartposition, uint aStartbraceposn);
       
   119   bool  IsFunctionNameStringNotAMacro(const string& aFile, uint aStartbraceposn, uint aTempParenPos, uint aNstart);
       
   120   bool  IsSemiColonAndAssignmentOccurs(const string& aFile, uint aStartbraceposn, uint aTempParenPos);
       
   121   bool  CheckValidFuncName(const string& aFile, uint aStart);
       
   122   bool  CheckForTemplateFunc(const string& aFile, uint nstart, uint nend);
       
   123   uint  FindFirstMatchType(uint aMatchSet[]);
       
   124   string PreProcess(const string& aFile);
       
   125   string CombineLine(const string& aFile);
       
   126   list<ClassMeta> GetClass(const string& aFile);
       
   127   int GetLeftParenthesis(const string& aText, uint pos);
       
   128   int GetRightParenthesis(const string& aText, uint pos);
       
   129   int GetLeftTmpltParentBack(const string& aText,uint pos);
       
   130   int GetRightTmpltParent(const string& aText,uint pos);
       
   131   bool IsClassKeyword(const string& aText, uint aBegin, uint aEnd);
       
   132   int GetLeftBracket(const string& aText,uint pos);
       
   133   int GetRightBracket(const string& aText,uint pos);
       
   134   void CheckClass(const string& aText , const string& aClassName, uint start,uint end);
       
   135   void CheckInClassFunc(const string& aText , const string& aClassName, const string& aFuncName, uint start,uint end);
       
   136   bool IsLClassCtor(const string& aName);
       
   137   bool IsInClassScope(uint pos);
       
   138   string GetFunctNameFromFuncHead(const string& aFuncHead);
       
   139   string GetFunctionParam(const string& aText, uint aStart);
       
   140   string GetFunctionHead(const string& aText, uint aStart);
       
   141   string GetErrorLineHead(const string& aText,uint aStart);
       
   142   string GetClassName(uint aStart);
       
   143   void  ReportErrorLineAndString(uint aStart);
       
   144   bool  AppendCommentToErrorString(uint aEnd);
       
   145   bool  IdentifyMacro(const string& str, const uint aPos);
       
   146   void  Test1();
       
   147   void  Test2L();
       
   148   void  Test3();
       
   149   void  Test4();
       
   150   
       
   151   inline bool IsNewLine(const char& aCurChar) {return ((aCurChar)=='\n'||(aCurChar)=='\r')?true:false;}
       
   152   inline bool IsLastChar(uint aCurPos, uint aStringLength) { return ((aCurPos+1)==aStringLength)?true:false;}
       
   153   inline bool HasEnoughChar(uint aCurPos,uint aStringLength,uint aWanted) {return (aStringLength-aCurPos-1>=aWanted)?true:false;}
       
   154   inline string TrimString(const string& aStr)
       
   155   {
       
   156 	string result = aStr;
       
   157 	result.erase(result.find_last_not_of(" \t\n\r")+1);
       
   158 	result.erase(0,result.find_first_not_of(" \t\n\r"));
       
   159 	return result;
       
   160   }
       
   161 private:
       
   162   string	iText;
       
   163   string	iBody;
       
   164   string	iErrorString;
       
   165   list<ClassMeta> iClassList;
       
   166   int	        iPositionOfError;
       
   167   char*         iFileName;
       
   168   
       
   169 };
       
   170 
       
   171 void pversion()
       
   172 {
       
   173   cout << "Leavescan version: " << Kversion <<"(build time:"<<__DATE__<<" "<<__TIME__<<")\n";
       
   174 }
       
   175 
       
   176 void pusage()
       
   177 {
       
   178   pversion();
       
   179   cout << "syntax: \n\tleavescan [-h|-n|-v|-N] <iFilename.cpp> [<iFilename.cpp> ...]\n\n";
       
   180   cout << "\t-h: This help.\n";
       
   181   cout << "\t-n: Noisy output - provides diagnostics (if available).\n";
       
   182   cout << "\t-N: Very noisy output - provides diagnostics (if available).\n";
       
   183   cout << "\t-v: Displays version (for build & automation systems).\n";
       
   184   cout << "\t-E: Only do pre-process\n\n";
       
   185 
       
   186 }
       
   187 
       
   188 int main(int argc, char** argv)
       
   189 {
       
   190   int noisy = 0;
       
   191   bool onlyPreProcess =false;
       
   192   if (argc < 2)
       
   193     {
       
   194       pusage();
       
   195       return 1;
       
   196     }
       
   197   
       
   198   for (int clparam = 1; clparam < argc; clparam++)
       
   199     {
       
   200       if (argv[clparam][0] == '-')
       
   201 	{
       
   202 	  switch(argv[clparam][1])
       
   203 	    {
       
   204 	    case 'n':
       
   205 	      noisy = 1;
       
   206 	      break;
       
   207 	    case 'N':
       
   208 	      noisy = 2;
       
   209 	      break;
       
   210 	    case 'h':
       
   211 	      pusage();
       
   212 	      break;
       
   213 	    case 'v':
       
   214 	      pversion();
       
   215 	      break;
       
   216 	    case 'E':
       
   217 	    	{
       
   218 	    		onlyPreProcess = true;
       
   219 	    	}
       
   220 	      break;
       
   221 	    default:
       
   222 	      pusage();
       
   223 	      break;
       
   224 	    }
       
   225 	} //if
       
   226       else
       
   227 	{
       
   228 	  // invoked once per file
       
   229 	  TLeaveScanModel model;
       
   230 	  model.SetFileName(argv[clparam]);
       
   231 	  model.Verbose = noisy;
       
   232 	  if(onlyPreProcess)
       
   233 	  {
       
   234 		  model.OnlyPrePrecess = true;
       
   235 	  }
       
   236 	  else
       
   237 	  {
       
   238 		  model.OnlyPrePrecess = false;
       
   239 	  }
       
   240 	  ifstream file(model.FileName());
       
   241 	  (void) model.Scan(file);
       
   242 	  file.close();
       
   243 	  //	  return 0;
       
   244 	}
       
   245     }
       
   246   return 0;
       
   247 }
       
   248   
       
   249 void TLeaveScanModel::SetFileName(char *aName)
       
   250 {
       
   251   iFileName = aName;
       
   252 }
       
   253 
       
   254 char* TLeaveScanModel::FileName()
       
   255 {
       
   256   return iFileName;
       
   257 }
       
   258 
       
   259 //
       
   260 // Main processing function which converts the file to a basic::string
       
   261 // and then searches through for methods, analysing them as they are
       
   262 // located.
       
   263 bool TLeaveScanModel::Scan(ifstream& aStream)
       
   264 {
       
   265   FileToText(aStream, iText);
       
   266   string oldText(iText);
       
   267   iText = PreProcess(iText);
       
   268   if(OnlyPrePrecess)
       
   269 	  {
       
   270 	  	cout<<iText;
       
   271 	  	return false;
       
   272 	  }
       
   273   if(!iText.length())
       
   274     {
       
   275       cout << "File not found or empty.\n";
       
   276       return false;
       
   277     }
       
   278   
       
   279   uint start  = 0;
       
   280   uint end    = 0;
       
   281   bool isLeaver;
       
   282   enum TReturnTypes getFuncReturnTypes;
       
   283   //init class list
       
   284   iClassList = GetClass(iText);
       
   285   //check function
       
   286   while (start < iText.length())
       
   287     {
       
   288       string name;
       
   289 	  getFuncReturnTypes = E_Continue;
       
   290 	  while(getFuncReturnTypes == E_Continue)
       
   291 	  {
       
   292 		  getFuncReturnTypes = GetFunc(iText, name, start, end);
       
   293 	  }
       
   294       if (!getFuncReturnTypes)
       
   295 		break;
       
   296       
       
   297       bool clean = CheckFunc(iText, name, start, end, isLeaver);
       
   298       bool isLCFunc =false;
       
   299       if(name[name.length()-1] == 'C' && name[name.length()-2] == 'L')
       
   300       {
       
   301     	  isLCFunc = true;
       
   302       }
       
   303       if (isLeaver) // was a leaving container(safe) and no leavers found
       
   304       {
       
   305     	  
       
   306     	  if (clean)
       
   307     	  {
       
   308     		  iPositionOfError=0;
       
   309     		  iErrorString = "Warning - " + name + " appears to contain no leavers.";
       
   310     		  if(!IsInClassScope(start))
       
   311 			  {
       
   312 				  ReportErrorLineAndString(start);	  
       
   313 			  }
       
   314     	  }
       
   315     	  else if(isLCFunc)
       
   316     	  {
       
   317     	      
       
   318 			  uint lcleanedupPos = iErrorString.find("LCleanedup");
       
   319 			  if(lcleanedupPos!=string::npos)
       
   320 				{
       
   321     	    	  uint callPos = iErrorString.find(" calls ");
       
   322 				  uint lcleanedupPosInFuncName = name.find("LCleanedup");
       
   323 				  if(callPos!=string::npos && lcleanedupPosInFuncName!=string::npos && lcleanedupPos<callPos)
       
   324 				  {;}
       
   325 				  else
       
   326 				  {
       
   327 					iErrorString = "LCleanedup class is used in a function suffixed LC";
       
   328     	    		if(!IsInClassScope(start))
       
   329 					{
       
   330 						ReportErrorLineAndString(start);	  
       
   331 					}
       
   332 				  }
       
   333 				}
       
   334     	  }
       
   335 
       
   336     	  // any leavers info can be supressed here since container was leaver
       
   337       }
       
   338       else // wasn't a leaving container 
       
   339       {
       
   340     	  if (!clean) // was dirty, so report
       
   341     		  if(!IsInClassScope(start))
       
   342 			  {
       
   343 				  ReportErrorLineAndString(start);	  
       
   344 			  }
       
   345       }
       
   346       start = end;
       
   347     }
       
   348   //check class 
       
   349   list<ClassMeta>::iterator iter; 
       
   350   for(iter=iClassList.begin();iter!=iClassList.end();iter++) 
       
   351   { 
       
   352 	  CheckClass(iText,iter->className,iter->startPos,iter->endPos);
       
   353   } 
       
   354   return true;
       
   355 }
       
   356 
       
   357 //
       
   358 // Spool a file into one large basic::string
       
   359 //
       
   360 void TLeaveScanModel::FileToText(ifstream& aStream, string& aText)
       
   361 {
       
   362   char data[1024];
       
   363   int len;
       
   364   do	
       
   365     {
       
   366       aStream.read(data,1024);
       
   367       len = aStream.gcount();
       
   368       aText.append(data, len);
       
   369     }
       
   370   while(len);
       
   371 }
       
   372 
       
   373 // To get the actual position of starting parenthesis for a function definition
       
   374 //
       
   375 uint TLeaveScanModel::GetRealStartPosition(const string& aFile,uint aStart, uint aIsvaliddoublecolon)
       
   376 {
       
   377 	uint realstartpos = 0;
       
   378 
       
   379 	// The opening parenthesis which comes fist after opening brace while moving
       
   380  	// in backward direction is a valid candidate for function name.
       
   381 		
       
   382 	uint firstcurlybrace = SmartFind(aFile, "{", aStart + 1 ); // advance start
       
   383 
       
   384 	if ((firstcurlybrace == string::npos) || (firstcurlybrace >= aFile.length())) 
       
   385 	{
       
   386 		return realstartpos;
       
   387 	}
       
   388 
       
   389 	// This variable will store the first paranthesis position
       
   390 	uint tempParenPos = aFile.find_last_of('(',firstcurlybrace);
       
   391 
       
   392 	if (tempParenPos == string::npos)
       
   393 	{
       
   394 		// No '(' found yet
       
   395 		return realstartpos;
       
   396 	}
       
   397 
       
   398 	if (aIsvaliddoublecolon == 1)
       
   399 	{ 
       
   400 		tempParenPos = aStart;	
       
   401 	}
       
   402 	
       
   403 	string whiteSpaceChars = " \t\n\r*&";
       
   404 	
       
   405 	// ignore all tab and spaces between function name and opening parenthesis
       
   406 	uint nend = aFile.find_last_not_of(whiteSpaceChars, --tempParenPos);
       
   407 	uint pos = aFile.find_last_of(whiteSpaceChars, nend);
       
   408 	
       
   409 	if (pos == string::npos)
       
   410 	{
       
   411 		return realstartpos;
       
   412 	}
       
   413 	else
       
   414 	{
       
   415 		return pos;
       
   416 	}
       
   417 }
       
   418 /*
       
   419 This function checks the following :
       
   420 1) Whether the name is in comment scope, name is checked for both C-style comments(or block comments) and C++-style comments(Line Comments)
       
   421 2) The function name is not a keyword having same program construct as function name(i.e. is not among 'while', 'for','if' and 'for'
       
   422 
       
   423 @internalComponent
       
   424 @released
       
   425 @param aFile -  Buffer storing the whole source file contents(input)
       
   426 @param aName -  String that is to be checked whether it lies in the scope of the comment(input)
       
   427 @param aStartposition - Starting offset of name in file.(input)
       
   428 @param aStartbraceposn - Starting offset of function block (input)
       
   429 @param true - if name is in comment scope(output)
       
   430 @param false - if name is not in comment scope
       
   431 
       
   432 
       
   433 Following patterns are handled in this function:
       
   434 -----------------------------------------------
       
   435 NOTE: in order to remove compile warning, i use "|" stand for "/" in this section of comment
       
   436 
       
   437 Pattern 1: String is in the scope of both c-style and C++-style comments
       
   438 		
       
   439 	|*
       
   440 	|| name1
       
   441 	* |
       
   442 
       
   443 	
       
   444 Pattern 2: String is in the scope of both c-style comments
       
   445 
       
   446 	|*
       
   447 		name2()
       
   448 	* |
       
   449 			
       
   450 Pattern 3: String is in comment scope and the comment scope llies in a string
       
   451 			
       
   452 	printf(" |*  * | || ")
       
   453 	
       
   454 
       
   455 Pattern 4: String is in the scope of C++-style comments but C-style comments is also available in souurce file	
       
   456 
       
   457 	|*
       
   458 
       
   459 	* |
       
   460 
       
   461 	|| function() 	
       
   462 		
       
   463 		
       
   464 
       
   465 Pattern 5: String is in the scope of C-style comments but C+++-style comments is also available in souurce file	
       
   466 		
       
   467 	|| function() 	
       
   468 	|*
       
   469 
       
   470 	* |
       
   471 
       
   472 
       
   473 Pattern 6: The string is a keyword and the program construct for the keyword is same as for the functions
       
   474 	for()
       
   475 	{ } 
       
   476 
       
   477 
       
   478 Pattern 7: Both C-style and C++-style comments are avialable in file and the way of specifying comments 
       
   479           is complex.(i.e. it is difficult to identify whether it is a C-Style comment or C++-style comment
       
   480 	  ||*******
       
   481 	   fun() 
       
   482 	  |******
       
   483 		**** | 
       
   484 	  {}
       
   485 
       
   486 */
       
   487 bool TLeaveScanModel::IsInCommentScopeOrKeyword(const string& aFile, string &aName, uint aStartposition,uint aStartbraceposn)
       
   488 {
       
   489 	uint blockCommentStartPosn = aFile.rfind("/*",aStartposition);  // In backward direction
       
   490 	uint lineCommentStartPosn = aFile.rfind("//",aStartposition);
       
   491 	uint blockCommentEndPosn = aFile.find("*/", aStartposition); // In forward direction
       
   492 	uint semicolon = aFile.rfind(";",aStartposition);
       
   493 	uint isvalidlocationforBlock;
       
   494 	uint isvalidlocationforLine ;
       
   495 
       
   496 	if( (0 == strcmp(aName.c_str(),"if")) || (0 == strcmp(aName.c_str(),"while")) ||
       
   497 		(0 == strcmp(aName.c_str(),"for"))|| (0 == strcmp(aName.c_str(),"switch")) ||
       
   498 		(0 == strcmp(aName.c_str(),"defined")))
       
   499 	{
       
   500 		return true;
       
   501 	}
       
   502 	// There is no comment of any type either block comment or line comment 
       
   503 	if(blockCommentStartPosn == string::npos && lineCommentStartPosn == string::npos)
       
   504 	{
       
   505 		return false;
       
   506 	}
       
   507 	// A semiclon exists and semicolon is followed by both (1) the end of block comment scope and (2) the end of line comment scope
       
   508 	else if((semicolon != string::npos)&& 
       
   509 		((semicolon > blockCommentEndPosn) && (blockCommentStartPosn < blockCommentEndPosn))  &&
       
   510 		(semicolon > lineCommentStartPosn))
       
   511 	{
       
   512 		return false;
       
   513 	}
       
   514 	else if(lineCommentStartPosn == string::npos)
       
   515 	{
       
   516 		// Valid Block comment, verify that the function name by applying smartfind
       
   517 		isvalidlocationforBlock = SmartFind(aFile, aName, blockCommentStartPosn); 
       
   518 		if( (isvalidlocationforBlock == string::npos) || // There is no occurrence of name
       
   519 			((isvalidlocationforBlock > aStartbraceposn) && (isvalidlocationforBlock != string::npos))) // The name exists but that is inside function block
       
   520 		{
       
   521 			return true; 
       
   522 		}
       
   523 		else
       
   524 		{
       
   525 			return false; 
       
   526 		}
       
   527 	}
       
   528 	else if(blockCommentStartPosn == string::npos)
       
   529 	{
       
   530 		isvalidlocationforLine = SmartFind(aFile,aName, lineCommentStartPosn); 
       
   531 		if(	(isvalidlocationforLine == string::npos) || // There is no occurrence of name
       
   532 			((isvalidlocationforLine > aStartbraceposn) && (isvalidlocationforLine != string::npos) ) ) // The name exists but that is inside function block
       
   533 		{
       
   534 			return true;
       
   535 		}
       
   536 		else
       
   537 		{
       
   538 			return false;
       
   539 		}
       
   540 	}
       
   541 	else
       
   542 	{
       
   543 		isvalidlocationforBlock = SmartFind(aFile,aName, blockCommentStartPosn); 
       
   544 		isvalidlocationforLine = SmartFind(aFile,aName, lineCommentStartPosn);
       
   545 		if((isvalidlocationforLine == string::npos) )
       
   546 		{
       
   547 		  return true;
       
   548 		}
       
   549 		else if(( (isvalidlocationforLine > aStartbraceposn) && (isvalidlocationforLine != string::npos)) )
       
   550 		{
       
   551 		 return true; 
       
   552 		}
       
   553 		else if( (0 == isvalidlocationforBlock) || ((isvalidlocationforBlock > aStartbraceposn) && (isvalidlocationforBlock != string::npos)) )
       
   554 		{
       
   555 		 return true; 
       
   556 		}
       
   557 		else if(( blockCommentStartPosn <  aStartbraceposn) && (blockCommentEndPosn < aStartbraceposn ) && (blockCommentStartPosn < blockCommentEndPosn) && ((isvalidlocationforBlock == string::npos)))
       
   558 		{
       
   559 			return true; 
       
   560 		}
       
   561 		else
       
   562 		{
       
   563 			return false; 
       
   564 		}
       
   565 	}
       
   566 }
       
   567 
       
   568 /*
       
   569 This function checks whether the function name is a macro or not
       
   570 
       
   571 @internalComponent
       
   572 @released
       
   573 @param aFile - Buffer storing the whole source file contents
       
   574 @param aStartbraceposn - Starting offset of function block (input)
       
   575 @param aParenPos - End position of function signature
       
   576 @param aStartposnofname - Starting offset of string that is to be considered as a function name
       
   577 @param true - If function name is not a macro
       
   578 @param false - If function name is a macro  
       
   579 
       
   580 Following patterns are handled in this function:
       
   581 -----------------------------------------------
       
   582 
       
   583 Pattern 1: Function is invoked in macro
       
   584 
       
   585 	#if defined macro()
       
   586 	#endif
       
   587 	struct s1
       
   588 	{
       
   589 
       
   590 	}
       
   591 
       
   592 Pattern 2: Function is invoked in macro but the macro itself is in comment scope
       
   593 	void fun()
       
   594 	// #if macro()
       
   595 	// #endif
       
   596 	{
       
   597 		struct s1
       
   598 		{
       
   599 		
       
   600 		}
       
   601 	}
       
   602   
       
   603 Pattern 3: There is parameterized Constructor e.g.
       
   604 
       
   605 	Foobar(CFileMan* aFileMan) : iFileMan(aFileMan), iCurrentStep(0) {}
       
   606 
       
   607 
       
   608 Pattern 4: Function is defined on the preprocessor statement e.g 
       
   609 
       
   610 	#define __KTRACE_ALL(a,p) {if((DEBUGMASK&(a))==(a))p;}
       
   611 
       
   612 Pattern 5: All the functions name in comment scope will be ignored
       
   613 
       
   614    void func() 
       
   615 	//	#if comments() 
       
   616 	{
       
   617 	 
       
   618 	}
       
   619 
       
   620 Pattern 6: All the functions name (e.g. comments) in comment scope will be ignored
       
   621   
       
   622    #if defined()
       
   623    // comments() 
       
   624    struct{
       
   625  	}
       
   626 
       
   627 */
       
   628 
       
   629 bool TLeaveScanModel::IsFunctionNameStringNotAMacro(const string& aFile, uint aStartbraceposn, uint aParenPos, uint aStartposnofname)
       
   630 {
       
   631 	uint startofword = 0;
       
   632 	uint endofword = 0;
       
   633 	uint tempParenPos = 0;
       
   634 	bool posn = true;
       
   635 	string whiteSpaceChars = " \t\n\r";
       
   636 	uint tempColonPosn = SmartFind(aFile,":",aParenPos); 
       
   637 	string  colonString(":");
       
   638 	bool isColonInCommentScope = IsInCommentScopeOrKeyword(aFile,colonString,aParenPos,aStartbraceposn);
       
   639 	if(	(tempColonPosn != string::npos)      &&
       
   640 		(false == isColonInCommentScope)     &&
       
   641 		(tempColonPosn < aStartbraceposn) )
       
   642 	{
       
   643 		return true; // Not a macro
       
   644 	}
       
   645 	// The function ignores all the strings which are in the scope of block comments.
       
   646 	while( startofword < aStartbraceposn && endofword < aStartbraceposn && posn == true)
       
   647 	{
       
   648 		if(tempParenPos == 0)
       
   649 		{
       
   650 			tempParenPos = aParenPos; // First word
       
   651 		}
       
   652 		else
       
   653 		{
       
   654 			tempParenPos = endofword; // Next word
       
   655 		}
       
   656 		startofword = aFile.find_first_not_of(whiteSpaceChars, tempParenPos+1);
       
   657 		if(startofword != aStartbraceposn) // No string between function signature and function start block
       
   658 		{
       
   659 			// get the posn of word end boundary
       
   660 			endofword = aFile.find_first_of(whiteSpaceChars, startofword);
       
   661 			string tmpString = aFile.substr(startofword,endofword-startofword);
       
   662 			string &aName = tmpString;
       
   663 			//is throw?
       
   664 			if(0==aName.find("throw"))
       
   665 			{
       
   666 				return true;
       
   667 			}
       
   668 			if(	(0 == strcmp(aName.c_str(),"const")) ||
       
   669 				(0 == strncmp(aName.c_str(),"//",2)) ||
       
   670 				(0 == strncmp(aName.c_str(),"*/",2)) ||
       
   671 				(0 == strncmp(aName.c_str(),"/*",2)) )
       
   672 			{
       
   673 				// do nothing
       
   674 			}
       
   675 			else
       
   676 			{
       
   677 				// If string is in comment scope then it is fine i.e. the  function returns true;
       
   678 				posn = IsInCommentScopeOrKeyword(aFile,aName,startofword,aStartbraceposn);
       
   679 			}
       
   680 		}
       
   681 		else
       
   682 		{
       
   683 			//	Pattern 1: only spaces are there between ')' and '{' e.g. void fun() {}
       
   684 			posn = true;
       
   685 		}
       
   686 	}
       
   687 	if(posn == false)
       
   688 	{
       
   689 		return false;
       
   690 	}
       
   691 	uint endOfLine=aFile.rfind('\n',aStartposnofname);  // Get the new line position while backtracking 
       
   692     uint aIndex=(endOfLine==string::npos ? 0 : endOfLine);
       
   693 	uint preprocessorDirective = aFile.rfind("#",aStartposnofname); // Get the first char of the line starting with #
       
   694 	if(preprocessorDirective != string::npos && aIndex <= preprocessorDirective)
       
   695 	{
       
   696 		return false; // // Yes, the first char is #, so the name on this line can not be a valid function name
       
   697 	}
       
   698 	// Check whether it is a macro 
       
   699 	return true;
       
   700 }
       
   701 
       
   702 
       
   703 
       
   704 /*
       
   705 This function checks whether any semocolon (';') or assignment(=) is encountered 
       
   706 when the backtracking is done to look for function name. 
       
   707   
       
   708 @internalComponent
       
   709 @released
       
   710 @param aFile - Buffer storing the whole source file contents
       
   711 @param aStartbraceposn - Starting offset of function block (input)
       
   712 @param aTempParenPos - End position of function signature
       
   713 @param true - if either assignment expression '=' or ':' occurs between function signature and starting curly brace of function block.
       
   714 @param false - if neither assignment expression '=' nor ':' occurs between function signature and starting curly brace of function block.
       
   715 
       
   716 
       
   717 Following patterns are handled in this function:
       
   718 -----------------------------------------------
       
   719 
       
   720 Pattern 1: The semicolon is encountered while backtracking in the search of function name
       
   721 
       
   722 	_LT();
       
   723 	struct s1
       
   724 	{
       
   725 
       
   726 	}
       
   727 
       
   728 Pattern 2: The semicolon is encountered while backtracking in the search of function name
       
   729 
       
   730   fun();
       
   731   a = 2;
       
   732   struct str1
       
   733   {
       
   734   
       
   735   }
       
   736 
       
   737 Pattern 3: The assignment is encountered while backtracking in the search of function name
       
   738 
       
   739   voidmain()
       
   740   a[2] = 
       
   741   {
       
   742 	1,2,3
       
   743   }
       
   744  
       
   745 */
       
   746 
       
   747 bool TLeaveScanModel::IsSemiColonAndAssignmentOccurs(const string& aFile,uint aStartbraceposn ,uint aTempParenPos)
       
   748 {
       
   749 	string  semicolon(";");
       
   750 	string  assignment("=");
       
   751 	uint tempSemicolonPosn = SmartFind(aFile,semicolon,aTempParenPos-1); 
       
   752 	//uint tempAssignMentPosn = SmartFind(aFile,assignment,aTempParenPos-1); 
       
   753 	bool isSemicolonInCommentScope = IsInCommentScopeOrKeyword(aFile,semicolon,aTempParenPos,aStartbraceposn);
       
   754 	bool isAssignmentInCommentScope = IsInCommentScopeOrKeyword(aFile,assignment,aTempParenPos,aStartbraceposn);
       
   755 	if( (tempSemicolonPosn != string::npos)   &&
       
   756 		((false == isSemicolonInCommentScope) || (false == isAssignmentInCommentScope)) &&
       
   757 		(tempSemicolonPosn < aStartbraceposn) 
       
   758 	  )
       
   759 	{
       
   760 		return false;
       
   761 	}
       
   762 	return true;
       
   763 }
       
   764 
       
   765 /*
       
   766 This function checks whether the function definition is terminated by semi colon
       
   767 
       
   768 If the function definition is terminated with semicolon, then it is
       
   769 more likely to be a class/struct declaration rather than a function definition.
       
   770 
       
   771 @internalComponent
       
   772 @released
       
   773 @param aFile - Buffer storing the whole source file contents
       
   774 @param aStart - Starting offset of the function name string
       
   775 @return true -  If closing brace corresponding to function names is followed by semicolon 
       
   776 @return false - If closing brace corresponding to function names is not by semicolon
       
   777 
       
   778 Following patterns are handled in this function:
       
   779 -----------------------------------------------
       
   780 
       
   781 Pattern 1: NONSHARABLE_CLASS/NONSHARABLE_STRUCT modifier is used
       
   782 
       
   783 	NONSHARABLE_CLASS(...)
       
   784 	{
       
   785 
       
   786 	}; 
       
   787 
       
   788 Pattern 2: function definition is terminated by semicolon 
       
   789 
       
   790 	aaa(...)
       
   791 	{
       
   792 
       
   793 	} // comment
       
   794 	; 
       
   795 
       
   796 Pattern 3: Class is defined in macro
       
   797 
       
   798 	#define MACRO(arg) class name { };
       
   799 
       
   800 */
       
   801 
       
   802 bool TLeaveScanModel::CheckValidFuncName(const string &aFile, uint aStart)
       
   803 {
       
   804   bool returnValue=false;
       
   805   unsigned long uiNumberOfCurlyBraces = 1;
       
   806   unsigned int TempPosn = aStart;
       
   807   unsigned int open_brace = 0;
       
   808   unsigned int close_brace = 0;
       
   809   // Continue till than at least any of open curly or close curly brace is remaining
       
   810   while( !(open_brace == string::npos) || !(close_brace == string::npos) )
       
   811   {
       
   812 		  open_brace = SmartFind(aFile, "{", TempPosn+1);
       
   813 		  close_brace = SmartFind(aFile, "}", TempPosn+1);
       
   814 
       
   815 		  if(open_brace < close_brace) // Handle which curly comes first
       
   816 		  {
       
   817 			  if((open_brace != string::npos)&& open_brace < aFile.size())
       
   818 			  {
       
   819 				uiNumberOfCurlyBraces++; // Update the curly counter
       
   820 				TempPosn = open_brace;   // move forward to the value from where the search of next curly to be started
       
   821 			  }
       
   822 		  }
       
   823 		  else // close brace comes first
       
   824 		  {
       
   825 			  if((close_brace != string::npos)&& close_brace < aFile.size())
       
   826 			  {
       
   827 				uiNumberOfCurlyBraces--;
       
   828 				TempPosn = close_brace; // move forward to the value from where the search of next curly to be started
       
   829 			  }
       
   830 			  if(uiNumberOfCurlyBraces == 0) // Match to the corresponding close curly
       
   831 			  {
       
   832 				break;
       
   833 			  }
       
   834 		  }
       
   835   }
       
   836   if(0 == uiNumberOfCurlyBraces)
       
   837   {
       
   838 	  string whiteSpaceChars = " \t\n\r";
       
   839 	  unsigned int braceFollowsSemicolon1 = 0;
       
   840 	  unsigned int braceFollowsSemicolon2 = 0;
       
   841 
       
   842 	  braceFollowsSemicolon1 = SmartFind(aFile, ";", close_brace); // check if any semocolon exists after }
       
   843 	  braceFollowsSemicolon2 = aFile.find_first_not_of(whiteSpaceChars,close_brace+1); // Get the next character after close_brace
       
   844 
       
   845 	  if( (braceFollowsSemicolon1 == braceFollowsSemicolon2) && (braceFollowsSemicolon1 !=  string::npos) &&   (braceFollowsSemicolon2 !=  string::npos))
       
   846 	  {
       
   847 	   returnValue = true;
       
   848 	  }
       
   849   }
       
   850 
       
   851   return returnValue;
       
   852 }
       
   853 /*
       
   854 This function checks whether the function name is specified with template class definition
       
   855 
       
   856 @internalComponent
       
   857 @released
       
   858 @param nstart - starting offset of the function name string 
       
   859 @param nend - end offset of the function name string
       
   860 @return true -  If function name is specified with template class functtion definition
       
   861 @return false - If function name is not specified with template class functtion definition
       
   862 
       
   863 Following patterns are handled in this function:
       
   864 -----------------------------------------------
       
   865 
       
   866 Pattern 1: 
       
   867 
       
   868   
       
   869 template <class T, class S, class L, class R>
       
   870 GLDEF_C void TestTDes<T,S,L,R>::Test1()
       
   871 {
       
   872 	T a(_TL("ABc"));
       
   873 }
       
   874 */
       
   875 
       
   876 bool TLeaveScanModel::CheckForTemplateFunc(const string& aFile,uint nstart,uint nend)
       
   877 {
       
   878 	bool returnValue = false;
       
   879 	uint OpennAnglebracket = aFile.find_first_of("<", nstart); // advance start
       
   880 	if(nend == OpennAnglebracket ) // The first invalid char name is <
       
   881 	{
       
   882 		uint OpennParen = aFile.find_first_of("(", nstart); // advance start
       
   883 		uint CloseAnglebracket = SmartFind(aFile, ">::", nstart );
       
   884 		if( (CloseAnglebracket < OpennParen) && (CloseAnglebracket > OpennAnglebracket))
       
   885 		{
       
   886 			returnValue = true;
       
   887 		}
       
   888 	}
       
   889 	return returnValue;
       
   890 }
       
   891 
       
   892 // Seek out mathod functions and return their name and start/end bounds in the
       
   893 // string file.
       
   894 //
       
   895 enum TReturnTypes TLeaveScanModel::GetFunc(const string& aFile, string &aName, uint &start, uint &end)
       
   896 {
       
   897   uint nstart = 0;//, cstart = 0;
       
   898   uint initStart = start;
       
   899   int realnstart = string::npos;
       
   900   uint safety = 1000000;
       
   901   string validNameChars = ":~abcdefghilkjmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_1234567890";
       
   902   uint prevstart = string::npos;
       
   903   FOREVER// do // forever 
       
   904     {
       
   905 	if(
       
   906 		(start == string::npos) ||
       
   907 		(prevstart == start && prevstart != string::npos)
       
   908 	 )
       
   909 	{
       
   910 		return E_False;
       
   911 	}
       
   912 	prevstart = start;
       
   913 
       
   914       if (safety-- == 0)
       
   915 	{
       
   916 	  cout << "ERROR: GetFunc context failure in " << iFileName << "\n";
       
   917 	  exit(6);
       
   918 	}
       
   919 
       
   920 	// move start along to 'real' double-colon
       
   921 	uint startColon = SmartFind(aFile, "::", start);
       
   922 	uint parenPostn = SmartFind(aFile, "(", start + 1);
       
   923      
       
   924 	if (startColon == string::npos || startColon >= aFile.length() )
       
   925 	{
       
   926 		// Function Definition do not have any :: and function body contains
       
   927   		nstart = start; 
       
   928 		// For 1st function, the value of start will be zero and for the
       
   929 		// second function onwards, it will start after the first function ends
       
   930 	}
       
   931 	else
       
   932 	{
       
   933 		uint Realstartpost  = GetRealStartPosition(aFile,parenPostn,0);
       
   934 		// If no real function name exists after double colon
       
   935 	//	if (Realstartpost == 0)
       
   936 	//		return E_False;
       
   937 		uint Realstartopnparen = SmartFind(aFile, "(", Realstartpost + 1); 
       
   938 
       
   939 		if(startColon < Realstartopnparen)
       
   940 		{
       
   941 			// If the double colon is used for function name then get function name which exists after ::
       
   942 			nstart = startColon;
       
   943 			//Get funcName before :: for "La :: La"
       
   944 			//step1 ':: L...'
       
   945 			uint fileLen = aFile.length();
       
   946 			int tmpnstart=nstart+2;
       
   947 			bool step1 = false;
       
   948 			while (tmpnstart<fileLen)
       
   949 			{
       
   950 				char curChar = aFile[tmpnstart];
       
   951 				if (curChar==' ' || curChar =='\n' || curChar=='\r' ||curChar=='\t')
       
   952 				{
       
   953 					tmpnstart++;
       
   954 				}
       
   955 				else if(curChar=='L')
       
   956 				{
       
   957 					step1=true;
       
   958 					break;
       
   959 				}
       
   960 				else
       
   961 				{
       
   962 					step1 = false;
       
   963 					break;
       
   964 				}
       
   965 			}
       
   966 			if(step1)
       
   967 			{
       
   968 				//step2 L...(<>)? :: L... -->skip all the blank
       
   969 				bool step2 = true;
       
   970 				tmpnstart = nstart-1;
       
   971 				while (tmpnstart>=0)
       
   972 				{
       
   973 					char curChar = aFile[tmpnstart];
       
   974 					if (curChar==' ' || curChar =='\n' || curChar=='\r' ||curChar=='\t')
       
   975 					{
       
   976 						tmpnstart--;
       
   977 					}
       
   978 					else
       
   979 					{
       
   980 						break;
       
   981 					}
       
   982 				}
       
   983 				if(tmpnstart<=0)
       
   984 				{
       
   985 					tmpnstart = 0;
       
   986 					step2 = false;
       
   987 				}
       
   988 				else
       
   989 				{
       
   990 					char curChar = aFile[tmpnstart];
       
   991 					if (curChar=='>')
       
   992 					{
       
   993 						tmpnstart = GetLeftTmpltParentBack(aFile,tmpnstart-1);
       
   994 						if(tmpnstart==string::npos)
       
   995 						{
       
   996 							//bad pattern
       
   997 							step2 =false;
       
   998 						}
       
   999 						else
       
  1000 						{
       
  1001 							tmpnstart --;
       
  1002 						}
       
  1003 					}
       
  1004 					if(tmpnstart==string::npos)
       
  1005 					{
       
  1006 						//bad pattern
       
  1007 						step2 =false;
       
  1008 					}
       
  1009 					else
       
  1010 					{
       
  1011 						
       
  1012 						while (tmpnstart>=0)
       
  1013 						{
       
  1014 							curChar = aFile[tmpnstart];
       
  1015 							if (curChar==' ' || curChar =='\n' || curChar=='\r' ||curChar=='\t')
       
  1016 							{
       
  1017 								tmpnstart--;
       
  1018 							}
       
  1019 							else
       
  1020 							{
       
  1021 								break;
       
  1022 							}
       
  1023 						}
       
  1024 						if(tmpnstart <=0) 
       
  1025 						{
       
  1026 							tmpnstart=0;
       
  1027 							step2=false;
       
  1028 						}
       
  1029 						while (tmpnstart>=0)
       
  1030 						{
       
  1031 							curChar = aFile[tmpnstart];
       
  1032 							if (curChar=='_' || (curChar>='a' && curChar<='z') || (curChar>='A' && curChar<='Z') ||(curChar>='0' && curChar<='9'))
       
  1033 							{
       
  1034 								tmpnstart--;
       
  1035 							}
       
  1036 							else
       
  1037 							{
       
  1038 								break;
       
  1039 							}
       
  1040 						}
       
  1041 						tmpnstart++;
       
  1042 						if (tmpnstart<0)
       
  1043 						{
       
  1044 							tmpnstart=0;
       
  1045 							step2=false;
       
  1046 						}
       
  1047 						if ( step2 && aFile[tmpnstart]=='L')
       
  1048 						{
       
  1049 							realnstart = tmpnstart;
       
  1050 						}
       
  1051 					}
       
  1052 
       
  1053 				}
       
  1054 			}
       
  1055 		}
       
  1056 		else
       
  1057 		{
       
  1058 			// start looking for function name after '('
       
  1059 			nstart = aFile.find_last_of(validNameChars,parenPostn-1);
       
  1060 			if(nstart == string::npos)
       
  1061 				return E_False;
       
  1062 		}
       
  1063 	}
       
  1064     
       
  1065 	uint semiPos = SmartFind(aFile, ";", nstart + 1); 
       
  1066 
       
  1067 	if (semiPos == string::npos || semiPos >= aFile.length())
       
  1068 		return E_False;
       
  1069 
       
  1070 	uint parenPos = SmartFind(aFile, "(", nstart + 1);
       
  1071     if (parenPos == string::npos || parenPos >= aFile.length()) 
       
  1072 		return E_False;
       
  1073 
       
  1074 	start = SmartFind(aFile, "{", nstart + 1); // advance start
       
  1075 	if (start == string::npos || start >= aFile.length())
       
  1076 		return E_False;
       
  1077 
       
  1078 	uint nstart2 = SmartFind(aFile, "::", nstart + 1); // next fn
       
  1079 	// Either (1) Second instance of Double collon is not there and first occurrence of double colon is valid
       
  1080 	// or (2) second occurrence of double colon is inside the function and first occurrence of double colon is valid
       
  1081 	
       
  1082 	if((nstart2 == string::npos && startColon < parenPos && startColon < start)  || ( nstart2 > start && startColon < parenPos && startColon < start ))
       
  1083 	{
       
  1084 		// This variable will store the first paranthesis position in a temporary variable
       
  1085 		// uint TempparenPos = parenPos;
       
  1086 		uint Realstartpost  = GetRealStartPosition(aFile,parenPos,1 /*To indicate that a valid double colon exists*/);
       
  1087 	
       
  1088 		nstart = Realstartpost+1; // reset
       
  1089 		
       
  1090 		break;
       
  1091 	}
       
  1092 	// Either Second occurrence of Double-colon is invalid  
       
  1093 	// or Second occurrence of Double-colon exists inside the function 
       
  1094 	// while first occurrence of double colon is valid
       
  1095 	else if (nstart2 == string::npos || nstart2 >= aFile.length() || (nstart2 != string::npos && nstart2 > start && startColon < parenPos && startColon < start))
       
  1096 	{
       
  1097 		// The opening parenthesis which comes fist after opening brace while moving
       
  1098  		// in backward direction is a valid candidate for function name.
       
  1099 		
       
  1100 		// This variable will store the first paranthesis position
       
  1101 		uint tempParenPos = aFile.find_last_of('(',start);
       
  1102 		
       
  1103 		
       
  1104 		//void foo() throw () {;}
       
  1105 		if(tempParenPos != string::npos)
       
  1106 		{
       
  1107  			uint throwPos = aFile.find("throw",initStart);
       
  1108 			if(throwPos!=string::npos && throwPos>=initStart && throwPos<start)
       
  1109 			{
       
  1110 					tempParenPos = aFile.find_last_of('(',throwPos);
       
  1111 					if(tempParenPos==string::npos || tempParenPos<initStart)
       
  1112 					{
       
  1113 						tempParenPos = aFile.find_last_of('(',throwPos);
       
  1114 					}
       
  1115 			}
       
  1116 		}
       
  1117 
       
  1118 		if (tempParenPos == string::npos)
       
  1119 		{
       
  1120 			//FIX this pattern
       
  1121 			//class A{};
       
  1122 			//void foo(){fooL();}
       
  1123 			if(start!=string::npos && semiPos!=string::npos && parenPos!=string::npos&&start<semiPos&&semiPos<parenPos)
       
  1124 			{
       
  1125 				start=semiPos+1;
       
  1126 				return E_Continue;
       
  1127 			}
       
  1128 			//FIX this pattern
       
  1129 			//class B;
       
  1130 			//class B{};
       
  1131 			//void foo(){fooL();}
       
  1132 			else if(start!=string::npos && semiPos!=string::npos && parenPos!=string::npos&&start<parenPos&&semiPos<start)
       
  1133 			{
       
  1134 				int tmpRightBracket = GetRightBracket(aFile,start+1);
       
  1135 				int tmpNextLeftBracket = GetLeftBracket(aFile,tmpRightBracket);
       
  1136 				int tmpSemiPos = aFile.find(";",tmpRightBracket);
       
  1137 				if(tmpRightBracket!=string::npos&&tmpNextLeftBracket!=string::npos&&tmpSemiPos!=string::npos)
       
  1138 				{
       
  1139 					if(tmpRightBracket<tmpSemiPos && tmpSemiPos<tmpNextLeftBracket)
       
  1140 					{
       
  1141 						//skip the content before B{};
       
  1142 						start = tmpSemiPos;
       
  1143 						return E_Continue;
       
  1144 					}
       
  1145 				}
       
  1146 			}
       
  1147 			//pattern:
       
  1148 			//class temp
       
  1149 			//{
       
  1150 			//LData func();
       
  1151 			//};
       
  1152 			//LData func() 
       
  1153 			//{
       
  1154 			//	foo();
       
  1155 			//}
       
  1156 			if(start!=string::npos && semiPos!=string::npos && parenPos!=string::npos&&start<semiPos&&semiPos>parenPos)
       
  1157 			{
       
  1158 				int tmpRightBracket = GetRightBracket(aFile,semiPos);
       
  1159 				if(tmpRightBracket!=string::npos)
       
  1160 				{
       
  1161 					start = tmpRightBracket;
       
  1162 					return E_Continue;
       
  1163 				}
       
  1164 			}
       
  1165 			
       
  1166 			// No '(' found yet
       
  1167 			return E_False;
       
  1168 		}
       
  1169 		
       
  1170 
       
  1171 		string whiteSpaceChars = " \t\n\r*&";
       
  1172 
       
  1173 		// ignore all tab and spaces and pointer between function name and opening parenthesis
       
  1174 		uint nend = aFile.find_last_not_of(whiteSpaceChars, --tempParenPos);
       
  1175 		uint currPos = aFile.find_last_of(whiteSpaceChars, nend);
       
  1176 	
       
  1177 		uint startOfBlock = SmartFind(aFile, "{", tempParenPos ); // advance start
       
  1178 
       
  1179 		if (startOfBlock == string::npos || startOfBlock >= aFile.length())
       
  1180  			return E_False;
       
  1181 
       
  1182 		if (start < tempParenPos || nstart2 < tempParenPos)
       
  1183 		{
       
  1184 			start = startOfBlock;
       
  1185 		}
       
  1186 
       
  1187 	 	if ((currPos != string::npos) && (currPos <  tempParenPos)) // fn1 before fn2
       
  1188 			nstart = currPos+1; // reset
       
  1189 	 	break;
       
  1190 	}
       
  1191 
       
  1192 	if (semiPos < start) // semi came before brace = prototype
       
  1193 		start = semiPos; 
       
  1194 	else
       
  1195 	if (nstart < nstart2 // fn1 before fn2
       
  1196 	    && nstart2 < parenPos) // fn2 before paren 
       
  1197 		start = nstart2; // reset
       
  1198 	else
       
  1199 		break;
       
  1200   } //while (true);
       
  1201   
       
  1202   // nstart should be left pointing to first of double colons
       
  1203   // start should point to curly brace
       
  1204 
       
  1205   assert(aFile[start] == '{');
       
  1206   
       
  1207   // locate the end of the method name
       
  1208   nstart = aFile.find_first_of(validNameChars,nstart);
       
  1209   if(nstart == string::npos)
       
  1210 	  return E_False;
       
  1211 
       
  1212   int nend = aFile.find_first_not_of(validNameChars, nstart);
       
  1213   if(true == CheckForTemplateFunc(aFile,nstart,nend))
       
  1214   {
       
  1215 	nend = aFile.find_first_of("(",nstart);
       
  1216   }
       
  1217   
       
  1218   if(realnstart!=string::npos && realnstart<nstart)
       
  1219   {
       
  1220 	aName = aFile.substr(realnstart, nend - realnstart);
       
  1221   }
       
  1222   else
       
  1223   {
       
  1224 	aName = aFile.substr(nstart, nend - nstart);
       
  1225   }
       
  1226   //operator
       
  1227   
       
  1228   if(aName.find("operator")!=string::npos)
       
  1229   {
       
  1230 	  nend = aFile.find_first_of("(",nstart);
       
  1231 	  while(nend>=0)
       
  1232 	  {
       
  1233 		  char tmpChar = aFile[nend];
       
  1234 		  if(tmpChar == ' ' || tmpChar == '\n' ||tmpChar == '\t' ||tmpChar == 'r')
       
  1235 		  {
       
  1236 			  nend--;
       
  1237 		  }
       
  1238 		  else
       
  1239 		  {
       
  1240 			  break;
       
  1241 		  }
       
  1242 	  }
       
  1243 	  aName = aFile.substr(nstart, nend - nstart);
       
  1244   }
       
  1245 int typeEnd = aFile.find_last_of(validNameChars,nstart-1);
       
  1246 int typeStart= aFile.find_last_of(" \t\n\r*&",typeEnd)+1;
       
  1247 string type=TrimString(aFile.substr(typeStart, typeEnd - typeStart+1));
       
  1248   uint closeparenposn = aFile.find_first_of(")", nstart); // advance start
       
  1249 
       
  1250   if(
       
  1251 	 (false == IsFunctionNameStringNotAMacro(aFile,start,closeparenposn,nstart)) ||
       
  1252 	 (false == IsSemiColonAndAssignmentOccurs(aFile,start,closeparenposn))
       
  1253 	)
       
  1254   {
       
  1255 	
       
  1256 	start = SmartFind(aFile, "}", start); 
       
  1257 	return E_Continue;
       
  1258   }
       
  1259   
       
  1260   // rewind nstart until non valid char found
       
  1261   safety = 1000000;
       
  1262   while (validNameChars.find_first_of(aFile[--nstart]) != string::npos)
       
  1263     {
       
  1264       if (safety-- == 0)
       
  1265 	{
       
  1266 	  cout << "ERROR: GetFunc context failure in " << iFileName << "\n";
       
  1267 	  exit(7);
       
  1268 	}
       
  1269     }
       
  1270   
       
  1271   nstart++;   // skip forward to acceptable character
       
  1272 
       
  1273   // cut name out
       
  1274   if(realnstart!=string::npos && realnstart<nstart)
       
  1275   {
       
  1276 	aName = aFile.substr(realnstart, nend - realnstart);
       
  1277   }
       
  1278   else
       
  1279   {
       
  1280 	aName = aFile.substr(nstart, nend - nstart);
       
  1281   }
       
  1282   
       
  1283   // truncate the name with zero
       
  1284 
       
  1285   if(realnstart!=string::npos && realnstart<nstart)
       
  1286   {
       
  1287 	  aName[nend-realnstart] = 0;
       
  1288   }
       
  1289   else
       
  1290   {
       
  1291 	  aName[nend-nstart] = 0;
       
  1292   }
       
  1293   aName = TrimString(aName);
       
  1294   uint NameSpaceinFunctionName = SmartFind(aName, "::",0);
       
  1295   // Continue processing when Either function name is in comment scope
       
  1296   // Or close curly corresponding to function name is followed by semicolon and pattern
       
  1297   // for scope resolution operator does not exists in function name
       
  1298   if(((true == IsInCommentScopeOrKeyword(aFile,aName,nstart,start))) || 
       
  1299 	  ( (string::npos == NameSpaceinFunctionName) &&  ((true == CheckValidFuncName(aFile,start))))) 
       
  1300   {
       
  1301 	  // Yes it is in comment scope
       
  1302 	  start = SmartFind(aFile, "}", start); 
       
  1303 	  return E_Continue;
       
  1304   }
       
  1305 
       
  1306   if (Verbose)
       
  1307     cout << "Processing method " << iFileName << ": " << aName << "()\n";
       
  1308   
       
  1309   end = start+1;  // start was a curly brace, so place end inside the brace
       
  1310   int braceCount = 1;   // count the one we've just stepped over & prime loop
       
  1311   //uint sanity = 0;
       
  1312   uint lpos = end;
       
  1313   uint match[E_Last];
       
  1314   uint braceDepth = 1;
       
  1315 
       
  1316   // keep progressing 'end' until braces match, end finishes up at brace+1
       
  1317   while (braceCount > 0)
       
  1318     {
       
  1319       if (Verbose > 1)
       
  1320 	cout << ".";
       
  1321 
       
  1322       // reset all types (in case we don't use all of them)
       
  1323       int counter;
       
  1324       for (counter = E_LCleanedUp; counter < E_Last; counter++)
       
  1325 	match[counter] = string::npos;
       
  1326 
       
  1327       match[E_OpenBrace]    = aFile.find("{",           lpos);
       
  1328       match[E_CloseBrace]   = aFile.find("}",           lpos);
       
  1329       match[E_BlockComment] = aFile.find("/*",          lpos);
       
  1330       match[E_LineComment]  = aFile.find("//",          lpos);
       
  1331       match[E_String]       = aFile.find("\"",          lpos);
       
  1332       match[E_Quote]        = aFile.find("\'",          lpos);
       
  1333 
       
  1334       // Check for at least one match-type
       
  1335       bool nothingFound = true;
       
  1336       for(counter = E_LCleanedUp; counter < E_Last; counter++)
       
  1337 	{
       
  1338 	  if(match[counter] != string::npos) // if found an item
       
  1339 	    nothingFound = false;
       
  1340 	}
       
  1341 
       
  1342       if(nothingFound) 
       
  1343 	{
       
  1344 	  if (Verbose > 1)
       
  1345 	    cout << "\n";
       
  1346 	  cout << "ERROR: " << iFileName << ":" << aName << " failed brace check.\n";
       
  1347 	  exit(1);
       
  1348 	}
       
  1349       
       
  1350       // Find the match-type which occurs first and set
       
  1351       // lps to its position
       
  1352       uint lowestMatchType = FindFirstMatchType(match);
       
  1353       lpos                 = match[lowestMatchType];
       
  1354       
       
  1355       switch(lowestMatchType)
       
  1356 	{
       
  1357 	case E_BlockComment:
       
  1358 	  MoveToEndOfComment(aFile, lpos, string::npos); // lpos modified
       
  1359 	  break;
       
  1360 
       
  1361 	case E_LineComment:
       
  1362 	  MoveToEndOfLine(aFile, lpos, string::npos); // lpos modified
       
  1363 	  break;
       
  1364 
       
  1365 	case E_OpenBrace:
       
  1366 	  braceCount++;
       
  1367 	  if (braceCount > (int)braceDepth)
       
  1368 	    braceDepth = braceCount;
       
  1369 	  lpos++;
       
  1370 	  break;
       
  1371 	  
       
  1372 	case E_CloseBrace:
       
  1373 	  braceCount--;
       
  1374 	  lpos++;
       
  1375 	  break;
       
  1376 
       
  1377 	case E_String:
       
  1378 	  // we're sat on a quote, so advance
       
  1379 	  lpos++;
       
  1380 	  //	  Peek(file,lpos);
       
  1381 	  lpos = SmartFindEndOfString(aFile, lpos, '\"');
       
  1382 	  if (lpos != string::npos)
       
  1383 	    lpos++; // skip closing quote
       
  1384 	  break;
       
  1385 	  
       
  1386 	case E_Quote:
       
  1387 	  lpos++;
       
  1388 	  lpos = SmartFindEndOfString(aFile, lpos, '\'');
       
  1389 	  if (lpos != string::npos)
       
  1390 	    lpos++; // skip closing quote
       
  1391 	  break;
       
  1392 
       
  1393 	default:
       
  1394 	  if (Verbose > 1)
       
  1395 	    cout << "\n";
       
  1396 	  cout << "ERROR: " << iFileName << ":" << aName << " bad match type.\n";
       
  1397 	  exit(1);
       
  1398 	} //endsw
       
  1399       
       
  1400       if (lpos == string::npos || lpos == 0 || lpos > aFile.length())
       
  1401 	{
       
  1402 	  if (Verbose > 1)
       
  1403 	    cout << "\n";
       
  1404 	  cout << "ERROR: " << iFileName << ":" << aName << " failed brace check (EOF).\n";
       
  1405 	  exit(1);
       
  1406 	}
       
  1407       
       
  1408     } //endwhile
       
  1409 
       
  1410   // advance 'end'
       
  1411   end = lpos;
       
  1412 
       
  1413   if (braceDepth > 10)
       
  1414     {
       
  1415       if (Verbose > 1)
       
  1416 	cout << "\n";
       
  1417       cout << "WARNING: " << iFileName << ":" << aName << " unexpectedly large brace depth.\n";
       
  1418     }
       
  1419   return E_True;
       
  1420 }
       
  1421 
       
  1422 // Diagnostic function for displaying the contents of a string
       
  1423 // starting at 'pos'
       
  1424 //
       
  1425 void TLeaveScanModel::Peek(const string aStr, uint aPos)
       
  1426 {
       
  1427 #define PEEKBUFFSIZE 20
       
  1428   static char peekBuf[PEEKBUFFSIZE];
       
  1429   int posn = aPos;
       
  1430   int remaining = aStr.length() - posn;
       
  1431   
       
  1432   if (remaining > (PEEKBUFFSIZE - 1))
       
  1433     remaining = PEEKBUFFSIZE;
       
  1434   
       
  1435   for (int i = 0; i < remaining; i++)
       
  1436     peekBuf[i] = aStr[i+posn];
       
  1437   
       
  1438   peekBuf[remaining] = 0;
       
  1439   
       
  1440   cout << "-------- Peek -----------\n" << peekBuf << "\n";
       
  1441   cout << "-------------------------\n";
       
  1442 #undef PEEKBUFFSIZE
       
  1443 }
       
  1444 
       
  1445 // Given an array of match types, work out which one actually comes first
       
  1446 // in the string. Effectively this function returns the match type with the
       
  1447 // lowest 'pos' value.
       
  1448 //
       
  1449 uint TLeaveScanModel::FindFirstMatchType(uint aMatchSet[])
       
  1450 {
       
  1451   // load indexOfLowestMatch with the item which comes first in the fn
       
  1452   int lowestMatch = 0;
       
  1453   for(int i = E_LCleanedUp; i < E_Last; i++) 
       
  1454     {
       
  1455       if((aMatchSet[lowestMatch] == string::npos) // if didn't find one
       
  1456 	 ||(aMatchSet[lowestMatch] > aMatchSet[i] && aMatchSet[i] != string::npos))
       
  1457 	lowestMatch = i;
       
  1458     }
       
  1459   //  cout << "Lowest match found: " << (int)lowestMatch << "\n";
       
  1460   return lowestMatch;
       
  1461 }
       
  1462 
       
  1463 //
       
  1464 // Given a string, see if it looks like a macro (e.g. is capitalised)
       
  1465 //
       
  1466 bool  TLeaveScanModel::IdentifyMacro(const string& str, const uint aPos)
       
  1467 {
       
  1468   string validNameChars = ":~abcdefghilkjmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_1234567890";
       
  1469   string LowerNameChars = "abcdefghilkjmnopqrstuvwxyz";
       
  1470 
       
  1471   // backwind until not valid
       
  1472   int start = str.find_last_not_of(validNameChars, aPos);
       
  1473 
       
  1474   // check for any lower case between start and pos
       
  1475   int lower = str.find_first_of(LowerNameChars, start);
       
  1476 
       
  1477   bool result = false;
       
  1478   if (lower < (int)aPos)
       
  1479     result = false; // lower case == not macro
       
  1480   else
       
  1481     result = true;
       
  1482   return result;
       
  1483 }
       
  1484 
       
  1485 // Given a method function bound, search thorough it looking for what appear to be
       
  1486 // leaving functions (unless it's a leaver itself).
       
  1487 //
       
  1488 // Returns false if error was detected signifying that caller should dump the 
       
  1489 // error string.
       
  1490 //
       
  1491 bool TLeaveScanModel::CheckFunc(const string& aFile, string &aName, 
       
  1492 				uint start, uint end, bool& aIsLeaver)
       
  1493 {
       
  1494   // entry criteria: name points to the container function name (after double-colon) which
       
  1495   // is now null-terminated.
       
  1496   // end is the bound for the end of the function (closing curly brace)
       
  1497   string extraTypes="CDX";
       
  1498   // Look for container name ending in L, or LC, LD, or LX
       
  1499   bool isLCFunc =false;
       
  1500   aName = TrimString(aName);
       
  1501   
       
  1502   string className="";
       
  1503     className = GetClassName( start);
       
  1504     if(className!="")
       
  1505     {
       
  1506     	  aName = className+"::"+aName;
       
  1507     }
       
  1508 	
       
  1509   if (Verbose > 1)
       
  1510     {
       
  1511       cout << "Evaluating code:\n";
       
  1512       Peek(aFile, start);
       
  1513     }
       
  1514 
       
  1515   if (aName[aName.length()-1] == 'L' || 
       
  1516       (aName[aName.length()-2] == 'L' && string::npos != extraTypes.find(aName[aName.length()-1]) ) )
       
  1517     //return true; // happy - we can exit since this container is marked as a leaver
       
  1518     aIsLeaver = true; // container is marked Leaver - used to return here
       
  1519   else if(IsLClassCtor(aName))
       
  1520   {
       
  1521 	  aIsLeaver = true;
       
  1522   }
       
  1523   
       
  1524   else
       
  1525     aIsLeaver = false; // container not marked Leaver
       
  1526   
       
  1527   if (aName[aName.length()-1] == 'C' && aName[aName.length()-2] == 'L' )
       
  1528   {
       
  1529 	 isLCFunc =true;
       
  1530   }
       
  1531   //CheckFuncDecl
       
  1532   //CheckFuncParam
       
  1533   int classNamePos = aFile.rfind(aName, start);
       
  1534   if(classNamePos == string::npos)
       
  1535   {
       
  1536 	  uint coloncolonPos =  aName.find("::");
       
  1537 	  if(coloncolonPos != string::npos)
       
  1538 	  {
       
  1539 		  string shortFuncName = aName.substr(coloncolonPos+2);
       
  1540 		  classNamePos = aFile.rfind(shortFuncName,start);
       
  1541 	  }
       
  1542   }
       
  1543   string funcParam = GetFunctionParam(aFile, classNamePos-1);
       
  1544   if(funcParam != "")
       
  1545   {
       
  1546   	if(funcParam.find("LString")!=string::npos||(funcParam.find("LData")!=string::npos))
       
  1547 	{
       
  1548   		if(!aIsLeaver)
       
  1549   		{
       
  1550   			cout<<GetErrorLineHead(aFile,classNamePos)<<aName + " uses LString/LData class as parameter"<<endl;	
       
  1551   		}
       
  1552 	}
       
  1553   }
       
  1554   //CheckFuncHead
       
  1555   string funcHead = GetFunctionHead(aFile, classNamePos-1);
       
  1556   if(funcHead != "")
       
  1557   {
       
  1558 	 if(funcHead.find("LString")!=string::npos||(funcHead.find("LData")!=string::npos))
       
  1559 	 {
       
  1560 	  	if(!aIsLeaver) 
       
  1561 	  	{
       
  1562 	  		cout<<GetErrorLineHead(aFile,classNamePos)<<aName + " returns LString/LData class"<<endl;	
       
  1563 	  	}
       
  1564 	 }
       
  1565   }
       
  1566   // remainder of function exists to deal with non-leaving container
       
  1567   bool ok      = true;
       
  1568   uint bodyLen = end - start;
       
  1569   iBody        = aFile.substr(start, bodyLen); // bound the string to end
       
  1570 
       
  1571   uint lpos = 0; 
       
  1572   uint match[E_Last]; // create some search-result slots
       
  1573   string extraTypesAndSpace=" CDX";
       
  1574 
       
  1575   bool keepProcessing = true; // keep going unless we run out of data or bail
       
  1576   uint sanity = 1000000;
       
  1577 
       
  1578   while (lpos < bodyLen && keepProcessing == true) 
       
  1579     {
       
  1580       if (sanity-- == 0)
       
  1581 	{
       
  1582 	  cout << "\nERROR: " << iFileName << ": " << aName << " context failure.\n";
       
  1583 	  exit(4);
       
  1584 	}
       
  1585       if (Verbose > 1)
       
  1586 	cout << "?";
       
  1587       // Scans for a whole set of items from position lpos.
       
  1588       // string::npos returned if not found
       
  1589 
       
  1590       // reset all types (in case we don't use all of them)
       
  1591       int counter;
       
  1592       for (counter = E_LCleanedUp; counter < E_Last; counter++)
       
  1593 	match[counter] = string::npos;
       
  1594 
       
  1595       match[E_Ell]          = iBody.find("L",           lpos); 
       
  1596       match[E_Trap]         = iBody.find("TRAP",        lpos); 
       
  1597       match[E_BlockComment] = iBody.find("/*",          lpos);
       
  1598       match[E_LineComment]  = iBody.find("//",          lpos);
       
  1599       match[E_Eleave]       = iBody.find("ELeave",      lpos);
       
  1600       match[E_UserEleave]   = iBody.find("User::Leave", lpos);
       
  1601       match[E_String]       = iBody.find("\"",          lpos);
       
  1602       match[E_Quote]        = iBody.find("\'",          lpos);
       
  1603       match[E_OrLeave]		= iBody.find("OR_LEAVE",	lpos);
       
  1604       match[E_LCleanedUp]	= iBody.find("LCleanedup",	lpos);
       
  1605       match[E_LString]		= iBody.find("LString",		lpos);
       
  1606       match[E_LManaged]		= iBody.find("LManaged",	lpos);
       
  1607       match[E_LData]		= iBody.find("LData",	    lpos);
       
  1608       
       
  1609       // Check for at least one match-type
       
  1610       bool doBreak = true;
       
  1611       for(counter = E_LCleanedUp; counter < E_Last; counter++)
       
  1612 	{
       
  1613 	  if(match[counter] != string::npos) // if found an item
       
  1614 	    doBreak = false; 
       
  1615 	}
       
  1616 
       
  1617       if(doBreak) 
       
  1618 	break; // found nothing of interest in this method function
       
  1619       
       
  1620       // Find the match-type which occurs first and set
       
  1621       // lps to its position
       
  1622       uint lowestMatchType = FindFirstMatchType(match);
       
  1623       lpos                 = match[lowestMatchType];
       
  1624       
       
  1625       switch(lowestMatchType) // what type was it?
       
  1626 	{
       
  1627 	case E_BlockComment:
       
  1628 	  MoveToEndOfComment(iBody, lpos, bodyLen); // lpos modified
       
  1629 	  break;
       
  1630 
       
  1631 	case E_LineComment:
       
  1632 	  MoveToEndOfLine(iBody, lpos, bodyLen); // lpos modified
       
  1633 	  break;
       
  1634 
       
  1635 	case E_Trap:
       
  1636 	  if (! MoveToEndOfTrapHarness(iBody, lpos, bodyLen)) // lpos modified
       
  1637 	    {
       
  1638               iErrorString     = aName + " structure Fault-Unclosed bracket after TRAP harness.";
       
  1639               iPositionOfError = lpos;
       
  1640 	      keepProcessing   = false; // bail
       
  1641 	    }
       
  1642 	  break;
       
  1643 
       
  1644 	case E_Eleave:
       
  1645 	  ok               = false;
       
  1646 	  iErrorString     = aName + " calls new(ELeave).";
       
  1647 	  iPositionOfError = match[E_Eleave];
       
  1648 	  keepProcessing   = false; // bail
       
  1649 	  break;
       
  1650 	case E_OrLeave:
       
  1651 		ok               = false;
       
  1652 		iErrorString     = aName + " calls OR_LEAVE.";
       
  1653 		iPositionOfError = match[E_OrLeave];
       
  1654 		keepProcessing   = false; // bail
       
  1655 		break;
       
  1656 	case E_LCleanedUp:
       
  1657 		ok               = false;
       
  1658 		iErrorString     = aName + " uses LCleanedup* class.";
       
  1659 		iPositionOfError = match[E_LCleanedUp];
       
  1660 		keepProcessing   = false; // bail
       
  1661 		break;
       
  1662 	case E_LString:
       
  1663 		ok               = false;
       
  1664 		iErrorString     = aName + " uses LString* class.";
       
  1665 		iPositionOfError = match[E_LString];
       
  1666 		keepProcessing   = false; // bail
       
  1667 		break;
       
  1668 	case E_LManaged:
       
  1669 		ok               = false;
       
  1670 		iErrorString     = aName + " uses LManaged* class.";
       
  1671 		iPositionOfError = match[E_LManaged];
       
  1672 		keepProcessing   = false; // bail
       
  1673 		break;
       
  1674 	
       
  1675 	case E_LData:
       
  1676 			ok               = false;
       
  1677 			iErrorString     = aName + " uses LData* class.";
       
  1678 			iPositionOfError = match[E_LData];
       
  1679 			keepProcessing   = false; // bail
       
  1680 			break;
       
  1681 			
       
  1682 	case E_UserEleave:
       
  1683 	  ok               = false;
       
  1684 	  iErrorString     = aName + " calls User::Leave() or User::LeaveIfError().";
       
  1685 	  iPositionOfError = match[E_UserEleave];
       
  1686 	  AppendCommentToErrorString(bodyLen);
       
  1687 	  keepProcessing   = false; // bail
       
  1688 	  break;
       
  1689 	  
       
  1690 	
       
  1691 	case E_Ell:
       
  1692 	  // Found an L, but is there an underbar before it, 
       
  1693 	  // AND (one of 'CDX ' AND a brace OR just a brace) _L[CDX ](
       
  1694 	  if ((iBody[lpos - 1] != '_') &&
       
  1695 	      (((string::npos != extraTypesAndSpace.find(iBody[lpos + 1])) 
       
  1696 		&& (iBody[lpos + 2] == '(')) || (iBody[lpos + 1] == '(')) ) 
       
  1697 	    {
       
  1698 	      if (IdentifyMacro(iBody, lpos))
       
  1699 		{
       
  1700 		  ok = false;
       
  1701 		  iErrorString = aName + " may employ a macro.";
       
  1702 		  iPositionOfError = match[E_Ell];
       
  1703 		  if(!AppendCommentToErrorString(bodyLen))
       
  1704 		    keepProcessing = false; // keep going if possible
       
  1705 		  lpos++;
       
  1706 		  break; // don't bail - false alarm
       
  1707 		}
       
  1708 	      else
       
  1709 		{
       
  1710 		  if (Verbose > 1)
       
  1711 		    {
       
  1712 		      cout << "Leaver found: \n";
       
  1713 		      Peek(iBody, lpos);
       
  1714 		    }
       
  1715 		}
       
  1716 	      ok = false;
       
  1717 	      iErrorString = aName + " calls a function that can leave.";
       
  1718 	      iPositionOfError = match[E_Ell];
       
  1719 	      if(!AppendCommentToErrorString(bodyLen))
       
  1720 		keepProcessing = false; // keep going if possible
       
  1721 	    }
       
  1722 	  lpos++; // move on over the L
       
  1723 	  break;
       
  1724 	  
       
  1725 	case E_String:
       
  1726 	  lpos++;
       
  1727 	  lpos = SmartFindEndOfString(iBody, lpos, '\"');
       
  1728 	  if (lpos == string::npos)
       
  1729 	    keepProcessing = false;
       
  1730 	  else
       
  1731 	    lpos++; // skip closing quote
       
  1732 	  break;
       
  1733 	  
       
  1734 	case E_Quote:
       
  1735 	  lpos++;
       
  1736 	  lpos = SmartFindEndOfString(iBody, lpos, '\'');
       
  1737 	  if (lpos == string::npos)
       
  1738 	    keepProcessing = false;
       
  1739 	  else
       
  1740 	    lpos++; // skip closing quote
       
  1741 	  break;
       
  1742 
       
  1743 	default:
       
  1744 	  cout << "\nERROR: " << iFileName << ": " << aName << " unexpected match type.\n";
       
  1745 	  exit(1);
       
  1746 
       
  1747 	} // endsw
       
  1748 	//LCleanedup and LManaged cann't be TRAPed
       
  1749 	/*
       
  1750 	if (match[E_LCleanedUp]==string::npos && match[E_LManaged]==string::npos)
       
  1751 	{
       
  1752 	}
       
  1753 	if(match[E_LCleanedUp]!=string::npos && match[E_LManaged]==string::npos)
       
  1754 	{
       
  1755 		ok               = false;
       
  1756 		iErrorString     = aName + " uses LCleanedup class.";
       
  1757 		iPositionOfError = match[E_LCleanedUp];
       
  1758 		keepProcessing   = false; // bail
       
  1759 		break;
       
  1760 	}
       
  1761 	else if(match[E_LManaged]!=string::npos && match[E_LCleanedUp]==string::npos)
       
  1762 	{
       
  1763 		ok               = false;
       
  1764 		iErrorString     = aName + " uses LManaged* class.";
       
  1765 		iPositionOfError = match[E_LManaged];
       
  1766 		keepProcessing   = false; // bail
       
  1767 		break;
       
  1768 	}
       
  1769 	else if(match[E_LCleanedUp]<match[E_LManaged])
       
  1770 	{
       
  1771 		ok               = false;
       
  1772 		iErrorString     = aName + " uses LCleanedup class.";
       
  1773 		iPositionOfError = match[E_LCleanedUp];
       
  1774 		keepProcessing   = false; // bail
       
  1775 		break;
       
  1776 	}
       
  1777 	else if(match[E_LCleanedUp]>match[E_LManaged])
       
  1778 	{
       
  1779 		ok               = false;
       
  1780 		iErrorString     = aName + " uses LManaged* class.";
       
  1781 		iPositionOfError = match[E_LManaged];
       
  1782 		keepProcessing   = false; // bail
       
  1783 		break;
       
  1784 	}
       
  1785 	*/
       
  1786     //check:An LCleanedup class is used in the same function body as the Classic cleanup stack API
       
  1787     if(match[E_LCleanedUp]!=string::npos)
       
  1788       {
       
  1789     	uint newLCPos = iBody.find("NewLC");
       
  1790 		uint pushLPos = string::npos; //Cleanedup::PushL()-->find Cleanedup
       
  1791 		uint bodyLen = iBody.length();
       
  1792 		for(uint tmpPos = 0;tmpPos<bodyLen;)
       
  1793 		{
       
  1794 			pushLPos = iBody.find("CleanupStack",tmpPos);
       
  1795 			if (pushLPos == string::npos)
       
  1796 			{
       
  1797 				break;
       
  1798 			}
       
  1799 			if(pushLPos>0)
       
  1800 			{
       
  1801 				if(iBody[pushLPos-1]=='L')
       
  1802 				{
       
  1803 					tmpPos++;
       
  1804 					pushLPos = string::npos;
       
  1805 					continue;
       
  1806 				}
       
  1807 				else
       
  1808 				{
       
  1809 					break;
       
  1810 				}
       
  1811 			}
       
  1812 			else
       
  1813 			{
       
  1814 				break;
       
  1815 			}
       
  1816 		}
       
  1817 		
       
  1818 		//uint new
       
  1819     	uint lcleanedUpPos = match[E_LCleanedUp];
       
  1820     	if(newLCPos!=string::npos && pushLPos!=string::npos)
       
  1821     	{
       
  1822     		if(newLCPos<pushLPos)
       
  1823     		{
       
  1824     			cout<<GetErrorLineHead(aFile,start+newLCPos)<<aName<<" uses NewLC method with LCleanedup* class.\n";
       
  1825     			break;
       
  1826     		}
       
  1827     		else
       
  1828     		{
       
  1829     			cout<<GetErrorLineHead(aFile,start+pushLPos)<<aName<<" uses classic CleanupStack method with LCleanedup* class.\n";
       
  1830     			break;
       
  1831     		}
       
  1832     	}
       
  1833     	else if(newLCPos!=string::npos)
       
  1834     	{
       
  1835     		cout<<GetErrorLineHead(aFile,start+newLCPos)<<aName<<" uses NewLC method with LCleanedup* class.\n";
       
  1836     		break;
       
  1837     	}
       
  1838     	else if(pushLPos!=string::npos)
       
  1839     	{
       
  1840     		cout<<GetErrorLineHead(aFile,start+pushLPos)<<aName<<" uses classic CleanupStack with LCleanedup* class.\n";
       
  1841     		break;
       
  1842     	}
       
  1843     	
       
  1844       }
       
  1845     } // endwhile
       
  1846   
       
  1847   if (Verbose > 1)
       
  1848     cout << "END\n";
       
  1849 
       
  1850   return ok;
       
  1851 }
       
  1852 
       
  1853 //
       
  1854 // Move an index forward to the start of a close-comment
       
  1855 //
       
  1856 void TLeaveScanModel::MoveToEndOfComment(const string& aStr, uint& aIndex, uint aLen)
       
  1857 {
       
  1858   uint endOfComment=aStr.find("*/",aIndex);
       
  1859   aIndex=(endOfComment == string::npos ? aLen : endOfComment+2);
       
  1860 }
       
  1861 
       
  1862 //
       
  1863 // Move an index forward to the EOL (\n)
       
  1864 //
       
  1865 void TLeaveScanModel::MoveToEndOfLine(const string& aStr, uint& aIndex, uint aLen)
       
  1866 {
       
  1867   uint endOfLine=aStr.find('\n',aIndex);
       
  1868   aIndex=(endOfLine==string::npos ? aLen : endOfLine);
       
  1869 }
       
  1870 
       
  1871 //
       
  1872 // Move an index forward to a closing quote (specified by x)
       
  1873 //
       
  1874 void TLeaveScanModel::MoveToEndOfString(const string& aStr, uint& aIndex, uint aLen, char aQuote)
       
  1875 {
       
  1876   uint endOfLine=aStr.find(aQuote,aIndex);
       
  1877   aIndex=(endOfLine==string::npos ? aLen : endOfLine);
       
  1878 }
       
  1879 
       
  1880 //
       
  1881 // Move to end of a trap harness
       
  1882 //
       
  1883 bool TLeaveScanModel::MoveToEndOfTrapHarness(const string& aStr, uint& aIndex, uint aLen)
       
  1884 {
       
  1885   uint bracketLevel=1;
       
  1886   uint closeBracket;
       
  1887   uint openBracket=aStr.find('(',aIndex);
       
  1888   bool cleanExit=true;
       
  1889   uint newIndex;
       
  1890   for(newIndex = openBracket; bracketLevel;)
       
  1891     {
       
  1892       closeBracket=aStr.find(')',newIndex+1);
       
  1893       openBracket=aStr.find('(',newIndex+1);
       
  1894       if (openBracket<closeBracket && openBracket!=string::npos)
       
  1895 	{
       
  1896 	  bracketLevel++;
       
  1897 	  newIndex=openBracket;
       
  1898 	}
       
  1899       else if ((closeBracket<openBracket && closeBracket!=string::npos) 
       
  1900 	       || (closeBracket!=string::npos && openBracket==string::npos)) 
       
  1901 	{
       
  1902 	  bracketLevel--;
       
  1903 	  newIndex=closeBracket;
       
  1904 	}
       
  1905       else //bad structure
       
  1906 	{
       
  1907 	  cleanExit=false;
       
  1908 	  break;
       
  1909 	}
       
  1910     }
       
  1911   aIndex=(cleanExit ? newIndex : aLen);
       
  1912   return cleanExit;
       
  1913 }
       
  1914 
       
  1915 //
       
  1916 // Report the current error - note works on class member iText
       
  1917 //
       
  1918 void TLeaveScanModel::ReportErrorLineAndString(uint aStart)
       
  1919 {
       
  1920   int positionInBody=aStart+iPositionOfError;
       
  1921   int positionOfNextLine=iText.find('\n',positionInBody+1);
       
  1922   if(positionOfNextLine==string::npos)
       
  1923   positionOfNextLine=iText.length()-1; //the first char could be '\n'
       
  1924   int positionOfLine=-1;
       
  1925   int lineNum;
       
  1926   for(lineNum=0 ;positionOfLine<positionOfNextLine;lineNum++)
       
  1927     positionOfLine=iText.find('\n',positionOfLine+1);
       
  1928  
       
  1929   cout << iFileName <<"("<< lineNum << ") : " << iErrorString << "\n";
       
  1930 }
       
  1931 
       
  1932 //calculate filename ,fileline
       
  1933 string TLeaveScanModel::GetErrorLineHead(const string& aText, uint aPos)
       
  1934 {
       
  1935 	int lineNum=1;
       
  1936 	char curChar=0;
       
  1937 	//i did not count '\r'
       
  1938 	for(int curPos=0;curPos<=aPos;curPos++)
       
  1939 	{
       
  1940 		curChar = aText[curPos];
       
  1941 		if(curChar=='\n')
       
  1942 		{
       
  1943 			lineNum++;
       
  1944 		}
       
  1945 	}
       
  1946 	stringstream   sstrm;
       
  1947 	sstrm<<iFileName << string("(")<<lineNum<<string(") : ");
       
  1948 	return sstrm.str();
       
  1949 }
       
  1950 //Get a class name from class list
       
  1951 //may return wrong name if there are inner classes
       
  1952 string TLeaveScanModel::GetClassName(uint aStart)
       
  1953 {
       
  1954 	list<ClassMeta>::iterator iter; 
       
  1955 	for(iter=iClassList.begin();iter!=iClassList.end();iter++) 
       
  1956 	{ 
       
  1957 		if(iter->startPos<=aStart && iter->endPos >= aStart)
       
  1958 		{
       
  1959 			return iter->className;
       
  1960 		}
       
  1961 	}
       
  1962 	return "";
       
  1963 }
       
  1964 //
       
  1965 // Add to the current error string - note works on class member iBody
       
  1966 //
       
  1967 bool TLeaveScanModel::AppendCommentToErrorString(uint aEnd)
       
  1968 {
       
  1969   bool qualified = true;
       
  1970   uint commentPosition   = iBody.find("//",iPositionOfError+1);
       
  1971   uint endOfLinePosition = iBody.find('\n',iPositionOfError+1);
       
  1972   if((commentPosition < endOfLinePosition) && (commentPosition != string::npos))
       
  1973     iErrorString+=" QUALIFIED WITH-> "+iBody.substr(commentPosition,endOfLinePosition-commentPosition);
       
  1974   else if(endOfLinePosition==string::npos && commentPosition!=string::npos)
       
  1975     iErrorString+=" QUALIFIED WITH-> "+iBody.substr(commentPosition,aEnd-commentPosition);
       
  1976   else //no comment
       
  1977     {
       
  1978       iErrorString+=" UnQualified.";
       
  1979       qualified = false;
       
  1980     }
       
  1981   return qualified;
       
  1982 }
       
  1983 
       
  1984 //
       
  1985 // Find the end of a string, but cope with escaped quotes
       
  1986 //
       
  1987 uint TLeaveScanModel::SmartFindEndOfString(const string& aStr, uint aPos, char aQuote)
       
  1988 {
       
  1989   FOREVER//while(true)
       
  1990     {
       
  1991        MoveToEndOfString(aStr, aPos, string::npos, aQuote);
       
  1992       if (aPos == string::npos) // end of fn
       
  1993 	  return aPos;
       
  1994 
       
  1995       if (aStr[aPos - 1] != '\\')
       
  1996 	return aPos;
       
  1997 
       
  1998       // looks like we have an escaped quote
       
  1999       if (aStr[aPos - 2] == '\\')
       
  2000 	{ // escape was itself quoted, so string end is real
       
  2001 	  return aPos;	
       
  2002 	}
       
  2003       else
       
  2004 	{ // quote is escaped - carry on
       
  2005 	  if (Verbose > 1)
       
  2006 	    cout << "\n";
       
  2007 	  cout << "WARNING: " << iFileName << ": detected quoted string.\n";
       
  2008 	  aPos++;
       
  2009 	  continue;
       
  2010 	}
       
  2011     } //while
       
  2012 }
       
  2013 
       
  2014 //
       
  2015 // Find a target string from a given start position, but ignore targets buried
       
  2016 // within comments, or strings.
       
  2017 //
       
  2018 uint  TLeaveScanModel::SmartFind(const string& aStr, const string& aTarget, uint aStart)
       
  2019 {
       
  2020   uint found,cstart;
       
  2021   FOREVER//while(1)
       
  2022     {
       
  2023       //      cout << "Searching for target from: " << aStart << "\n";
       
  2024       // record found target 
       
  2025       found = aStr.find(aTarget, aStart);
       
  2026       if (found == string::npos)
       
  2027 	  return(string::npos);
       
  2028 
       
  2029       // cout << "Target candidate found at: " << found << "\n";
       
  2030       // look for earlier comment
       
  2031       cstart = aStr.find("//", aStart);
       
  2032 
       
  2033       if (cstart < found) // earlier
       
  2034 	{
       
  2035 	  aStart = cstart; // reset start to after comment
       
  2036 	  // cout << "Earlier comment found at: " << start << "\n";
       
  2037 	  MoveToEndOfLine(aStr, aStart, string::npos);
       
  2038 	  // cout << "Start advanced to: " << aStart << "\n";
       
  2039 	  if (aStart == string::npos)
       
  2040 	    return(aStart);
       
  2041 	  else
       
  2042 	    continue; // start search again
       
  2043 	}
       
  2044       
       
  2045       // do the same for block comments
       
  2046       cstart = aStr.find("/*", aStart);
       
  2047       if (cstart < found)
       
  2048 	{
       
  2049 	  aStart = cstart;
       
  2050 	  // cout << "Earlier block found at: " << aStart << "\n";
       
  2051 	  MoveToEndOfComment(aStr, aStart, string::npos);
       
  2052 	  // cout << "Start advanced to: " << aStart << "\n";
       
  2053 	  if (aStart == string::npos)
       
  2054 	    return(aStart);
       
  2055 	  else
       
  2056 	    continue;
       
  2057 	}
       
  2058       
       
  2059       cstart = aStr.find("\"", aStart);
       
  2060 
       
  2061       if (cstart < found)
       
  2062 	{
       
  2063 	  aStart = cstart + 1;
       
  2064 	  MoveToEndOfString(aStr, aStart, string::npos, '\"');
       
  2065 	  if (aStart == string::npos)
       
  2066 	    return(aStart);
       
  2067 	  else
       
  2068 	    {
       
  2069 	      aStart++;
       
  2070 	      continue;
       
  2071 	    }
       
  2072 	}
       
  2073 
       
  2074       cstart = aStr.find("\'", aStart);
       
  2075       if (cstart < found)
       
  2076 	{
       
  2077 	  aStart = cstart + 1;
       
  2078 	  MoveToEndOfString(aStr, aStart, string::npos, '\'');
       
  2079 	  if (aStart == string::npos)
       
  2080 	    return(aStart);
       
  2081 	  else
       
  2082 	    {
       
  2083 	      aStart++;
       
  2084 	      continue;
       
  2085 	    }
       
  2086 	}
       
  2087       return(found); // quit loop
       
  2088     } // endwhile
       
  2089 }
       
  2090 
       
  2091 
       
  2092 /*
       
  2093  * Decide the "class" is keyword
       
  2094  * e.g
       
  2095  *  class -> true
       
  2096  *  Aclass ->false
       
  2097  *  classA ->false
       
  2098  */
       
  2099 bool TLeaveScanModel::IsClassKeyword(const string& aText, uint aBegin, uint aEnd)
       
  2100 {
       
  2101 	bool tmpBefore =false;
       
  2102 	bool tmpAfter =false;
       
  2103 	int len = aText.size();
       
  2104 	if(aBegin==0)
       
  2105 	{
       
  2106 		tmpBefore = true;
       
  2107 	}
       
  2108 	else
       
  2109 	{
       
  2110 		char tmpChar = aText[aBegin-1];
       
  2111 		if(tmpChar==' ' || tmpChar=='\n' || tmpChar=='\r' || tmpChar=='\t' || tmpChar=='{'|| tmpChar=='}'|| tmpChar==';')
       
  2112 		{
       
  2113 			tmpBefore = true;
       
  2114 		}
       
  2115 	}
       
  2116 	if(aEnd==len-1)
       
  2117 	{
       
  2118 		tmpAfter = true;
       
  2119 	}
       
  2120 	else
       
  2121 	{
       
  2122 		char tmpChar = aText[aEnd+1];
       
  2123 		if(tmpChar==' ' || tmpChar=='\n' || tmpChar=='\r' || tmpChar=='{' || tmpChar=='('|| tmpChar==':')
       
  2124 		{
       
  2125 			tmpAfter = true;
       
  2126 		}
       
  2127 	}
       
  2128 	return tmpAfter&&tmpBefore;
       
  2129 }
       
  2130 /**
       
  2131  * combine escaped lines to one line.
       
  2132  */
       
  2133 string TLeaveScanModel::CombineLine(const string& aText)
       
  2134 {
       
  2135 
       
  2136 	if(aText.size()<0) return string("");
       
  2137 	int curPos = 0;
       
  2138 	int curState = PPSTATE_NORMAL;
       
  2139 	int firstPos = 0;
       
  2140 	int stringSize = aText.size();
       
  2141 	int newlineCount=0;
       
  2142 	string newText("");
       
  2143 	while(curPos< stringSize)
       
  2144 	{
       
  2145 		//remove "\"
       
  2146 		switch(curState)
       
  2147 		{
       
  2148 		case PPSTATE_NORMAL:
       
  2149 		{
       
  2150 			char curChar=aText[curPos];
       
  2151 			if(curChar=='\\')
       
  2152 			{
       
  2153 				// '\\\n" | "\\\r"
       
  2154 				if(stringSize>(curPos+1)&&IsNewLine(aText[curPos+1]))
       
  2155 				{
       
  2156 					curState= PPSTATE_ESCAPED_LINE;				
       
  2157 					newText.append(aText.substr(firstPos,curPos-firstPos));
       
  2158 					curPos+=1;
       
  2159 					newlineCount+=1;
       
  2160 					
       
  2161 				}
       
  2162 				else if(IsLastChar(curPos,stringSize))
       
  2163 				{
       
  2164 					curPos++;
       
  2165 					firstPos++;
       
  2166 				}
       
  2167 				else
       
  2168 				{
       
  2169 					curPos++;
       
  2170 				}
       
  2171 			}
       
  2172 			else if(IsNewLine(curChar))
       
  2173 			{
       
  2174 				if (newlineCount>0)
       
  2175 				{
       
  2176 					newText.append(aText.substr(firstPos,curPos-firstPos));
       
  2177 					while(newlineCount>= 0)
       
  2178 					{
       
  2179 						newText.append("\n");
       
  2180 						newlineCount--;
       
  2181 					}
       
  2182 					newlineCount=0;
       
  2183 					curPos++;
       
  2184 					firstPos=curPos;
       
  2185 				}
       
  2186 				else
       
  2187 				{
       
  2188 					curPos++;
       
  2189 				}
       
  2190 			}
       
  2191 			else
       
  2192 			{
       
  2193 				curPos++;
       
  2194 			}
       
  2195 		}
       
  2196 			break;
       
  2197 		case PPSTATE_ESCAPED_LINE:
       
  2198 			if(stringSize-curPos>1)
       
  2199 			{
       
  2200 				if(
       
  2201 					(aText[curPos]=='\n'&&aText[curPos+1]=='\r')
       
  2202 					||
       
  2203 					(aText[curPos]=='\r'&&aText[curPos+1]=='\n')
       
  2204 					)
       
  2205 				{
       
  2206 					curPos+=2;
       
  2207 					firstPos=curPos;
       
  2208 					curState=PPSTATE_NORMAL;
       
  2209 				}
       
  2210 				else if(IsNewLine(aText[curPos]))
       
  2211 				{
       
  2212 					curPos+=1;
       
  2213 					firstPos=curPos;
       
  2214 					curState=PPSTATE_NORMAL;
       
  2215 				}
       
  2216 			}
       
  2217 			else
       
  2218 			{
       
  2219 				//EOF
       
  2220 				return newText;
       
  2221 			}
       
  2222 		
       
  2223 		}
       
  2224 	}
       
  2225 	newText.append(aText.substr(firstPos,curPos-firstPos));
       
  2226 	return newText;
       
  2227 }
       
  2228 
       
  2229 /**
       
  2230  * C Preprocess
       
  2231  * a.remove single line comment
       
  2232  * b.remove mul-lines comment
       
  2233  * c.remove #command
       
  2234  * d.struct,NONSHARABLE_CLASS,NONSHARABLE_STRUCT --> class
       
  2235  * e.string literal -> blank string
       
  2236  */
       
  2237 string TLeaveScanModel::PreProcess(const string& aText)
       
  2238 {
       
  2239 	string afterCombine = CombineLine(aText);
       
  2240 	//cout<<"before:"<<endl<<afterCombine<<endl;
       
  2241 	if(afterCombine.size()<0) return string("");
       
  2242 	
       
  2243 	int curPos = 0;
       
  2244 	int curState = PPSTATE_NORMAL;
       
  2245 	int firstPos = 0;
       
  2246 	int stringSize = aText.size();
       
  2247 	int newlineCount=0;
       
  2248 	int blankCount=2;
       
  2249 	string newText("");
       
  2250 	while(curPos< stringSize)
       
  2251 	{
       
  2252 		switch(curState)
       
  2253 		{
       
  2254 			case PPSTATE_NORMAL:
       
  2255             {
       
  2256 				char curChar = afterCombine[curPos];
       
  2257 				if(curChar=='/')
       
  2258 				{
       
  2259 					if(HasEnoughChar(curPos,stringSize,1))
       
  2260 					{
       
  2261 						if('/'==afterCombine[curPos+1])
       
  2262 						{
       
  2263 							curState=PPSTATE_SINGLE_COMMENT;
       
  2264 							newText.append(afterCombine.substr(firstPos,curPos-firstPos));
       
  2265 							curPos+=2;
       
  2266 						}
       
  2267 						else if('*'==afterCombine[curPos+1])
       
  2268 						{
       
  2269 							curState=PPSTATE_MUL_COMMENT;
       
  2270 							newText.append(afterCombine.substr(firstPos,curPos-firstPos));
       
  2271 							curPos+=2;
       
  2272 						}
       
  2273 						else
       
  2274 						{
       
  2275 							curPos++;
       
  2276 						}
       
  2277 					}
       
  2278 					else
       
  2279 					{
       
  2280 						curPos++;
       
  2281 					}
       
  2282 				}
       
  2283 				else if(curChar=='"')
       
  2284 				{
       
  2285 					if(curPos>0&&(afterCombine[curPos-1]!='\\'&&afterCombine[curPos-1]!='\''))
       
  2286 					{
       
  2287 						curState=PPSTATE_STRING_LITERAL;
       
  2288 						newText.append(afterCombine.substr(firstPos,curPos-firstPos+1));
       
  2289 						
       
  2290 					}
       
  2291 					curPos+=1;
       
  2292 				}
       
  2293 				else if(curChar=='#')
       
  2294 				{
       
  2295 					//if # is the first non-blank char of line, comment this line
       
  2296 					bool checkSharp=true;
       
  2297 					for(int i=curPos-1;i>=0;i--)
       
  2298 					{
       
  2299 						char tmpChar = afterCombine[i];
       
  2300 						if(tmpChar==' '||tmpChar=='\t'||tmpChar=='\f')
       
  2301 						{
       
  2302 							continue;
       
  2303 						}
       
  2304 						else if(tmpChar=='\n' || tmpChar=='\t')
       
  2305 						{
       
  2306 							break;
       
  2307 						
       
  2308 						}
       
  2309 						else
       
  2310 						{
       
  2311 							checkSharp=false;
       
  2312 							break;
       
  2313 						}
       
  2314 					}
       
  2315 					if(checkSharp)
       
  2316 					{
       
  2317 						curState=PPSTATE_SHARP_COMMENT;
       
  2318 						newText.append(afterCombine.substr(firstPos,curPos-firstPos));
       
  2319 					}
       
  2320 					curPos+=1;
       
  2321 				}
       
  2322 				//struct,NONSHARABLE_CLASS,NONSHARABLE_STRUCT --> class
       
  2323 				else if(HasEnoughChar(curPos,stringSize,5))
       
  2324 				{
       
  2325 					
       
  2326 					if(curChar=='s'&&afterCombine[curPos+1]=='t'&&afterCombine[curPos+2]=='r'&&afterCombine[curPos+3]=='u'&&afterCombine[curPos+4]=='c'&&afterCombine[curPos+5]=='t'&&IsClassKeyword(aText,curPos,curPos+5))
       
  2327 					{
       
  2328 						newText.append(afterCombine.substr(firstPos,curPos-firstPos));
       
  2329 						newText.append("class ");
       
  2330 						curPos+=6;
       
  2331 						firstPos=curPos;
       
  2332 					}
       
  2333 					else if(curChar=='N'&&HasEnoughChar(curPos,stringSize,11)&&afterCombine[curPos+1]=='O'&&afterCombine[curPos+2]=='N'&&afterCombine[curPos+3]=='S'&&afterCombine[curPos+4]=='H'&&afterCombine[curPos+5]=='A'&&afterCombine[curPos+6]=='R'&&afterCombine[curPos+7]=='A'&&afterCombine[curPos+8]=='B'&&afterCombine[curPos+9]=='L'&&afterCombine[curPos+10]=='E'&&afterCombine[curPos+11]=='_')
       
  2334 					{
       
  2335 						if(HasEnoughChar(curPos,stringSize,5))
       
  2336 						{
       
  2337 							if(afterCombine[curPos+12]=='C'&&afterCombine[curPos+13]=='L'&&afterCombine[curPos+14]=='A'&&afterCombine[curPos+15]=='S'&&afterCombine[curPos+16]=='S'&&IsClassKeyword(aText,curPos,curPos+16))
       
  2338 							{
       
  2339 								newText.append(afterCombine.substr(firstPos,curPos-firstPos));
       
  2340 								newText.append("class");
       
  2341 								for(int i=0;i<12;i++)
       
  2342 								{
       
  2343 									newText.append(" ");
       
  2344 								}
       
  2345 								curPos+=17;
       
  2346 								firstPos=curPos;
       
  2347 								break;
       
  2348 							}
       
  2349 						}
       
  2350 						if(HasEnoughChar(curPos,stringSize,6))
       
  2351 						{
       
  2352 							if(afterCombine[curPos+12]=='S'&&afterCombine[curPos+13]=='T'&&afterCombine[curPos+14]=='R'&&afterCombine[curPos+15]=='U'&&afterCombine[curPos+16]=='C'&&afterCombine[curPos+17]=='T'&&IsClassKeyword(aText,curPos,curPos+17))
       
  2353 							{
       
  2354 								newText.append(afterCombine.substr(firstPos,curPos-firstPos));
       
  2355 								newText.append("class");
       
  2356 								for(int i=0;i<13;i++)
       
  2357 								{
       
  2358 									newText.append(" ");
       
  2359 								}
       
  2360 								curPos+=18;
       
  2361 								firstPos=curPos;
       
  2362 								break;
       
  2363 							}
       
  2364 						}
       
  2365 						curPos++;
       
  2366 						
       
  2367 					}//end of nonsharable
       
  2368 					else
       
  2369 					{
       
  2370 						curPos++;
       
  2371 					}
       
  2372 				}
       
  2373 				
       
  2374 				else
       
  2375 				{
       
  2376 					curPos++;
       
  2377 				}
       
  2378 				break;
       
  2379             }
       
  2380 			case PPSTATE_SHARP_COMMENT:
       
  2381 			case PPSTATE_SINGLE_COMMENT:
       
  2382 			{
       
  2383 				while(curPos< stringSize)
       
  2384 				{
       
  2385 					if(IsNewLine(afterCombine[curPos]))
       
  2386 					{
       
  2387 						if(stringSize-curPos>1)
       
  2388 						{
       
  2389 										if(
       
  2390 											(afterCombine[curPos]=='\n'&&afterCombine[curPos+1]=='\r')
       
  2391 											||
       
  2392 											(afterCombine[curPos]=='\r'&&afterCombine[curPos+1]=='\n')
       
  2393 											)
       
  2394 										{
       
  2395 											curPos+=2;									
       
  2396 										}
       
  2397 										else 
       
  2398 										{
       
  2399 											curPos+=1;
       
  2400 										}
       
  2401 										firstPos=curPos;
       
  2402 										curState=PPSTATE_NORMAL;
       
  2403 										newText.append("\n");
       
  2404 										break;
       
  2405 						}
       
  2406 						else
       
  2407 						{					
       
  2408 							newText.append("\n");
       
  2409 							return newText;
       
  2410 						}
       
  2411 					}
       
  2412 					else
       
  2413 					{
       
  2414 						curPos++;
       
  2415 					}
       
  2416 				}
       
  2417 				firstPos=curPos;
       
  2418 			
       
  2419 				break;
       
  2420 			}
       
  2421 			case PPSTATE_MUL_COMMENT:
       
  2422 			{
       
  2423 				blankCount=2;
       
  2424 				while(curPos< stringSize)
       
  2425 				{
       
  2426 					if(!HasEnoughChar(curPos,stringSize,1))
       
  2427 					{
       
  2428 						return newText;
       
  2429 					}
       
  2430 					if(afterCombine[curPos]=='*' && afterCombine[curPos+1]=='/')
       
  2431 					{
       
  2432 						curPos+=2;
       
  2433 						firstPos=curPos;
       
  2434 						curState=PPSTATE_NORMAL;
       
  2435 						blankCount+=2;
       
  2436 						break;
       
  2437 					}
       
  2438 					else if(IsNewLine(afterCombine[curPos]))
       
  2439 					{
       
  2440 						if(HasEnoughChar(curPos,stringSize,1))
       
  2441 						{
       
  2442 							if(
       
  2443 									(afterCombine[curPos]=='\n'&&afterCombine[curPos+1]=='\r')
       
  2444 									||
       
  2445 									(afterCombine[curPos]=='\r'&&afterCombine[curPos+1]=='\n')
       
  2446 								)
       
  2447 							{
       
  2448 										curPos+=2;				
       
  2449 							}
       
  2450 							else
       
  2451 							{
       
  2452 								curPos+=1;
       
  2453 							}
       
  2454 						}
       
  2455 						else 
       
  2456 						{
       
  2457 									curPos+=1;
       
  2458 						}					
       
  2459 						while (blankCount-->0)
       
  2460 						{
       
  2461 							newText.append(" ");
       
  2462 						}
       
  2463 						newText.append("\n");				
       
  2464 						blankCount=0;
       
  2465 					}
       
  2466 					else
       
  2467 					{
       
  2468 						curPos++;
       
  2469 						blankCount++;
       
  2470 					}
       
  2471 				}
       
  2472 				firstPos=curPos;
       
  2473 				while (blankCount-->0)
       
  2474 				{
       
  2475 						newText.append(" ");
       
  2476 				}
       
  2477 				blankCount=0;
       
  2478 			
       
  2479 				break;
       
  2480 			}
       
  2481 			case PPSTATE_STRING_LITERAL:
       
  2482 				blankCount=0;
       
  2483 				while(curPos< stringSize)
       
  2484 								{
       
  2485 									
       
  2486 									if((afterCombine[curPos]=='"' )&& (afterCombine[curPos-1]!='\\'))
       
  2487 									{
       
  2488 										curPos+=1;
       
  2489 										firstPos=curPos;
       
  2490 										while (blankCount-->0)
       
  2491 										{
       
  2492 											newText.append(" ");
       
  2493 										}
       
  2494 										newText.append("\"");
       
  2495 										curState=PPSTATE_NORMAL;
       
  2496 										break;
       
  2497 									}
       
  2498 									else
       
  2499 									{
       
  2500 										if(curPos>1 && (afterCombine[curPos]=='"' )&& (afterCombine[curPos-1]=='\\')&&(afterCombine[curPos-2]=='\\'))
       
  2501 										{
       
  2502 											curPos+=1;
       
  2503 										    firstPos=curPos;
       
  2504 											while (blankCount-->0)
       
  2505 											{
       
  2506 													newText.append(" ");
       
  2507 											}
       
  2508 											newText.append("\"");
       
  2509 											curState=PPSTATE_NORMAL;
       
  2510 											break;
       
  2511 										}
       
  2512 										else
       
  2513 										{
       
  2514 											curPos++;
       
  2515 											blankCount++;
       
  2516 										}
       
  2517 									}
       
  2518 								}
       
  2519 				break;
       
  2520 		}
       
  2521 	}
       
  2522 	newText.append(afterCombine.substr(firstPos,curPos-firstPos));
       
  2523 	return newText;
       
  2524 }
       
  2525 /*
       
  2526  * Get next matched '{'
       
  2527  */
       
  2528 int TLeaveScanModel::GetLeftBracket(const string& aText,uint pos)
       
  2529 {
       
  2530 	int len =aText.size();
       
  2531 	if(pos>=len)
       
  2532 	{
       
  2533 		return string::npos;
       
  2534 	}
       
  2535 	while(pos<len)
       
  2536 	{
       
  2537 		if(aText[pos]=='{')
       
  2538 		{
       
  2539 			return pos;
       
  2540 		}
       
  2541 		pos++;
       
  2542 	}
       
  2543 	return string::npos;
       
  2544 }
       
  2545 /*
       
  2546  * Get next matched '}'
       
  2547  */
       
  2548 int TLeaveScanModel::GetRightBracket(const string& aText,uint pos)
       
  2549 {
       
  2550 	int len = aText.size();
       
  2551 	if(pos>=len)
       
  2552 	{
       
  2553 		return string::npos;
       
  2554 	}
       
  2555 	int parentCount = 1;
       
  2556 	while(pos<len)
       
  2557 		{
       
  2558 			if(aText[pos]=='{')
       
  2559 			{
       
  2560 				parentCount++;
       
  2561 			}
       
  2562 			else if (aText[pos]=='}' )
       
  2563 			{
       
  2564 				parentCount--;
       
  2565 				if(parentCount==0)
       
  2566 				{
       
  2567 					return pos;
       
  2568 				}
       
  2569 			}
       
  2570 			pos++;
       
  2571 		}
       
  2572 		return string::npos;
       
  2573 	
       
  2574 }
       
  2575 /*
       
  2576  Get next '('
       
  2577  */
       
  2578 int TLeaveScanModel::GetLeftParenthesis(const string& aText,uint pos)
       
  2579 {
       
  2580 	int len =aText.size();
       
  2581 	if(pos>=len)
       
  2582 	{
       
  2583 		return string::npos;
       
  2584 	}
       
  2585 	while(pos<len)
       
  2586 	{
       
  2587 		char curChar = aText[pos];
       
  2588 		if(curChar=='(')
       
  2589 		{
       
  2590 			return pos;
       
  2591 		}
       
  2592 		pos++;
       
  2593 	}
       
  2594 	return string::npos;
       
  2595 }
       
  2596 
       
  2597 /*
       
  2598  * Get next matched ')'
       
  2599  */
       
  2600 int TLeaveScanModel::GetRightParenthesis(const string& aText,uint pos)
       
  2601 {
       
  2602 	int len = aText.size();
       
  2603 		if(pos>=len)
       
  2604 		{
       
  2605 			return string::npos;
       
  2606 		}
       
  2607 	int parentCount = 1;
       
  2608 	while(pos<len)
       
  2609 		{
       
  2610 			char curChar = aText[pos];
       
  2611 			if(curChar=='(')
       
  2612 			{
       
  2613 				parentCount++;
       
  2614 			}
       
  2615 			else if (curChar==')' )
       
  2616 			{
       
  2617 				parentCount--;
       
  2618 				if(parentCount==0)
       
  2619 				{
       
  2620 					return pos;
       
  2621 				}
       
  2622 			}
       
  2623 			pos++;
       
  2624 		}
       
  2625 		return string::npos;
       
  2626 }
       
  2627 
       
  2628 /*
       
  2629  Get next '<' by pair
       
  2630  */
       
  2631 int TLeaveScanModel::GetLeftTmpltParentBack(const string& aText,uint pos)
       
  2632 {
       
  2633 	int count=1;
       
  2634 	if (pos<=0)
       
  2635 	{
       
  2636 		return string::npos;
       
  2637 	}
       
  2638 	while(pos>0)
       
  2639 	{
       
  2640 		char curChar = aText[pos];
       
  2641 		if(curChar=='<')
       
  2642 		{
       
  2643 			count--;
       
  2644 			if (count <= 0)
       
  2645 				return pos;
       
  2646 		}
       
  2647 		else if(curChar=='>')
       
  2648 		{
       
  2649 			count++;
       
  2650 		}
       
  2651 		pos--;
       
  2652 	}
       
  2653 	return string::npos;
       
  2654 }
       
  2655 
       
  2656 /*
       
  2657  * Get next matched '>'
       
  2658  */
       
  2659 int TLeaveScanModel::GetRightTmpltParent(const string& aText,uint pos)
       
  2660 {
       
  2661 	int len = aText.size();
       
  2662 		if(pos>=len)
       
  2663 		{
       
  2664 			return string::npos;
       
  2665 		}
       
  2666 	int parentCount = 1;
       
  2667 	while(pos<len)
       
  2668 		{
       
  2669 			char curChar = aText[pos];
       
  2670 			if(curChar=='<')
       
  2671 			{
       
  2672 				parentCount++;
       
  2673 			}
       
  2674 			else if (curChar=='>' )
       
  2675 			{
       
  2676 				parentCount--;
       
  2677 				if(parentCount==0)
       
  2678 				{
       
  2679 					return pos;
       
  2680 				}
       
  2681 			}
       
  2682 			pos++;
       
  2683 		}
       
  2684 		return string::npos;
       
  2685 }
       
  2686 
       
  2687 /*
       
  2688  *Get the start and end position of a class
       
  2689  */
       
  2690 list<ClassMeta> TLeaveScanModel::GetClass(const string& aFile)
       
  2691 {
       
  2692 	int len= aFile.size();
       
  2693 	int startPos=0;
       
  2694 	int nextClassPos=-1;
       
  2695 	list<ClassMeta> classList;
       
  2696 	//struct ,NONSHARABLE_CLASS,NONSHARABLE_STRUCT should be parsed to 'class' in pp stage
       
  2697 	while((nextClassPos = aFile.find("class",startPos))!=string::npos)
       
  2698 	{
       
  2699 		
       
  2700 
       
  2701 		char classSuffix = aFile[nextClassPos+5]; //the char after class
       
  2702 		if(classSuffix!=' '&& classSuffix!='\n' && classSuffix!='\r' && classSuffix!='\t'&& classSuffix!=':'&&classSuffix!='{')
       
  2703 		{
       
  2704 			nextClassPos++;
       
  2705 			startPos=nextClassPos;
       
  2706 			continue;
       
  2707 		}
       
  2708 		/*no use*/
       
  2709 		/*
       
  2710 		if(nextClassPos>0)
       
  2711 		{
       
  2712 			char classPrfix = aFile[nextClassPos-1];
       
  2713 			if (classPrfix =='_' || (classPrfix>='a' && classPrfix<='z') || (classPrfix>='A' && classPrfix<='Z') || (classPrfix>='0' && classPrfix<='9'))
       
  2714 			{
       
  2715 				nextClassPos++;
       
  2716 				startPos=nextClassPos;
       
  2717 				continue;
       
  2718 			}
       
  2719 		}
       
  2720 		*/
       
  2721 		if(nextClassPos >0 )
       
  2722 		{
       
  2723 			char classPrefix = aFile[nextClassPos-1];
       
  2724 			if(classPrefix!=' '&& classPrefix!='\n' && classPrefix!='\r' && classPrefix!='\t'&& classPrefix!='{'&& classPrefix!='>'&& classPrefix!='}')
       
  2725 			{
       
  2726 				nextClassPos++;
       
  2727 				startPos=nextClassPos;
       
  2728 				continue;
       
  2729 			}
       
  2730 		}
       
  2731 		
       
  2732 		//pattern: template< ...class...>
       
  2733 		int checkTemplate = nextClassPos-1;
       
  2734 		bool isTemplateClass = false;
       
  2735 		while(checkTemplate >= 0)
       
  2736 		{
       
  2737 			char checkTempChar = aFile[checkTemplate];
       
  2738 			if(checkTempChar==' '|| checkTempChar=='\n' || checkTempChar=='\r' ||checkTempChar=='\t')
       
  2739 			{
       
  2740 				checkTemplate --;
       
  2741 			}
       
  2742 			else if(checkTempChar=='>') //template<> class
       
  2743 			{
       
  2744 				break;
       
  2745 			}
       
  2746 			else if(checkTempChar=='<')
       
  2747 			{
       
  2748 				isTemplateClass =true;
       
  2749 				break;
       
  2750 			}
       
  2751 			else if(checkTempChar==',') //template<typename a, class T>
       
  2752 			{
       
  2753 				isTemplateClass =true;
       
  2754 				break;	
       
  2755 			}
       
  2756 			else
       
  2757 			{
       
  2758 				break;
       
  2759 			}
       
  2760 		}
       
  2761 		if(isTemplateClass)
       
  2762 		{
       
  2763 			startPos = nextClassPos+1;
       
  2764 			continue;
       
  2765 		}
       
  2766 
       
  2767 		int classStart = GetLeftBracket(aFile,nextClassPos);
       
  2768 		if(classStart==-1)
       
  2769 		{
       
  2770 			break;  //there is no more class-body, so we can break dircetly
       
  2771 		}
       
  2772 		//skip this pattern
       
  2773 		//class a;
       
  2774 		uint semiPos = aFile.find(";",nextClassPos);
       
  2775 		//such as this pattern: 
       
  2776 		//class a;
       
  2777 		//class b{};
       
  2778 		if(semiPos!=string::npos&&semiPos<classStart)
       
  2779 		{
       
  2780 			startPos = semiPos;
       
  2781 			continue;
       
  2782 		}
       
  2783 
       
  2784 		uint classEnd = GetRightBracket(aFile,classStart+1);
       
  2785 		if(classEnd == -1)
       
  2786 		{
       
  2787 			classEnd = len-1;
       
  2788 		}
       
  2789 		
       
  2790 		//get class name
       
  2791 		int curClassNamePos = classStart-1;
       
  2792 		char curClassChar = 0;
       
  2793 		//find pattern:
       
  2794 		//class a:publlc b{...
       
  2795 		uint colonPos = aFile.find(":",nextClassPos);
       
  2796 		while(colonPos!=string::npos && colonPos<curClassNamePos)
       
  2797 		{
       
  2798 			if(colonPos != string::npos && colonPos < classStart)
       
  2799 			{
       
  2800 				uint secondColonPos = aFile.find(":",colonPos+1);
       
  2801 				if(secondColonPos != string::npos && secondColonPos!=(colonPos+1))
       
  2802 				{
       
  2803 					curClassNamePos = colonPos-1;
       
  2804 					break;
       
  2805 				}
       
  2806 				else if(secondColonPos == string::npos)
       
  2807 				{
       
  2808 					curClassNamePos = colonPos-1;
       
  2809 					break;
       
  2810 				}
       
  2811 				//find ::
       
  2812 				else
       
  2813 				{
       
  2814 					colonPos = aFile.find(":",colonPos+2);
       
  2815 				}
       
  2816 			}
       
  2817 		}
       
  2818 		//skip white spaces
       
  2819 		while(curClassNamePos >=  nextClassPos)
       
  2820 		{
       
  2821 			curClassChar = aFile[curClassNamePos];
       
  2822 			if(curClassChar ==' ' || curClassChar =='\t' || curClassChar =='\n' ||curClassChar=='\r' ||curClassChar==')')
       
  2823 			{
       
  2824 				curClassNamePos--;
       
  2825 			}
       
  2826 			else
       
  2827 			{
       
  2828 				break;
       
  2829 			}
       
  2830 		}
       
  2831 		int classNameEnd = curClassNamePos;
       
  2832 		while(curClassNamePos>=nextClassPos)
       
  2833 		{
       
  2834 			curClassChar = aFile[curClassNamePos];
       
  2835 			if(curClassChar ==' ' || curClassChar =='\t' || curClassChar =='\n' ||curClassChar=='\r'||curClassChar==':'||curClassChar=='(')
       
  2836 			{
       
  2837 				break;
       
  2838 			}
       
  2839 			else
       
  2840 			{
       
  2841 				curClassNamePos--;
       
  2842 			}
       
  2843 		}
       
  2844 		int classNameStart = curClassNamePos+1; //cur is a blank
       
  2845 		string curClassName = TrimString(aFile.substr(classNameStart,classNameEnd-classNameStart+1));
       
  2846 		if (curClassName == "class")
       
  2847 		{
       
  2848 			curClassName = "anonymous-class";
       
  2849 		}
       
  2850 		ClassMeta curClass;
       
  2851 		curClass.startPos=classStart;
       
  2852 		curClass.endPos=classEnd;
       
  2853 		curClass.className = curClassName;
       
  2854 		classList.push_back(curClass);
       
  2855 		startPos=nextClassPos+1;
       
  2856 	}
       
  2857 	return classList;
       
  2858 }
       
  2859 
       
  2860 /*
       
  2861  * parse the class and check it
       
  2862  * */
       
  2863 void TLeaveScanModel::CheckClass(const string& aText ,const string& aClassName , uint start,uint end)
       
  2864 {
       
  2865 	start=start+1;
       
  2866 	int curPos = start;
       
  2867 	end=end-1;
       
  2868 	if(end<=start) return;
       
  2869 	//int colonCount=0;
       
  2870 	int curStart= curPos;
       
  2871 	int curEnd = curStart;
       
  2872 	int curType = E_NA;
       
  2873 	int curLine = 0; // wrong!!!
       
  2874 	int len = aText.size();
       
  2875 	string functionHead="";
       
  2876 	string functionArgu="";
       
  2877 	string functionBody="";
       
  2878 	string memberDef="";
       
  2879 	
       
  2880 	for(curPos = start;curPos<=end;curPos++)
       
  2881 	{
       
  2882 		char curChar = aText[curPos];
       
  2883 		switch(curChar)
       
  2884 		{
       
  2885 		case ':':
       
  2886 			if (aText[curPos+1]==':')//  a '::'
       
  2887 			{
       
  2888 				//skip second :
       
  2889 				curPos+=1;
       
  2890 			}
       
  2891 			//such as ctor_init_list
       
  2892 			else if(curType == E_MemberFunctionDecl || curType==E_MemberFunctionDef)
       
  2893 			{
       
  2894 				//nothing
       
  2895 			}
       
  2896 			else //such as "public:"  ->ignore
       
  2897 			{
       
  2898 				curStart = curPos+1;
       
  2899 			}
       
  2900 			break;
       
  2901 		case '{':
       
  2902 			if(curType ==E_MemberFunctionDecl )
       
  2903 			{
       
  2904 				curType = E_MemberFunctionDef;
       
  2905 			}
       
  2906 			else
       
  2907 			{
       
  2908 				curType = E_Enum;
       
  2909 			}		
       
  2910 			curEnd = GetRightBracket(aText,curPos+1);
       
  2911 			functionBody = aText.substr(curPos,curEnd-curPos+1);
       
  2912 			//check in class function
       
  2913 			if(E_MemberFunctionDef==curType)
       
  2914 			{
       
  2915 				CheckInClassFunc(aText,aClassName,functionHead,curPos,curEnd);
       
  2916 			}
       
  2917 			curPos = curEnd;
       
  2918 			curStart =curPos;
       
  2919 			curType = E_NA;
       
  2920 			break;
       
  2921 		case '(':
       
  2922 			curType = E_MemberFunctionDecl;
       
  2923 			curEnd = GetRightParenthesis(aText,curPos+1);		
       
  2924 			functionHead = aText.substr(curStart,curPos-curStart);
       
  2925 			functionArgu = aText.substr(curPos,curEnd-curPos+1);
       
  2926 			curPos = curEnd;
       
  2927 			curStart =curPos;
       
  2928 			
       
  2929 			break;
       
  2930 		case ';':
       
  2931 			if(curType == E_NA)
       
  2932 			{
       
  2933 				curType = E_MemberData;
       
  2934 			}
       
  2935 			//check point
       
  2936 			if (curType == E_MemberData)
       
  2937 			{
       
  2938 				memberDef = aText.substr(curStart,curPos-curStart);
       
  2939 				if(memberDef.find("LCleanedup")!=string::npos)
       
  2940 				{
       
  2941 					iErrorString = "class "+aClassName+" defines a data member with LCleanedup* type.\n";
       
  2942 					cout<<GetErrorLineHead(aText, curPos)<<iErrorString;	
       
  2943 				}
       
  2944 			}
       
  2945 			else if(curType == E_MemberFunctionDecl)
       
  2946 			{
       
  2947 				string funcName = GetFunctNameFromFuncHead(functionHead);
       
  2948 				string extraTypes="CDX";
       
  2949 				bool isLeaver = false;
       
  2950 				if (funcName[funcName.length()-1] == 'L' || 
       
  2951 				      (funcName[funcName.length()-2] == 'L' && string::npos != extraTypes.find(funcName[funcName.length()-1]) ) )
       
  2952 				{
       
  2953 					isLeaver = true; // container is marked Leaver - used to return here
       
  2954 				}
       
  2955 				else if(IsLClassCtor(aClassName+"::"+funcName))
       
  2956 				{
       
  2957 					isLeaver = true;
       
  2958 				}
       
  2959 				else
       
  2960 				    isLeaver = false; // container not marked Leaver
       
  2961 				  
       
  2962 				
       
  2963 				if(functionHead.find("LString")!=string::npos ||functionHead.find("LData")!=string::npos)
       
  2964 				{
       
  2965 					iErrorString = aClassName+"::"+funcName+" returns LString/LData class.\n";
       
  2966 					if(!isLeaver) cout<<GetErrorLineHead(aText, curPos)<<iErrorString;
       
  2967 				}
       
  2968 				if(functionArgu.find("LString")!=string::npos ||functionArgu.find("LData")!=string::npos)
       
  2969 				{
       
  2970 					iErrorString = aClassName+"::"+funcName+"  uses LString/LData class as parameter.\n";
       
  2971 					if(!isLeaver) cout<<GetErrorLineHead(aText, curPos)<<iErrorString;
       
  2972 				}
       
  2973 			}
       
  2974 			//set up next check
       
  2975 			curStart = curPos;
       
  2976 			curType =E_NA;
       
  2977 			break;
       
  2978 		case 'c':
       
  2979 			//check if 'class' and skip the inner class
       
  2980 			if (HasEnoughChar(curPos,len,5))
       
  2981 			{
       
  2982 				if ( aText[curPos+1]=='l' && aText[curPos+2]=='a'  && aText[curPos+3]=='s'  && aText[curPos+4]=='s' )
       
  2983 				{
       
  2984 					char delimiter = aText[curPos+5];
       
  2985 					//exclude pattern: void classa ()
       
  2986 					if (!((delimiter >='0' && delimiter <='9') || (delimiter>='a' && delimiter<='z') || (delimiter>='A' && delimiter<='Z') ||(delimiter=='_')))
       
  2987 					{
       
  2988 						delimiter = aText[curPos-1];
       
  2989 						//exclude pattern: void aclass()
       
  2990 						if(curPos>0 && !((delimiter >='0' && delimiter <='9') || (delimiter>='a' && delimiter<='z') || (delimiter>='A' && delimiter<='Z') ||(delimiter=='_')))
       
  2991 						{
       
  2992 							//pattern: template<class T> Ltemp(T x){}
       
  2993 							uint templatePos = aText.find("template",curStart);
       
  2994 							if(templatePos != string::npos && templatePos < curPos)
       
  2995 							{
       
  2996 								continue;
       
  2997 							}
       
  2998 							else
       
  2999 							{
       
  3000 								int tmpLeft = GetLeftBracket(aText,curPos+4);
       
  3001 								int tempRight = GetRightBracket(aText,tmpLeft+1);
       
  3002 								curPos = tempRight;
       
  3003 								curStart = curPos;
       
  3004 								curType = E_NA;
       
  3005 							}
       
  3006 						}
       
  3007 					}
       
  3008 					
       
  3009 				}			
       
  3010 			}
       
  3011 			//ignore
       
  3012 			break;
       
  3013 		default:
       
  3014 			//curPos++;
       
  3015 			break;
       
  3016 		}
       
  3017 		//curPos++;
       
  3018 	}
       
  3019 }
       
  3020 /*
       
  3021  * Is a ctor of L class
       
  3022  * */
       
  3023 bool TLeaveScanModel::IsLClassCtor(const string& aName)
       
  3024 {
       
  3025 	
       
  3026 	//if(aName[0]=='L'&&aName.find("::")!=string::npos)%
       
  3027 	//{
       
  3028 	//	return true;
       
  3029 	//}
       
  3030 	uint colonPos = aName.find("::");
       
  3031 	if(colonPos == string::npos)
       
  3032 	{
       
  3033 		return false;
       
  3034 	}
       
  3035 	string s1 = aName.substr(0,colonPos);
       
  3036 	string s2 = aName.substr(colonPos+2);
       
  3037 	s1.erase(s1.find_last_not_of(" \t\n\r")+1);
       
  3038 	s1.erase(0,s1.find_first_not_of(" \t\n\r"));
       
  3039 
       
  3040 	s2.erase(s2.find_last_not_of(" \t\n\r")+1);
       
  3041 	s2.erase(0,s2.find_first_not_of(" \t\n\r"));
       
  3042 	
       
  3043 
       
  3044 	uint tmpltPos = s1.find('<');
       
  3045 	if(tmpltPos!=string::npos)
       
  3046 	{
       
  3047 		s1 = s1.substr(0,tmpltPos);
       
  3048 	}
       
  3049 	if(s1[0]!='L')
       
  3050 	{
       
  3051 		return false;
       
  3052 	}
       
  3053 	if(s1.find(s2)!=string::npos)
       
  3054 	{
       
  3055 		uint s1Len = s1.length();
       
  3056 		uint s2Len = s2.length();
       
  3057 		//s1=LAL
       
  3058 		//s2=LA
       
  3059 		if(s2Len>0 && s1Len > s2Len)
       
  3060 		{
       
  3061 			char diffChar = s1[s2Len];
       
  3062 			if( (diffChar>='a' && diffChar<='z') || (diffChar>='A' && diffChar<='Z') 
       
  3063 				||(diffChar>='0' && diffChar<='9') || (diffChar=='_'))
       
  3064 			{
       
  3065 				return false;
       
  3066 			}
       
  3067 		}
       
  3068 		return true;
       
  3069 	}
       
  3070 	if(s2.find("operator")==0)
       
  3071 	{
       
  3072 		return true;
       
  3073 	}
       
  3074 	if(s2.find("new")==0)
       
  3075 	{
       
  3076 		return true;
       
  3077 	}
       
  3078 
       
  3079 	return false;
       
  3080 }
       
  3081 /*
       
  3082 * Is sometiing defined in class scope?
       
  3083 */
       
  3084 bool TLeaveScanModel::IsInClassScope(uint pos)
       
  3085 {
       
  3086 	if (pos == string::npos)
       
  3087 	{
       
  3088 		return false;
       
  3089 	}
       
  3090 	list<ClassMeta>::iterator iter; 
       
  3091 	for(iter=iClassList.begin();iter!=iClassList.end();iter++) 
       
  3092 	{ 
       
  3093 		if(iter->startPos<=pos && iter->endPos >= pos)
       
  3094 		{
       
  3095 			return true;
       
  3096 		}
       
  3097 	}
       
  3098 	return false;
       
  3099 
       
  3100 }
       
  3101 /*
       
  3102  * Try to get the function name from a function head
       
  3103  * */
       
  3104 string TLeaveScanModel::GetFunctNameFromFuncHead(const string& aFuncHead)
       
  3105 {
       
  3106 	string funcName;
       
  3107 	int len = aFuncHead.length();
       
  3108 	int curPos=len-1;
       
  3109 	char curChar;
       
  3110 	int nameStart = -1;
       
  3111 	int nameEnd;
       
  3112 	//skip white spaces
       
  3113 	while(curPos>=0)
       
  3114 	{
       
  3115 		curChar = aFuncHead[curPos];
       
  3116 		if(curChar==' ' || curChar=='\t' ||curChar=='\n'||curChar=='\r')
       
  3117 		{
       
  3118 			curPos--;
       
  3119 		}
       
  3120 		else
       
  3121 		{
       
  3122 			break;
       
  3123 		}	
       
  3124 	}
       
  3125 	if(curChar == '>')
       
  3126 	{
       
  3127 		int templateBalance = 1;
       
  3128 		curPos--;
       
  3129 		while(curPos>=0)
       
  3130 		{
       
  3131 			curChar = aFuncHead[curPos];
       
  3132 			
       
  3133 			if(curChar=='>')
       
  3134 			{
       
  3135 				templateBalance++;
       
  3136 			}
       
  3137 			else if(curChar =='<')
       
  3138 			{
       
  3139 				templateBalance--;
       
  3140 			}
       
  3141 			curPos--;
       
  3142 			if(templateBalance==0)
       
  3143 			{
       
  3144 				break;
       
  3145 			}
       
  3146 			
       
  3147 		}
       
  3148 	}
       
  3149 	if(curPos<=0) return "";
       
  3150 	
       
  3151 	nameEnd = curPos;
       
  3152 	if(aFuncHead.find("operator")!=string::npos)
       
  3153 	{
       
  3154 		int tmpNameStart = aFuncHead.find("operator");
       
  3155 		char delimiter = aFuncHead[tmpNameStart+8];
       
  3156 		if (!((delimiter >='0' && delimiter <='9') || (delimiter>='a' && delimiter<='z') || (delimiter>='A' && delimiter<='Z') ||(delimiter=='_')))
       
  3157 		{
       
  3158 			if(tmpNameStart>0)
       
  3159 			{
       
  3160 				delimiter = aFuncHead[tmpNameStart-1];
       
  3161 				if (!((delimiter >='0' && delimiter <='9') || (delimiter>='a' && delimiter<='z') || (delimiter>='A' && delimiter<='Z') ||(delimiter=='_')))
       
  3162 				{
       
  3163 					nameStart = tmpNameStart;
       
  3164 				}
       
  3165 			}
       
  3166 			if(tmpNameStart==0)
       
  3167 			{
       
  3168 				nameStart = tmpNameStart;
       
  3169 			}
       
  3170 		}				
       
  3171 	}
       
  3172 	if(nameStart == -1)
       
  3173 	{
       
  3174 		while(curPos>=0)
       
  3175 		{
       
  3176 			curChar = aFuncHead[curPos];
       
  3177 			if(curChar==' ' || curChar=='\t' ||curChar=='\n'||curChar=='\r'||curChar=='>')
       
  3178 			{
       
  3179 				nameStart = curPos+1;
       
  3180 				if(nameStart<0)
       
  3181 				{
       
  3182 					nameStart = 0;
       
  3183 				}
       
  3184 				break;
       
  3185 				
       
  3186 			}
       
  3187 			else
       
  3188 			{
       
  3189 				curPos--;
       
  3190 			}	
       
  3191 			
       
  3192 		}
       
  3193 		if(curPos<0)
       
  3194 		{
       
  3195 			nameStart = 0;
       
  3196 		}
       
  3197 	}
       
  3198 	funcName = aFuncHead.substr(nameStart,nameEnd-nameStart+1);
       
  3199 	return funcName;
       
  3200 
       
  3201 	
       
  3202 }
       
  3203 /*
       
  3204  * Get the Param string of a function decl
       
  3205  * aStart usually is the position of '{'
       
  3206  * */
       
  3207 string TLeaveScanModel::GetFunctionParam(const string& aText, uint aStart)
       
  3208 {
       
  3209 	int curPos = aStart;
       
  3210 	if(curPos == string::npos)
       
  3211 	{
       
  3212 			return "";
       
  3213 	}
       
  3214 	int leftParenthesis  = GetLeftParenthesis(aText, curPos);
       
  3215 	int rightParenthesis = GetRightParenthesis(aText, leftParenthesis+1);
       
  3216 	
       
  3217 	if(leftParenthesis==string::npos || rightParenthesis==string::npos)
       
  3218 	{
       
  3219 		return "";
       
  3220 	}
       
  3221 	else if(rightParenthesis>leftParenthesis) 
       
  3222 	{
       
  3223 		return aText.substr(leftParenthesis+1, rightParenthesis-leftParenthesis-1);
       
  3224 	}
       
  3225 	return "";
       
  3226 	
       
  3227 	
       
  3228 }
       
  3229 
       
  3230 /*Get the string from last member decl to aStart*/
       
  3231 string TLeaveScanModel::GetFunctionHead(const string& aText, uint aStart)
       
  3232 {
       
  3233 	int curPos = aStart;
       
  3234 	char curChar;
       
  3235 	if(curPos==string::npos || curPos<=0)
       
  3236 	{
       
  3237 		return "";
       
  3238 	}
       
  3239 	while(curPos >= 0)
       
  3240 	{
       
  3241 		curChar = aText[curPos];
       
  3242 		if(curChar == '{' || curChar == '}' || curChar == ';')
       
  3243 		{
       
  3244 			break;
       
  3245 		}
       
  3246 		curPos--;
       
  3247 	}
       
  3248 	if(curPos<0)
       
  3249 	{
       
  3250 		curPos = 0;
       
  3251 	}
       
  3252         
       
  3253 	int tempPos = string::npos;
       
  3254 	if( (aText.rfind("public",aStart)!=string::npos)||(aText.rfind("protected",aStart))!=string::npos ||(aText.rfind("private",aStart))!=string::npos)
       
  3255 	{
       
  3256 		tempPos = aText.rfind(':',aStart);
       
  3257                  
       
  3258 	}
       
  3259         if(tempPos>curPos)
       
  3260 	{
       
  3261 		curPos = tempPos;
       
  3262 	}
       
  3263 	return aText.substr(curPos,aStart-curPos);
       
  3264 
       
  3265 }
       
  3266 /*Chech the function decl/define in a class*/
       
  3267 void TLeaveScanModel::CheckInClassFunc(const string& aText , const string& aClassName, const string& aFuncName, uint start,uint end)
       
  3268 {
       
  3269 	bool isLeaver;
       
  3270 	bool clean;
       
  3271 	string funcName = TrimString(GetFunctNameFromFuncHead(aFuncName));
       
  3272 	string qualifiedFuncName = aClassName+"::"+funcName;
       
  3273 	clean = CheckFunc(aText, funcName, start, end, isLeaver);
       
  3274 	bool isLCFunc =false;
       
  3275 	if(funcName[funcName.length()-1] == 'C' && funcName[funcName.length()-2] == 'L')
       
  3276 	{
       
  3277 	    isLCFunc = true;
       
  3278 	}
       
  3279 	if (isLeaver) // was a leaving container(safe) and no leavers found
       
  3280 	{
       
  3281 	
       
  3282 	    if (clean)
       
  3283 	    {
       
  3284 	    	iPositionOfError=0;
       
  3285 	    	iErrorString = "Warning - " + funcName + " appears to contain no leavers.";
       
  3286 	        ReportErrorLineAndString(start);	  
       
  3287 	    }
       
  3288 	    else if(isLCFunc)
       
  3289     	  {
       
  3290     	      
       
  3291 			  uint lcleanedupPos = iErrorString.find("LCleanedup");
       
  3292 			  if(lcleanedupPos!=string::npos)
       
  3293 				{
       
  3294     	    	  uint callPos = iErrorString.find(" calls ");
       
  3295 				  uint lcleanedupPosInFuncName = funcName.find("LCleanedup");
       
  3296 				  if(callPos!=string::npos && lcleanedupPosInFuncName!=string::npos && lcleanedupPos<callPos)
       
  3297 				  {;}
       
  3298 				  else
       
  3299 				  {
       
  3300 					iErrorString = "LCleanedup class is used in a function suffixed LC";
       
  3301     	    		ReportErrorLineAndString(start);
       
  3302 				  }
       
  3303 				}
       
  3304     	  }
       
  3305 
       
  3306 	    // any leavers info can be supressed here since container was leaver
       
  3307 	  }
       
  3308 	  else // wasn't a leaving container 
       
  3309 	  {
       
  3310 	    if (!clean) // was dirty, so report
       
  3311 	    	ReportErrorLineAndString(start);
       
  3312 	  }
       
  3313 };
       
  3314 
       
  3315 //
       
  3316 // Some test functions (for when leavescan parses its own source code)
       
  3317 //
       
  3318 void TLeaveScanModel::Test1()
       
  3319 {
       
  3320   Test2L();
       
  3321 }
       
  3322 
       
  3323 void TLeaveScanModel::Test2L()
       
  3324 {
       
  3325   Test1();
       
  3326 }
       
  3327 
       
  3328 #define TEST2L Test2L
       
  3329 void TLeaveScanModel::Test3()
       
  3330 {
       
  3331   TEST2L();
       
  3332 }
       
  3333 
       
  3334 void TLeaveScanModel::Test4()
       
  3335 {
       
  3336   Test2L(); // qualify me
       
  3337 };
       
  3338 
       
  3339 
       
  3340 
       
  3341 // warnings back to default levels
       
  3342 //#pragma warning (pop) 
       
  3343