apicompatanamdw/compatanalysercmd/headeranalyser/src/CPPParser.cpp
changeset 3 ebe3f8f03b59
parent 0 638b9c697799
equal deleted inserted replaced
2:0cb2248d0edc 3:ebe3f8f03b59
    43 XERCES_CPP_NAMESPACE_USE
    43 XERCES_CPP_NAMESPACE_USE
    44 
    44 
    45 const int KMaxFilenameLength = 512;
    45 const int KMaxFilenameLength = 512;
    46 const int KMaxDirLength=1024;
    46 const int KMaxDirLength=1024;
    47 
    47 
       
    48 #define MAX_ARRAY_COUNT 200
       
    49 
    48 // The C++ parser executable
    50 // The C++ parser executable
    49 #ifdef __WIN__
    51 #ifdef __WIN__
    50 static const char* GCCXML_COMMAND = "ha_gccxml_cc1plus ";
    52 static const char* GCCXML_COMMAND = "ha_gccxml_cc1plus ";
    51 #else
    53 #else
    52 static const char* GCCXML_COMMAND = "./ha_gccxml_cc1plus ";
    54 static const char* GCCXML_COMMAND = "./ha_gccxml_cc1plus ";
   464 
   466 
   465 // ----------------------------------------------------------------------------
   467 // ----------------------------------------------------------------------------
   466 // CPPParser::HandleExports
   468 // CPPParser::HandleExports
   467 // ----------------------------------------------------------------------------
   469 // ----------------------------------------------------------------------------
   468 //
   470 //
       
   471 
   469 int CPPParser::HandleExports(string aFilename, string aVersion)
   472 int CPPParser::HandleExports(string aFilename, string aVersion)
   470 {
   473 {
   471     int ret = 0;
   474 	int ret = 0;
   472     string ofilename = aFilename + ".2";
   475 	string ofilename = aFilename + ".2";
   473     
   476 
   474     ifstream input(aFilename.c_str(), ios::in);
   477 	ifstream input(aFilename.c_str(), ios::in);
   475     ofstream output(ofilename.c_str(), ios::out);
   478 	ofstream output(ofilename.c_str(), ios::out);
   476     iOutputFilename = ofilename;
   479 	iOutputFilename = ofilename;
   477     char c;
   480 	char c;
   478     string toflush = "";
   481 	string toflush = "";
   479     unsigned int matches = 0;
   482 	string flush = "";
   480     string tofind = STR_EXPORT_HACK;
   483 	unsigned int matches = 0;
   481     string attribstr = STR_ATTRIBUTE_STR;
   484 	string tofind = STR_EXPORT_HACK;
   482     string outputBuffer;
   485 	string attribstr = STR_ATTRIBUTE_STR;
   483     outputBuffer.reserve(PREPROCESS_BUFFERSIZE);
   486 	string outputBuffer;
   484     int state = EStateSearching;
   487 	outputBuffer.reserve(PREPROCESS_BUFFERSIZE);
   485     bool purevirtual = false;
   488 	int state = EStateSearching;
   486     bool possiblepurevirtual = false;
   489 	char stackArray[MAX_ARRAY_COUNT] = {'\0'};
   487     while (input.get(c))
   490 	int arryPos = 0;
   488     {
   491 	
   489         if (outputBuffer.length() >= PREPROCESS_BUFFERSIZE)
   492 	string isClass = "class";
   490         {
   493 	string isEnum = "enum";
   491             output << outputBuffer;
   494 	string isStruct = "struct";
   492             outputBuffer = "";
   495 	string isUnion = "union";
   493         }
   496 	string isInline = "inline";
   494         if (state == EStateSearching)
   497 
   495         {
   498 	unsigned int clsPos = 0;
   496             if (c == tofind.at(matches))
   499 	unsigned int enmPos = 0;
   497             {
   500 	unsigned int strctPos = 0;
   498                 matches++;
   501 	unsigned int inlinePos = 0;
   499                 toflush += c;
   502 	unsigned int unionPos = 0;
   500             } else 
   503 	char arraychar = '\0';
   501             {
   504 
   502                 matches = 0;
   505 	unsigned int bufPos = 0;
   503                 if (!toflush.empty())
   506 	
   504                 {
   507 	string temp;
   505                     outputBuffer += toflush;
   508 	string buf;
   506                     toflush = "";
   509 	
   507                 }
   510 	bool possibleVirtualFunc = false;
   508                 outputBuffer += c;
   511 	bool virtualFunc = false;
   509             }
   512 	bool ignorecheck = false;
   510             if (matches == tofind.length())
   513 	while (input.get(c))
   511             {
   514 	{
   512                 toflush = "";
   515 		ignorecheck = false;
   513                 state = EStateReplacing;
   516 		if (outputBuffer.length() >= PREPROCESS_BUFFERSIZE)
   514                 matches = 0;
   517 		{
   515             }
   518 			output << outputBuffer;
   516         } else if (state == EStateReplacing)
   519 			outputBuffer = "";
   517         {
   520 		}
   518             if (c == '=')
   521        // Get the bufferpos
   519             {
   522 		bufPos = (unsigned int)outputBuffer.length()-1;
   520                 if (possiblepurevirtual == true && !toflush.empty())
   523 
   521                 {
   524 		// delete buf (class\enum\struct) entry if next letter is not space
   522                     outputBuffer += toflush;
   525  		if ( buf.length() > 0 && state == EStateReplacing && (c != ' ' && c != '\t' && int(c) != 10))
   523                     toflush = "";
   526 		{
   524                 }
   527 			buf = "";
   525                 possiblepurevirtual = true;
   528 		}
   526                 toflush += c;
   529 		if( c == isClass.at(clsPos))
   527             } else if (possiblepurevirtual == true && c!= ';')
   530 		{
   528             {
   531 			if( clsPos == 0 ) // searching for class keyword with space before and after
   529                 if (c == ' ')
   532 			{
   530                 {
   533 				if(outputBuffer == "" || outputBuffer.at(bufPos) == ' ' || outputBuffer.at(bufPos) == '\t'
   531                     toflush += c;
   534 					|| int(outputBuffer.at(bufPos)) == 10 || int(outputBuffer.at(bufPos)) == 32 )
   532                 } else if (c == '\t')
   535 					clsPos++;
   533                 {
   536 			}
   534                     toflush += c;
   537 			else
   535                 } else if (c == '0')
   538 				clsPos++;
   536                 {
   539 		}			
   537                     toflush += c;
   540 			
   538                     purevirtual = true;
   541 		else
   539                 } else
   542 			clsPos = 0;
   540                 {
   543 		if (clsPos == isClass.length()) // keyword found 
   541                     outputBuffer += toflush;
   544 		{
   542                     outputBuffer += c;
   545 			clsPos = 0;
   543                     toflush = "";
   546 			buf = isClass;
   544                     possiblepurevirtual = false;
   547 			ignorecheck = true; // in the current iteration don't match buf string with class\enum\struct keyword
   545                     purevirtual = false;
   548 			                    // as keyword may be part of some word like " classification" 
   546                 }
   549 		}
   547             } else if (c == ';')
   550 
   548             {
   551 		if( c == isUnion.at(unionPos))
   549                 state = EStateSearching;
   552 		{
   550                 if (purevirtual)
   553 			if( unionPos == 0 ) // searching for union keyword with space before and after
   551                 {
   554 			{
   552                 } else if (possiblepurevirtual)
   555 				if(outputBuffer == "" || outputBuffer.at(bufPos) == ' ' || outputBuffer.at(bufPos) == '\t'
   553                 {
   556 					|| int(outputBuffer.at(bufPos)) == 10 || int(outputBuffer.at(bufPos)) == 32 )
   554                     outputBuffer += toflush;
   557 					unionPos++;
   555                     toflush = "";
   558 			}
   556                 }
   559 			else
   557 
   560 				unionPos++;
   558                 outputBuffer += " ";
   561 		}			
   559                 outputBuffer += attribstr;
   562 			
   560                 if (!toflush.empty())
   563 		else
   561                 {
   564 			unionPos = 0;
   562                     outputBuffer += " ";
   565 		if (unionPos == isUnion.length()) // keyword found 
   563                     outputBuffer += toflush;
   566 		{
   564                     toflush = "";
   567 			unionPos = 0;
   565                 }
   568 			buf = isUnion;
   566                 possiblepurevirtual = false;
   569 			ignorecheck = true; // in the current iteration don't match buf string with class\enum\struct\union keyword
   567                 purevirtual = false;
   570 			                    // as keyword may be part of some word like " classification" 
   568                 outputBuffer += ';';
   571 		}
   569             } else
   572 
   570             {
   573 		if(c == isStruct.at(strctPos))// searching for struct keyword with space before and after
   571                 outputBuffer += c;
   574 		{
   572             }
   575 			if( strctPos == 0 )
   573         } else if (state == EStateReplaceDone)
   576 			{
   574         {
   577 				if(outputBuffer == "" || outputBuffer.at(bufPos) == ' ' || outputBuffer.at(bufPos) == '\t'
   575 
   578 					|| int(outputBuffer.at(bufPos)) == 10 )
   576         }
   579 					strctPos++;
   577 
   580 			}
   578     }
   581 			else
   579     if (outputBuffer.length() != 0)
   582 				strctPos++;
   580     {
   583 		}
   581         output << outputBuffer;
   584 		else
   582     }
   585 			strctPos = 0;
   583     return ret;
   586 
   584 }
   587 		if(strctPos == isStruct.length())
   585 
   588 		{
       
   589 			strctPos = 0;
       
   590 			buf = isStruct;
       
   591 			ignorecheck = true; // in the current iteration don't match buf string with class\enum\struct keyword
       
   592 			                    // as keyword may be part of some word like " structural" 
       
   593 		}
       
   594 
       
   595 		if(c == isEnum.at(enmPos) )// searching for enum keyword with space before and after
       
   596 		{
       
   597 			if( enmPos == 0 )
       
   598 			{
       
   599 				if(outputBuffer == "" || outputBuffer.at(bufPos) == ' ' || outputBuffer.at(bufPos) == '\t'
       
   600 					|| int(outputBuffer.at(bufPos)) == 10 )
       
   601 					enmPos++;
       
   602 			}
       
   603 			else
       
   604 				enmPos++;
       
   605 		}
       
   606 		else
       
   607 			enmPos = 0;
       
   608 
       
   609 		if( enmPos == isEnum.length())
       
   610 		{
       
   611 			enmPos = 0;
       
   612 			buf = isEnum;
       
   613 			ignorecheck = true;// in the current iteration don't match buf string with class\enum\struct keyword
       
   614 			                    // as keyword may be part of some word like " enumuration" 
       
   615 		}
       
   616 
       
   617 		if (state == EStateSearching)
       
   618 		{
       
   619 			memset(stackArray,'\0',MAX_ARRAY_COUNT);
       
   620 			if (c == tofind.at(matches))
       
   621 			{
       
   622 				matches++;
       
   623 				toflush += c;
       
   624 			} else 
       
   625 			{
       
   626 				matches = 0;
       
   627 				if (!toflush.empty())
       
   628 				{
       
   629 					outputBuffer += toflush;
       
   630 					toflush = "";
       
   631 				}
       
   632 				outputBuffer += c;
       
   633 				
       
   634 				if(buf.length() > 0 && ignorecheck == false && (c != ' ' && c != '\t' 
       
   635 					&& int(c) != 10 ))
       
   636 				{
       
   637 					buf = "";
       
   638 					arraychar = '\0';
       
   639 				}
       
   640 			}
       
   641 			if (matches == tofind.length())
       
   642 			{
       
   643 				toflush = "";
       
   644 				state = EStateReplacing; // export keyword match found, so make the stae as replacing
       
   645 				matches = 0;
       
   646 			}
       
   647 		} else if (state == EStateReplacing)
       
   648 		{  
       
   649 			// under a exported class,for a function the exported keyword is present,it should be deleted.
       
   650 			if (c == tofind.at(matches))
       
   651 			{
       
   652 				matches++;
       
   653 				toflush += c;
       
   654 				if (matches == tofind.length())
       
   655 				{
       
   656 					toflush = "";
       
   657 					matches = 0;					
       
   658 				}
       
   659 				continue;
       
   660 			} else 
       
   661 			{
       
   662 				matches = 0;
       
   663 				if (!toflush.empty())
       
   664 				{
       
   665 					outputBuffer += toflush;
       
   666 					toflush = "";
       
   667 				}		
       
   668 			}
       
   669 			
       
   670 		
       
   671 			if(c == isInline.at(inlinePos))
       
   672 			{
       
   673 				if( inlinePos == 0 )// searching for inline keyword with space before and after
       
   674 				{
       
   675 					if(outputBuffer == "" || outputBuffer.at(bufPos) == ' ' || outputBuffer.at(bufPos) == '\t'
       
   676 						|| int(outputBuffer.at(bufPos)) == 10 )
       
   677 						inlinePos++;
       
   678 				}
       
   679 				else
       
   680 					inlinePos++;
       
   681 			}		
       
   682 			else
       
   683 				inlinePos = 0;
       
   684 			
       
   685 			if( inlinePos == isInline.length())
       
   686 			{
       
   687 				inlinePos = 0;
       
   688 				buf = isInline;
       
   689 
       
   690 			}
       
   691 
       
   692 			if ( buf.length() > 0 && (c == ' ' || c == '\t' || int(c) == 10))
       
   693 			{
       
   694 				if (buf == isClass)
       
   695 				{
       
   696 					arraychar = 'c';
       
   697 				}
       
   698 				if (buf == isStruct )
       
   699 				{
       
   700 					arraychar = 's';
       
   701 				}
       
   702 				if (buf == isEnum)
       
   703 				{
       
   704 					arraychar = 'e';
       
   705 				}
       
   706 				if(buf == isUnion)
       
   707 				{
       
   708 					arraychar = 'u';
       
   709 				}
       
   710 				if(buf == isInline) 
       
   711 				{
       
   712 					stackArray[arryPos] = 'i'; // place inline keyword in stack
       
   713 					arryPos++;
       
   714 				}
       
   715 				
       
   716 				buf = "";
       
   717 				if(temp.length() > 0) 
       
   718 					temp = "";
       
   719 			}
       
   720 			else if (c == '{')
       
   721 			{
       
   722 				// place the keyword in stack for class\enum\struct
       
   723 				if(arraychar != '\0')
       
   724 				{
       
   725 					stackArray[arryPos] = arraychar;
       
   726 					arraychar = '\0';
       
   727 					arryPos++;
       
   728 				}				
       
   729 				stackArray[arryPos] = c;				
       
   730                 arryPos++;
       
   731 
       
   732 				if(temp.length() > 0) 
       
   733 					temp = "";
       
   734 			}
       
   735 			else if(c== '}')
       
   736 			{
       
   737 				temp = "";
       
   738 				bool ignore = false;
       
   739 				// can be end of class\enum\struct				
       
   740 				for (int i = arryPos-1; i >= 0; i-- )
       
   741 				{
       
   742 
       
   743 					if (stackArray[i] == '{' ) 
       
   744 					{
       
   745 						if( stackArray[i-1] != 'c' && stackArray[i-1] != 's' 
       
   746 							&& stackArray[i-1] != 'e' && stackArray[i-1] != 'u')
       
   747 							// check if the function is inline
       
   748 						{
       
   749 
       
   750 							ignore = true;
       
   751 							break;
       
   752 						}
       
   753 					}
       
   754 				}
       
   755 				if(ignore == false)
       
   756 					temp = c;
       
   757 				
       
   758 				stackArray[arryPos] = c;
       
   759                 arryPos++;
       
   760 
       
   761 				if(temp == "")
       
   762 				{
       
   763 					int openbraceCount = 0;
       
   764 					int closebracecount = 0;
       
   765 
       
   766 					// if it is end of a function then delete the entry from stack
       
   767 					// and it is ofcourse not a exported function, 
       
   768 					//will definitely be a inline function with or without "inline" keyword
       
   769 					bool deleteEntry = false;
       
   770 					int setpos = 0;
       
   771 					// get the pos after class\struct\enum started
       
   772 					for(int i = arryPos; i >= 0; i--)
       
   773 					{
       
   774 						if(stackArray[i] == '{')
       
   775 						{
       
   776 							deleteEntry = true;
       
   777 							if (stackArray[i-1] == 'c' || stackArray[i-1] == 's' 
       
   778 								|| stackArray[i-1] == 'e' || stackArray[i-1] == 'u')
       
   779 							{
       
   780 								setpos = i+1;								
       
   781 								break;
       
   782 							}							
       
   783 						}
       
   784 					}
       
   785 					// find the end pos of the non exported function by matching the open and close flower brace count.
       
   786 					if(deleteEntry)
       
   787 					{
       
   788 						deleteEntry = false;
       
   789 						for(int i = setpos; i <= arryPos; i++ )
       
   790 						{						
       
   791 							if(stackArray[i] == '{')
       
   792 								openbraceCount++;
       
   793 							else if(stackArray[i] == '}')
       
   794 								closebracecount++;
       
   795 						}
       
   796 						if(openbraceCount > 0 && openbraceCount == closebracecount )
       
   797 						{
       
   798 							deleteEntry = true;// need to delete the non exported function entry from stack now
       
   799 						}
       
   800 					}
       
   801 					// noe delete the non exported entry and re arrange the stack
       
   802 					if(deleteEntry)
       
   803 					{
       
   804 						for(int pos = setpos; pos <= arryPos; pos++ )
       
   805 							stackArray[pos] = '\0';
       
   806 
       
   807 						arryPos = setpos;
       
   808 					}
       
   809 				}
       
   810 				
       
   811 			}
       
   812 			else if ( (c == '=' && stackArray[arryPos-1] == ')') ||
       
   813                       (c == '0' && stackArray[arryPos-1] == '=') ||
       
   814 					  (c == '(' || c == ')' )||
       
   815 					  ( possibleVirtualFunc == true ||virtualFunc == true)
       
   816 					 ) // can be a virtual function or normal function which might be exported
       
   817 			{
       
   818 				if(temp.length() > 0) 
       
   819 					temp = "";
       
   820 
       
   821 				if( (possibleVirtualFunc == true && (  c!= '0' && c != ' ' && c != '\t' && int(c) != 10) ) ||
       
   822 					(virtualFunc == true && (c!= ';' && c != ' ' && c != '\t' && int(c) != 10)) )
       
   823 				{ // if other than space and '0', then set posVirtual func to false
       
   824 					// or if other than space and ';', then set Virtual func to false
       
   825 					outputBuffer += flush;
       
   826 					outputBuffer += c;
       
   827 					flush = "";
       
   828 					possibleVirtualFunc = false;
       
   829 					virtualFunc = false;
       
   830 					continue;
       
   831 				}
       
   832 
       
   833 				else if( c == '=') // possible virtual function
       
   834 				{
       
   835 					flush = c;
       
   836 					possibleVirtualFunc = true;
       
   837 					virtualFunc = false;
       
   838 					stackArray[arryPos] = c;
       
   839 					arryPos++;
       
   840 					continue;
       
   841 				}
       
   842 				else if (possibleVirtualFunc == true)
       
   843 				{				
       
   844 					flush += c;
       
   845 					if ( c == '0')
       
   846 					{
       
   847 						virtualFunc = true; // pure virtual function
       
   848 						possibleVirtualFunc = false;
       
   849 						stackArray[arryPos] = c;
       
   850 						arryPos++;
       
   851 					}					
       
   852 					continue;
       
   853 				}
       
   854 				else if (c == '(' || c == ')')
       
   855 				{
       
   856 					flush = "";
       
   857 					stackArray[arryPos] = c;
       
   858 					arryPos++;
       
   859 				}
       
   860 				
       
   861 			} 
       
   862 			
       
   863 			if (c == ';')
       
   864 			{
       
   865 				arraychar = '\0';
       
   866 				// first check for inline function and delete the entry from stack for this func
       
   867 				bool isinline = false;
       
   868 				bool nonExpFun = false;
       
   869 				bool removeEntry = false;
       
   870 
       
   871 				for (int i = arryPos-1; i >= 0; i-- )
       
   872 				{
       
   873 					if ( stackArray[i] == 'i') // inline function with inline keyword
       
   874 						isinline = true;
       
   875 					
       
   876 					else if (stackArray[i] == '{')// check if the function is inline
       
   877 					{
       
   878 						if (stackArray[i-1] != 'c' && stackArray[i-1] != 's' 
       
   879 							  && stackArray[i-1] != 'e' && stackArray[i-1] != 'u')
       
   880 							nonExpFun = true;
       
   881 					}
       
   882 				}
       
   883 
       
   884 				// end of struct/class/enum
       
   885 				if (stackArray[arryPos-1] == '}' && temp == "}"   ) 
       
   886 				{
       
   887 					//if(!isinline && !nonExpFun)
       
   888 					{
       
   889 					int cnt = arryPos-1;
       
   890 					bool flag = false;
       
   891 					for (int i = cnt; i>=0; i--)
       
   892 					{
       
   893 						if (stackArray[i] == 'c' || stackArray[i] == 's' 
       
   894 							   || stackArray[i] == 'e' || stackArray[i] == 'u')
       
   895 						{
       
   896 							flag = true;
       
   897 						}	
       
   898 						stackArray[i] = '\0';		
       
   899 						arryPos--;
       
   900 						if( flag )	
       
   901 						{
       
   902 							break;
       
   903 						}
       
   904 					}
       
   905 					outputBuffer += c;
       
   906 					temp = "";
       
   907 
       
   908 					if(stackArray[0] == '\0') // check if exported class\struct is ended .. 
       
   909 						                      // set state to searching and continue;
       
   910 						state = EStateSearching;
       
   911 					continue;
       
   912 					}
       
   913 				}				
       
   914 				
       
   915 				if(stackArray[arryPos-1] == '('&& nonExpFun == false && isinline == false) 
       
   916 					// not function, can be a for loop, so reset the stackArray ...
       
   917 				{				
       
   918 					outputBuffer += c;
       
   919 					removeEntry = true;
       
   920 				}
       
   921 				else if(stackArray[arryPos-1] == ')'  ) 
       
   922 					// some exported function can be "abcd( xyz(0), pqr(0))"
       
   923 				{	
       
   924 					if( nonExpFun == false && isinline == false )
       
   925 					{
       
   926 						outputBuffer += " ";
       
   927 						outputBuffer += attribstr;
       
   928 					}
       
   929 					outputBuffer += c;	
       
   930 					if (nonExpFun == false)
       
   931 					removeEntry = true;
       
   932 				}			
       
   933 				else if( (stackArray[arryPos-1] == '0' && stackArray[arryPos-2] == '=' && virtualFunc == true) )
       
   934 				{ // can be a virtual function or normal function which is definitely exported
       
   935 					if(!isinline && !nonExpFun)
       
   936 					{
       
   937 						outputBuffer += " ";
       
   938 						outputBuffer += attribstr;
       
   939 						outputBuffer += " ";
       
   940 					}					
       
   941 					outputBuffer += flush;					
       
   942 					outputBuffer += c;
       
   943 					flush = "";
       
   944 					if(nonExpFun == false)
       
   945 						removeEntry = true;
       
   946 					virtualFunc = false;
       
   947 				}
       
   948 				else	
       
   949 				{
       
   950 					outputBuffer += c;
       
   951 				}
       
   952 
       
   953 				if(removeEntry == true)
       
   954 				{
       
   955 					int cnt = arryPos-1;
       
   956 					bool flag = false;
       
   957 					for (int i = cnt; i>=0; i--)
       
   958 					{
       
   959 						if (stackArray[i] == '{' && 
       
   960 							(stackArray[i-1] == 'c' || stackArray[i-1] == 's' 
       
   961 							|| stackArray[i-1] == 'e' || stackArray[i-1] == 'u') )
       
   962 							flag = true;
       
   963 
       
   964 						if(flag == false)
       
   965 						{
       
   966 							stackArray[i] = '\0';	
       
   967 							arryPos--;
       
   968 						}
       
   969 					}
       
   970 				}
       
   971 	
       
   972 				if(stackArray[0] == '\0')
       
   973 					state = EStateSearching;				
       
   974 			} 
       
   975 			else
       
   976 			{
       
   977 				if(  virtualFunc == true )
       
   978 				{
       
   979 					outputBuffer += flush;					
       
   980 					flush = "";
       
   981                     virtualFunc = false;
       
   982 				}
       
   983 				outputBuffer += c;
       
   984 			}
       
   985 		} else if (state == EStateReplaceDone)
       
   986 		{
       
   987 
       
   988 		}
       
   989 
       
   990 	}
       
   991 	if (outputBuffer.length() != 0)
       
   992 	{
       
   993 		output << outputBuffer;
       
   994 	}
       
   995 	return ret;
       
   996 }
   586 
   997 
   587 // ----------------------------------------------------------------------------
   998 // ----------------------------------------------------------------------------
   588 // CPPParser::ReplaceExport
   999 // CPPParser::ReplaceExport
   589 // ----------------------------------------------------------------------------
  1000 // ----------------------------------------------------------------------------
   590 //
  1001 //