diff options
| author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 | 
|---|---|---|
| committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 | 
| commit | 114a878c64ce6f8223cfd22d76a20eb16d177e5e (patch) | |
| tree | acaf47eb0fa12142d3896416a69e74cbf5a72242 /lib/astyle/ASEnhancer.cpp | |
| download | tdevelop-114a878c64ce6f8223cfd22d76a20eb16d177e5e.tar.gz tdevelop-114a878c64ce6f8223cfd22d76a20eb16d177e5e.zip | |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdevelop@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'lib/astyle/ASEnhancer.cpp')
| -rw-r--r-- | lib/astyle/ASEnhancer.cpp | 483 | 
1 files changed, 483 insertions, 0 deletions
| diff --git a/lib/astyle/ASEnhancer.cpp b/lib/astyle/ASEnhancer.cpp new file mode 100644 index 00000000..6fea5970 --- /dev/null +++ b/lib/astyle/ASEnhancer.cpp @@ -0,0 +1,483 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + *   ASEnhancer.cpp + * + *   This file is a part of "Artistic Style" - an indentation and + *   reformatting tool for C, C++, C# and Java source files. + *   http://astyle.sourceforge.net + * + *   The "Artistic Style" project, including all files needed to + *   compile it, is free software; you can redistribute it and/or + *   modify it under the terms of the GNU Lesser General Public + *   License as published by the Free Software Foundation; either + *   version 2.1 of the License, or (at your option) any later + *   version. + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU Lesser General Public License for more details. + * + *   You should have received a copy of the GNU Lesser General Public + *   License along with this project; if not, write to the + *   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + *   Boston, MA  02110-1301, USA. + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + */ + +// can trace only if NDEBUG is not defined +#ifndef NDEBUG +// #define TRACEswitch +// #define TRACEcase +// #define TRACEmisc +#endif + +#include "astyle.h" + +#include <iostream> +#include <fstream> +#include <sstream> + +#ifdef TRACEswitch +#define TRswitch(a,b)   *traceOut << lineNumber << a << b << endl; +#else +#define TRswitch(a,b)   ((void)0) +#endif // TRACEswitch +#ifdef TRACEcase +#define TRcase(a,b)     *traceOut << lineNumber << a << b << endl; +#else +#define TRcase(a,b)     ((void)0) +#endif // TRACEcase +#ifdef TRACEmisc +#define TRmisc(a)       *traceOut << lineNumber << a << endl; +#else +#define TRmisc(a)       ((void)0) +#endif // TRACEmisc + + +namespace astyle +{ + +// ---------------------------- functions for ASEnhancer Class ------------------------------------- + +/** + * ASEnhancer constructor + */ +ASEnhancer::ASEnhancer() +{ +	// variables are initialized by init() +	traceOut = new stringstream; +} + +/** + * Destructor of ASEnhancer + * Display the TRACE entries. + */ +ASEnhancer::~ASEnhancer() +{ +#if defined(TRACEswitch) || defined(TRACEcase) || defined(TRACEmisc) +	string line; +	string msg = "TRACE Entries\n\n"; +	char countLine[50]; +	int count = 0; + +	while (getline(*traceOut, line)) +	{ +		msg += line + '\n'; +		count++; +	} +	sprintf(countLine, "\n%d Entries", count); +	msg += countLine; +	// write a text file to "My Documents" (Windows) +	char filename [_MAX_PATH + _MAX_FNAME + _MAX_EXT + 1];   // full path and filename +	strcpy(filename, getenv("USERPROFILE")); +	strcat(filename, "\\My Documents\\tracee.txt"); +	ofstream outfile(filename); +	outfile << msg; +	outfile.close(); +#endif +	delete traceOut; +} + +/** + * initialize the ASEnhancer. + * + * init() is called each time an ASFormatter object is initialized. + */ +void ASEnhancer::init(int _indentLength, +                      string _indentString, +                      bool _isCStyle, +                      bool _isJavaStyle, +                      bool _isSharpStyle, +                      bool _caseIndent, +                      bool _emptyLineFill) +{ +	// formatting variables from ASFormatter and ASBeautifier +	indentLength = _indentLength; +	if (_indentString.compare(0, 1, "\t") == 0) +		useTabs = true; +	else +		useTabs = false; +	isCStyle      = _isCStyle; +	isJavaStyle   = _isJavaStyle; +	isSharpStyle  = _isSharpStyle; +	caseIndent    = _caseIndent; +	emptyLineFill = _emptyLineFill; + +	// unindent variables +	lineNumber = 0; +	bracketCount = 0; +	isInComment = false; +	isInQuote = false; +	switchDepth = 0; +	lookingForCaseBracket = false; +	unindentNextLine = false; + +#if defined(TRACEswitch) || defined(TRACEcase) || defined(TRACEmisc) +	*traceOut << "New file -------------" << endl; +#endif +} + +/** + * additional formatting for line of source code. + * every line of source code in a source code file should be sent + *     one after the other to this function. + * indents event tables + * unindents the case blocks + * + * @param line       the original formatted line will be updated if necessary. + */ +void ASEnhancer::enhance(string &line) +{ +	static vector<switchVariables>  swVector;       // stack vector of switch variables +	static switchVariables sw;                      // switch variables struct + +	static bool nextLineIsEventTable;				// begin event table is reached +	static bool isInEventTable;						// need to indent an event table + +	bool   isSpecialChar = false; +	size_t  lineLength;                             // length of the line being parsed + +	lineNumber++; +	lineLength = line.length(); + +	// check for beginning of event table +	if (nextLineIsEventTable) +	{ +		isInEventTable = true; +		nextLineIsEventTable = false; +	} + +	if (lineLength == 0 +	        && ! isInEventTable +	        && ! emptyLineFill) +		return; + +	// test for unindent on attached brackets +	if (unindentNextLine) +	{ +		sw.unindentDepth++; +		sw.unindentCase = true; +		unindentNextLine = false; +		TRcase(" unindent case ", sw.unindentDepth); +	} + +	// parse characters in the current line. + +	for (size_t i = 0; i < lineLength; i++) +	{ +		char ch = line[i]; + +		// bypass whitespace +		if (isWhiteSpaceX(ch)) +			continue; + +		// handle special characters (i.e. backslash+character such as \n, \t, ...) +		if (isSpecialChar) +		{ +			isSpecialChar = false; +			continue; +		} +		if (!(isInComment) && line.compare(i, 2, "\\\\") == 0) +		{ +			i++; +			continue; +		} +		if (!(isInComment) && ch == '\\') +		{ +			isSpecialChar = true; +			continue; +		} + +		// handle quotes (such as 'x' and "Hello Dolly") +		if (!(isInComment) && (ch == '"' || ch == '\'')) +			if (!isInQuote) +			{ +				quoteChar = ch; +				isInQuote = true; +			} +			else if (quoteChar == ch) +			{ +				isInQuote = false; +				continue; +			} + +		if (isInQuote) +			continue; + +		// handle comments + +		if (!(isInComment) && line.compare(i, 2, "//") == 0) +		{ +			// check for windows line markers +			if (line.compare(i + 2, 1, "\xf0") > 0) +				lineNumber--; +			break;                 // finished with the line +		} +		else if (!(isInComment) && line.compare(i, 2, "/*") == 0) +		{ +			isInComment = true; +			i++; +			continue; +		} +		else if ((isInComment) && line.compare(i, 2, "*/") == 0) +		{ +			isInComment = false; +			i++; +			continue; +		} + +		if (isInComment) +			continue; + +		// if we have reached this far then we are NOT in a comment or string of special characters + +		if (line[i] == '{')                                 // if open bracket +			bracketCount++; + +		if (line[i] == '}')                     // if close bracket +			bracketCount--; + +		// ----------------  process event tables  -------------------------------------- + +		// check for event table begin +		if (findKeyword(line, i, "BEGIN_EVENT_TABLE") +		        || findKeyword(line, i, "BEGIN_MESSAGE_MAP")) +			nextLineIsEventTable = true; + +		// check for event table end +		if (findKeyword(line, i, "END_EVENT_TABLE") +		        || findKeyword(line, i, "END_MESSAGE_MAP")) +			isInEventTable = false; + +		// ----------------  process switch statements  --------------------------------- + +		if (findKeyword(line, i, "switch"))                 // if switch statement +		{ +			switchDepth++;                                  // bump switch depth +			TRswitch(" switch ", switchDepth); +			swVector.push_back(sw);                         // save current variables +			sw.switchBracketCount = 0; +			sw.unindentCase = false;                        // don't clear case until end of switch +			i += 5;                                         // bypass switch statement +			continue; +		} + +		// just want switch statements from this point + +		if (caseIndent || switchDepth == 0)                 // from here just want switch statements +			continue;                                      // get next char + +		if (line[i] == '{')                                 // if open bracket +		{ +			sw.switchBracketCount++; +			if (lookingForCaseBracket)                      // if 1st after case statement +			{ +				sw.unindentCase = true;                     // unindenting this case +				sw.unindentDepth++;                         // bump depth +				lookingForCaseBracket = false;              // not looking now +				TRcase(" unindent case ", sw.unindentDepth); +			} +			continue; +		} + +		lookingForCaseBracket = false;                      // no opening bracket, don't indent + +		if (line[i] == '}')                                 // if close bracket +		{ +			sw.switchBracketCount--; +			if (sw.switchBracketCount == 0)                 // if end of switch statement +			{ +				TRswitch("  endsw ", switchDepth); +				switchDepth--;                              // one less switch +				sw = swVector.back();                       // restore sw struct +				swVector.pop_back();                        // remove last entry from stack +			} +			continue; +		} + +		// look for case or default header + +		if (findKeyword(line, i, "case") || findKeyword(line, i, "default")) +		{ +			if (sw.unindentCase)                            // if unindented last case +			{ +				sw.unindentCase = false;                    // stop unindenting previous case +				sw.unindentDepth--;                         // reduce depth +			} +			for (; i < lineLength; i++)                     // bypass colon +			{ +				if (line[i] == ':') +					if ((i + 1 < lineLength) && (line[i + 1] == ':')) +						i++;								// bypass scope resolution operator +					else +						break; +			} +			i++; +			for (; i < lineLength; i++)                     // bypass whitespace +			{ +				if (!(isWhiteSpaceX(line[i]))) +					break; +			} +			if (i < lineLength)                             // check for bracket +			{ +				if (line[i] == '{')                         // if bracket found +				{ +					sw.switchBracketCount++; +					unindentNextLine = true;                // start unindenting on next line +					continue; +				} +			} +			lookingForCaseBracket = true;                   // bracket must be on next line +			i--;                                            // need to check for comments +			continue; +		} +	}   // end of for loop + +	if (isInEventTable) 									// if need to indent +		indentLine(line, 1);               					//    do it + +	if (sw.unindentDepth > 0)                               // if need to unindent +		unindentLine(line, sw.unindentDepth);               //    do it +} + +/** + * indent a line by a given number of tabsets + *    by inserting leading whitespace to the line argument. + * + * @param line          a pointer to the line to indent. + * @param unindent      the number of tabsets to insert. + * @return              the number of characters inserted. + */ +int ASEnhancer::indentLine(string  &line, const int indent) const +{ +	if (line.length() == 0 +	        && ! emptyLineFill) +		return 0; + +	size_t charsToInsert;                   	// number of chars to insert + +	if (useTabs)                    			// if formatted with tabs +	{ +		charsToInsert = indent;             	// tabs to insert +		line.insert((size_t) 0, charsToInsert, '\t');    // insert the tabs +	} +	else +	{ +		charsToInsert = indent * indentLength;  // compute chars to insert +		line.insert((size_t)0, charsToInsert, ' ');     // insert the spaces +	} + +	return charsToInsert; +} + +/** + * unindent a line by a given number of tabsets + *    by erasing the leading whitespace from the line argument. + * + * @param line          a pointer to the line to unindent. + * @param unindent      the number of tabsets to erase. + * @return              the number of characters erased. + */ +int ASEnhancer::unindentLine(string  &line, const int unindent) const +{ +	size_t whitespace = line.find_first_not_of(" \t"); + +	if (whitespace == string::npos)         // if line is blank +		whitespace = line.length();         // must remove padding, if any + +	if (whitespace == 0) +		return 0; + +	size_t charsToErase;                    // number of chars to erase + +	if (useTabs)                    		// if formatted with tabs +	{ +		charsToErase = unindent;            // tabs to erase +		if (charsToErase <= whitespace)     // if there is enough whitespace +			line.erase(0, charsToErase);    // erase the tabs +		else +			charsToErase = 0; +	} +	else +	{ +		charsToErase = unindent * indentLength; // compute chars to erase +		if (charsToErase <= whitespace)         // if there is enough whitespace +			line.erase(0, charsToErase);        // erase the spaces +		else +			charsToErase = 0; +	} + +	return charsToErase; +} + +/** + * check if a specific line position contains a keyword. + * + * @return    true if the word was found. false if the word was not found. + */ +bool ASEnhancer::findKeyword(const string &line, int i, const char *keyword) const +{ +	if (line.compare(i, strlen(keyword), keyword) == 0) +	{ +		// check that this is a header and not a part of a longer word +		// (e.g. not at its begining, not at its middle...) + +		int lineLength = line.length(); +		int wordEnd = i + strlen(keyword); +		char startCh = keyword[0];      // first char of header +		char endCh = 0;                // char just after header +		char prevCh = 0;               // char just before header + +		if (wordEnd < lineLength) +		{ +			endCh = line[wordEnd]; +		} +		if (i > 0) +		{ +			prevCh = line[i-1]; +		} + +		if (prevCh != 0 +		        && isLegalNameCharX(startCh) +		        && isLegalNameCharX(prevCh)) +		{ +			return false; +		} +		else if (wordEnd >= lineLength +		         || !isLegalNameCharX(startCh) +		         || !isLegalNameCharX(endCh)) +		{ +			return true; +		} +		else +		{ +			return false; +		} +	} + +	return false; +} + +}   // end namespace astyle | 
