1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  *
3  *   ASBeautifier.cpp
4  *
5  *   This file is a part of "Artistic Style" - an indentation and
6  *   reformatting tool for C, C++, C# and Java source files.
7  *   http://astyle.sourceforge.net
8  *
9  *   The "Artistic Style" project, including all files needed to
10  *   compile it, is free software; you can redistribute it and/or
11  *   modify it under the terms of the GNU Lesser General Public
12  *   License as published by the Free Software Foundation; either
13  *   version 2.1 of the License, or (at your option) any later
14  *   version.
15  *
16  *   This program is distributed in the hope that it will be useful,
17  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *   GNU Lesser General Public License for more details.
20  *
21  *   You should have received a copy of the GNU Lesser General Public
22  *   License along with this project; if not, write to the
23  *   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  *   Boston, MA  02110-1301, USA.
25  *
26  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
27  */
28 
29  /*
30  	2008-01-26 Patches by Massimo Del Fedele :
31  		- modified sources to use Ultimate++ containers instead std:: ones
32  		- fixed memory leaks based on bug report 1804791 submitted by Eran Ifrah
33  		- modified to work with unicode
34  */
35 #include "astyle.h"
36 
37 
38 #define INIT_CONTAINER(container, value)     {if ( (container) != NULL ) delete (container); (container) = (value); }
39 #define DELETE_CONTAINER(container)          {if ( (container) != NULL ) delete (container); }
40 
41 
42 namespace astyle
43 {
44 Vector<const WString*> ASBeautifier::headers;
45 Vector<const WString*> ASBeautifier::nonParenHeaders;
46 Vector<const WString*> ASBeautifier::preBlockStatements;
47 Vector<const WString*> ASBeautifier::assignmentOperators;
48 Vector<const WString*> ASBeautifier::nonAssignmentOperators;
49 
50 
51 /*
52  * initialize the static vars
53  */
initStatic()54 void ASBeautifier::initStatic()
55 {
56 	static int beautifierFileType = 9;     // initialized with an invalid type
57 
58 	if (fileType == beautifierFileType)    // don't build unless necessary
59 		return;
60 
61 	beautifierFileType = fileType;
62 
63 	headers.clear();
64 	nonParenHeaders.clear();
65 	assignmentOperators.clear();
66 	nonAssignmentOperators.clear();
67 	preBlockStatements.clear();
68 
69 	ASResource::buildHeaders(headers, fileType, true);
70 	ASResource::buildNonParenHeaders(nonParenHeaders, fileType, true);
71 	ASResource::buildAssignmentOperators(assignmentOperators);
72 	ASResource::buildNonAssignmentOperators(nonAssignmentOperators);
73 	ASResource::buildPreBlockStatements(preBlockStatements);
74 
75 //	cout << "beaut" << endl;
76 }
77 
78 /**
79  * ASBeautifier's constructor
80  */
ASBeautifier()81 ASBeautifier::ASBeautifier()
82 {
83 	waitingBeautifierStack = NULL;
84 	activeBeautifierStack = NULL;
85 	waitingBeautifierStackLengthStack = NULL;
86 	activeBeautifierStackLengthStack = NULL;
87 
88 	headerStack  = NULL;
89 	tempStacks = NULL;
90 	blockParenDepthStack = NULL;
91 	blockStatementStack = NULL;
92 	parenStatementStack = NULL;
93 	bracketBlockStateStack = NULL;
94 	inStatementIndentStack = NULL;
95 	inStatementIndentStackSizeStack = NULL;
96 	parenIndentStack = NULL;
97 	sourceIterator = NULL;
98 
99 	isMinimalConditinalIndentSet = false;
100 	shouldForceTabIndentation = false;
101 
102 	setSpaceIndentation(4);
103 	setMaxInStatementIndentLength(40);
104 	setClassIndent(false);
105 	setSwitchIndent(false);
106 	setCaseIndent(false);
107 	setBlockIndent(false);
108 	setBracketIndent(false);
109 	setNamespaceIndent(false);
110 	setLabelIndent(false);
111 	setEmptyLineFill(false);
112 	fileType = C_TYPE;
113 	setCStyle();
114 	setPreprocessorIndent(false);
115 }
116 
117 /**
118  * ASBeautifier's copy constructor
119  */
ASBeautifier(const ASBeautifier & other)120 ASBeautifier::ASBeautifier(const ASBeautifier &other)
121 {
122 	waitingBeautifierStack = NULL;
123 	activeBeautifierStack = NULL;
124 	waitingBeautifierStackLengthStack = NULL;
125 	activeBeautifierStackLengthStack = NULL;
126 
127 	headerStack  = new WithDeepCopy<Vector<const WString*> >;
128 	*headerStack <<= *other.headerStack;
129 
130 	tempStacks = new WithDeepCopy<Vector<Vector<const WString*>*> >;
131 	WithDeepCopy<Vector<Vector<const WString*>*> >::iterator iter;
132 	for (iter = other.tempStacks->begin();
133 	        iter != other.tempStacks->end();
134 	        ++iter)
135 	{
136 		WithDeepCopy<Vector<const WString*> > *newVec = new WithDeepCopy<Vector<const WString*> >;
137 		*newVec = **iter;
138 		tempStacks->push_back(newVec);
139 	}
140 	blockParenDepthStack = new WithDeepCopy<Vector<int> >;
141 	*blockParenDepthStack = *other.blockParenDepthStack;
142 
143 	blockStatementStack = new WithDeepCopy<Vector<bool> >;
144 	*blockStatementStack = *other.blockStatementStack;
145 
146 	parenStatementStack =  new WithDeepCopy<Vector<bool> >;
147 	*parenStatementStack = *other.parenStatementStack;
148 
149 	bracketBlockStateStack = new WithDeepCopy<Vector<bool> >;
150 	*bracketBlockStateStack = *other.bracketBlockStateStack;
151 
152 	inStatementIndentStack = new WithDeepCopy<Vector<int> >;
153 	*inStatementIndentStack = *other.inStatementIndentStack;
154 
155 	inStatementIndentStackSizeStack = new WithDeepCopy<Vector<int> >;
156 	*inStatementIndentStackSizeStack = *other.inStatementIndentStackSizeStack;
157 
158 	parenIndentStack = new WithDeepCopy<Vector<int> >;
159 	*parenIndentStack = *other.parenIndentStack;
160 
161 	sourceIterator = other.sourceIterator;
162 
163 	// protected variables
164 	fileType = other.fileType;
165 	isCStyle = other.isCStyle;
166 	isJavaStyle = other.isJavaStyle;
167 	isSharpStyle = other.isSharpStyle;
168 
169 	// variables set by ASFormatter
170 	// must also be updated in preprocessor
171 	inLineNumber = other.inLineNumber;
172 	outLineNumber = other.outLineNumber;
173 	lineCommentNoBeautify = other.lineCommentNoBeautify;
174 	isNonInStatementArray = other.isNonInStatementArray;
175 
176 	// private variables
177 	indentString = other.indentString;
178 	currentHeader = other.currentHeader;
179 	previousLastLineHeader = other.previousLastLineHeader;
180 	immediatelyPreviousAssignmentOp = other.immediatelyPreviousAssignmentOp;
181 	probationHeader = other.probationHeader;
182 	isInQuote = other.isInQuote;
183 	isInComment = other.isInComment;
184 	isInCase = other.isInCase;
185 	isInQuestion = other.isInQuestion;
186 	isInStatement = other.isInStatement;
187 	isInHeader = other.isInHeader;
188 	isInOperator = other.isInOperator;
189 	isInTemplate = other.isInTemplate;
190 	isInDefine = other.isInDefine;
191 	isInDefineDefinition = other.isInDefineDefinition;
192 	classIndent = other.classIndent;
193 	isInClassHeader = other.isInClassHeader;
194 	isInClassHeaderTab = other.isInClassHeaderTab;
195 	switchIndent = other.switchIndent;
196 	caseIndent = other.caseIndent;
197 	namespaceIndent = other.namespaceIndent;
198 	bracketIndent = other.bracketIndent;
199 	blockIndent = other.blockIndent;
200 	labelIndent = other.labelIndent;
201 	preprocessorIndent = other.preprocessorIndent;
202 	isInConditional = other.isInConditional;
203 	isMinimalConditinalIndentSet = other.isMinimalConditinalIndentSet;
204 	shouldForceTabIndentation = other.shouldForceTabIndentation;
205 	emptyLineFill = other.emptyLineFill;
206 	backslashEndsPrevLine = other.backslashEndsPrevLine;
207 	blockCommentNoIndent = other.blockCommentNoIndent;
208 	blockCommentNoBeautify = other.blockCommentNoBeautify;
209 	previousLineProbationTab = other.previousLineProbationTab;
210 	minConditionalIndent = other.minConditionalIndent;
211 	parenDepth = other.parenDepth;
212 	indentLength = other.indentLength;
213 	blockTabCount = other.blockTabCount;
214 	leadingWhiteSpaces = other.leadingWhiteSpaces;
215 	maxInStatementIndent = other.maxInStatementIndent;
216 	templateDepth = other.templateDepth;
217 	prevFinalLineSpaceTabCount = other.prevFinalLineSpaceTabCount;
218 	prevFinalLineTabCount = other.prevFinalLineTabCount;
219 	defineTabCount = other.defineTabCount;
220 	quoteChar = other.quoteChar;
221 	prevNonSpaceCh = other.prevNonSpaceCh;
222 	currentNonSpaceCh = other.currentNonSpaceCh;
223 	currentNonLegalCh = other.currentNonLegalCh;
224 	prevNonLegalCh = other.prevNonLegalCh;
225 }
226 
227 /**
228  * ASBeautifier's destructor
229  */
~ASBeautifier()230 ASBeautifier::~ASBeautifier()
231 {
232 	DELETE_CONTAINER(headerStack);
233 	DELETE_CONTAINER(blockParenDepthStack);
234 	DELETE_CONTAINER(blockStatementStack);
235 	DELETE_CONTAINER(parenStatementStack);
236 	DELETE_CONTAINER(bracketBlockStateStack);
237 	DELETE_CONTAINER(inStatementIndentStack);
238 	DELETE_CONTAINER(inStatementIndentStackSizeStack);
239 	DELETE_CONTAINER(parenIndentStack);
240 
241 	//this two were missing...
242 	DELETE_CONTAINER(waitingBeautifierStackLengthStack);
243 	DELETE_CONTAINER(activeBeautifierStackLengthStack);
244 
245 	//the correct way to release tempStacks, waitingBeautifierStack and activeBeautifierStack
246 	if(tempStacks)
247 	{
248 		Vector< Vector<const WString*>* >::iterator iter = tempStacks->begin();
249 		for(; iter != tempStacks->end(); iter++)
250 			delete *iter;
251 		tempStacks->clear();
252 		delete tempStacks;
253 		tempStacks = NULL;
254 	}
255 
256 	if(waitingBeautifierStack)
257 	{
258 		Vector<ASBeautifier*>::iterator iter = waitingBeautifierStack->begin();
259 		for(; iter != waitingBeautifierStack->end(); iter++)
260 			delete *iter;
261 		waitingBeautifierStack->clear();
262 		delete waitingBeautifierStack;
263 		waitingBeautifierStack = NULL;
264 	}
265 
266 	if(activeBeautifierStack)
267 	{
268 		Vector<ASBeautifier*>::iterator iter = activeBeautifierStack->begin();
269 		for(; iter != activeBeautifierStack->end(); iter++)
270 			delete *iter;
271 		activeBeautifierStack->clear();
272 		delete activeBeautifierStack;
273 		activeBeautifierStack = NULL;
274 	}
275 }
276 
277 /**
278  * initialize the ASBeautifier.
279  *
280  * init() should be called every time a ABeautifier object is to start
281  * beautifying a NEW source file.
282  * init() recieves a pointer to a DYNAMICALLY CREATED ASSourceIterator object
283  * that will be used to iterate through the source code. This object will be
284  * deleted during the ASBeautifier's destruction, and thus should not be
285  * deleted elsewhere.
286  *
287  * @param iter     a pointer to the DYNAMICALLY CREATED ASSourceIterator object.
288  */
init(ASSourceIterator * iter)289 void ASBeautifier::init(ASSourceIterator *iter)
290 {
291 	sourceIterator = iter;
292 	init();
293 }
294 
295 /**
296  * initialize the ASBeautifier.
297  */
init()298 void ASBeautifier::init()
299 {
300 	initStatic();
301 
302 	INIT_CONTAINER(waitingBeautifierStack,  new Vector<ASBeautifier*>);
303 	INIT_CONTAINER(activeBeautifierStack,  new Vector<ASBeautifier*>);
304 
305 	INIT_CONTAINER(waitingBeautifierStackLengthStack, new Vector<int>);
306 	INIT_CONTAINER(activeBeautifierStackLengthStack, new Vector<int>);
307 
308 	INIT_CONTAINER(headerStack,  new WithDeepCopy<Vector<const WString*> >);
309 	INIT_CONTAINER(tempStacks, new WithDeepCopy<Vector<Vector<const WString*>*> >);
310 	tempStacks->push_back(new Vector<const WString*>);
311 
312 	INIT_CONTAINER(blockParenDepthStack, new WithDeepCopy<Vector<int> >);
313 	INIT_CONTAINER(blockStatementStack, new WithDeepCopy<Vector<bool> >);
314 	INIT_CONTAINER(parenStatementStack, new WithDeepCopy<Vector<bool> >);
315 
316 	INIT_CONTAINER(bracketBlockStateStack, new WithDeepCopy<Vector<bool> >);
317 	bracketBlockStateStack->push_back(true);
318 
319 	INIT_CONTAINER(inStatementIndentStack, new WithDeepCopy<Vector<int> >);
320 	INIT_CONTAINER(inStatementIndentStackSizeStack, new WithDeepCopy<Vector<int> >);
321 	inStatementIndentStackSizeStack->push_back(0);
322 	INIT_CONTAINER(parenIndentStack, new WithDeepCopy<Vector<int> >);
323 
324 	immediatelyPreviousAssignmentOp = NULL;
325 	previousLastLineHeader = NULL;
326 	currentHeader = NULL;
327 
328 	isInQuote = false;
329 	isInComment = false;
330 	isInStatement = false;
331 	isInCase = false;
332 	isInQuestion = false;
333 	isInClassHeader = false;
334 	isInClassHeaderTab = false;
335 	isInHeader = false;
336 	isInOperator = false;
337 	isInTemplate = false;
338 	isInConditional = false;
339 	templateDepth = 0;
340 	parenDepth = 0;
341 	blockTabCount = 0;
342 	leadingWhiteSpaces = 0;
343 	prevNonSpaceCh = '{';
344 	currentNonSpaceCh = '{';
345 	prevNonLegalCh = '{';
346 	currentNonLegalCh = '{';
347 	quoteChar = ' ';
348 	prevFinalLineSpaceTabCount = 0;
349 	prevFinalLineTabCount = 0;
350 	probationHeader = NULL;
351 	backslashEndsPrevLine = false;
352 	isInDefine = false;
353 	isInDefineDefinition = false;
354 	defineTabCount = 0;
355 	lineCommentNoBeautify = false;
356 	blockCommentNoIndent = false;
357 	blockCommentNoBeautify = false;
358 	previousLineProbationTab = false;
359 	isNonInStatementArray = false;
360 	inLineNumber = -1;           // for debugging
361 	outLineNumber = 0;           // for debugging
362 }
363 
364 /**
365  * set indentation style to C/C++.
366  */
setCStyle()367 void ASBeautifier::setCStyle()
368 {
369 	fileType = C_TYPE;
370 	isCStyle     = true;
371 	isJavaStyle  = false;
372 	isSharpStyle = false;
373 }
374 
375 /**
376  * set indentation style to Java.
377  */
setJavaStyle()378 void ASBeautifier::setJavaStyle()
379 {
380 	fileType = JAVA_TYPE;
381 	isJavaStyle  = true;
382 	isCStyle     = false;
383 	isSharpStyle = false;
384 }
385 
386 /**
387  * set indentation style to C#.
388  */
setSharpStyle()389 void ASBeautifier::setSharpStyle()
390 {
391 	fileType = SHARP_TYPE;
392 	isSharpStyle = true;
393 	isCStyle     = false;
394 	isJavaStyle  = false;
395 }
396 
397 /**
398  * indent using one tab per indentation
399  */
setTabIndentation(int length,bool forceTabs)400 void ASBeautifier::setTabIndentation(int length, bool forceTabs)
401 {
402 	indentString = "\t";
403 	indentLength = length;
404 	shouldForceTabIndentation = forceTabs;
405 
406 	if (!isMinimalConditinalIndentSet)
407 		minConditionalIndent = indentLength * 2;
408 }
409 
410 /**
411  * indent using a number of spaces per indentation.
412  *
413  * @param   length     number of spaces per indent.
414  */
setSpaceIndentation(int length)415 void ASBeautifier::setSpaceIndentation(int length)
416 {
417 	indentString = WString(' ', length);
418 	indentLength = length;
419 
420 	if (!isMinimalConditinalIndentSet)
421 		minConditionalIndent = indentLength * 2;
422 }
423 
424 /**
425  * set the maximum indentation between two lines in a multi-line statement.
426  *
427  * @param   max     maximum indentation length.
428  */
setMaxInStatementIndentLength(int max)429 void ASBeautifier::setMaxInStatementIndentLength(int max)
430 {
431 	maxInStatementIndent = max;
432 }
433 
434 /**
435  * set the minimum indentation between two lines in a multi-line condition.
436  *
437  * @param   min     minimal indentation length.
438  */
setMinConditionalIndentLength(int min)439 void ASBeautifier::setMinConditionalIndentLength(int min)
440 {
441 	minConditionalIndent = min;
442 	isMinimalConditinalIndentSet = true;
443 }
444 
445 /**
446  * set the state of the bracket indentation option. If true, brackets will
447  * be indented one additional indent.
448  *
449  * @param   state             state of option.
450  */
setBracketIndent(bool state)451 void ASBeautifier::setBracketIndent(bool state)
452 {
453 	bracketIndent = state;
454 }
455 
456 /**
457  * set the state of the block indentation option. If true, entire blocks
458  * will be indented one additional indent, similar to the GNU indent style.
459  *
460  * @param   state             state of option.
461  */
setBlockIndent(bool state)462 void ASBeautifier::setBlockIndent(bool state)
463 {
464 	if (state)
465 		setBracketIndent(false); // so that we don't have both bracket and block indent
466 	blockIndent = state;
467 }
468 
469 /**
470  * set the state of the class indentation option. If true, C++ class
471  * definitions will be indented one additional indent.
472  *
473  * @param   state             state of option.
474  */
setClassIndent(bool state)475 void ASBeautifier::setClassIndent(bool state)
476 {
477 	classIndent = state;
478 }
479 
480 /**
481  * set the state of the switch indentation option. If true, blocks of 'switch'
482  * statements will be indented one additional indent.
483  *
484  * @param   state             state of option.
485  */
setSwitchIndent(bool state)486 void ASBeautifier::setSwitchIndent(bool state)
487 {
488 	switchIndent = state;
489 }
490 
491 /**
492  * set the state of the case indentation option. If true, lines of 'case'
493  * statements will be indented one additional indent.
494  *
495  * @param   state             state of option.
496  */
setCaseIndent(bool state)497 void ASBeautifier::setCaseIndent(bool state)
498 {
499 	caseIndent = state;
500 }
501 
502 /**
503  * set the state of the namespace indentation option.
504  * If true, blocks of 'namespace' statements will be indented one
505  * additional indent. Otherwise, NO indentation will be added.
506  *
507  * @param   state             state of option.
508  */
setNamespaceIndent(bool state)509 void ASBeautifier::setNamespaceIndent(bool state)
510 {
511 	namespaceIndent = state;
512 }
513 
514 /**
515  * set the state of the label indentation option.
516  * If true, labels will be indented one indent LESS than the
517  * current indentation level.
518  * If false, labels will be flushed to the left with NO
519  * indent at all.
520  *
521  * @param   state             state of option.
522  */
setLabelIndent(bool state)523 void ASBeautifier::setLabelIndent(bool state)
524 {
525 	labelIndent = state;
526 }
527 
528 /**
529  * set the state of the preprocessor indentation option.
530  * If true, multiline #define statements will be indented.
531  *
532  * @param   state             state of option.
533  */
setPreprocessorIndent(bool state)534 void ASBeautifier::setPreprocessorIndent(bool state)
535 {
536 	preprocessorIndent = state;
537 }
538 
539 /**
540  * set the state of the empty line fill option.
541  * If true, empty lines will be filled with the whitespace.
542  * of their previous lines.
543  * If false, these lines will remain empty.
544  *
545  * @param   state             state of option.
546  */
setEmptyLineFill(bool state)547 void ASBeautifier::setEmptyLineFill(bool state)
548 {
549 	emptyLineFill = state;
550 }
551 
552 /**
553  * get the number of spaces per indent
554  *
555  * @return   value of indentLength option.
556 */
getIndentLength(void)557 int ASBeautifier::getIndentLength(void)
558 {
559 	return indentLength;
560 }
561 
562 /**
563  * get the char used for indentation, space or tab
564   *
565  * @return   the char used for indentation.
566  */
getIndentString(void)567 WString ASBeautifier::getIndentString(void)
568 {
569 	return indentString;
570 }
571 
572 /**
573  * get the state of the case indentation option. If true, lines of 'case'
574  * statements will be indented one additional indent.
575  *
576  * @return   state of caseIndent option.
577  */
getCaseIndent(void)578 bool ASBeautifier::getCaseIndent(void)
579 {
580 	return caseIndent;
581 }
582 
583 /**
584  * get C style identifier.
585  * If true, a C source is being indented.
586  *
587  * @return   state of isCStyle option.
588  */
getCStyle(void)589 bool ASBeautifier::getCStyle(void)
590 {
591 	return isCStyle;
592 }
593 
594 /**
595  * get Java style identifier.
596  * If true, a Java source is being indented.
597  *
598  * @return   state of isJavaStyle option.
599  */
getJavaStyle(void)600 bool ASBeautifier::getJavaStyle(void)
601 {
602 	return isJavaStyle;
603 }
604 
605 /**
606  * get C# style identifier.
607  * If true, a C# source is being indented.
608  *
609  * @return   state of isSharpStyle option.
610  */
getSharpStyle(void)611 bool ASBeautifier::getSharpStyle(void)
612 {
613 	return isSharpStyle;
614 }
615 
616 /**
617  * get the state of the empty line fill option.
618  * If true, empty lines will be filled with the whitespace.
619  * of their previous lines.
620  * If false, these lines will remain empty.
621  *
622  * @return   state of emptyLineFill option.
623  */
getEmptyLineFill(void)624 bool ASBeautifier::getEmptyLineFill(void)
625 {
626 	return emptyLineFill;
627 }
628 
629 /**
630  * check if there are any indented lines ready to be read by nextLine()
631  *
632  * @return    are there any indented lines ready?
633  */
hasMoreLines() const634 bool ASBeautifier::hasMoreLines() const
635 {
636 	return sourceIterator->hasMoreLines();
637 }
638 
639 /**
640  * get the next indented line.
641  *
642  * @return    indented line.
643  */
nextLine()644 WString ASBeautifier::nextLine()
645 {
646 	return beautify(sourceIterator->nextLine());
647 }
648 
649 /**
650  * beautify a line of source code.
651  * every line of source code in a source code file should be sent
652  * one after the other to the beautify method.
653  *
654  * @return      the indented line.
655  * @param originalLine       the original unindented line.
656  */
beautify(const WString & originalLine)657 WString ASBeautifier::beautify(const WString &originalLine)
658 {
659 	WString line;
660 	bool isInLineComment = false;
661 	bool lineStartsInComment = false;
662 	bool isInClass = false;
663 	bool isInSwitch = false;
664 	bool isImmediatelyAfterConst = false;
665 	bool isSpecialChar = false;
666 	wchar ch = ' ';
667 	wchar prevCh;
668 	WString outBuffer; // the newly idented line is bufferd here
669 	int tabCount = 0;
670 	const WString *lastLineHeader = NULL;
671 	bool closingBracketReached = false;
672 	int spaceTabCount = 0;
673 	wchar tempCh;
674 	int headerStackSize = headerStack->GetCount();
675 	bool shouldIndentBrackettedLine = true;
676 	int lineOpeningBlocksNum = 0;
677 	int lineClosingBlocksNum = 0;
678 	bool previousLineProbation = (probationHeader != NULL);
679 	int i;
680 
681 	currentHeader = NULL;
682 	lineStartsInComment = isInComment;
683 	blockCommentNoBeautify = blockCommentNoIndent;
684 	previousLineProbationTab = false;
685 	outLineNumber++;
686 
687 	// handle and remove white spaces around the line:
688 	// If not in comment, first find out size of white space before line,
689 	// so that possible comments starting in the line continue in
690 	// relation to the preliminary white-space.
691 	if (!isInComment)
692 	{
693 		int strlen = originalLine.GetCount();
694 		leadingWhiteSpaces = 0;
695 
696 		for (int j = 0; j < strlen && isWhiteSpace(originalLine[j]); j++)
697 		{
698 			if (originalLine[j] == '\t')
699 				leadingWhiteSpaces += indentLength;
700 			else
701 				leadingWhiteSpaces++;
702 		}
703 		line = trim(originalLine);
704 	}
705 	else
706 	{
707 		// convert leading tabs to spaces
708 		WString spaceTabs(' ', indentLength);
709 		WString newLine = originalLine;
710 		int strlen = newLine.GetCount();
711 
712 		for (int j=0; j < leadingWhiteSpaces && j < strlen; j++)
713 		{
714 			if (newLine[j] == '\t')
715 			{
716 				ASString_Replace(newLine, j, 1, spaceTabs);
717 				strlen = newLine.GetCount();
718 			}
719 		}
720 
721 		// trim the comment leaving the new leading whitespace
722 		int trimSize = 0;
723 		strlen = newLine.GetCount();
724 
725 		while (trimSize < strlen
726 		        && trimSize < leadingWhiteSpaces
727 		        && isWhiteSpace(newLine[trimSize]))
728 			trimSize++;
729 
730 
731 		while (trimSize < strlen && isWhiteSpace(newLine[strlen-1]))
732 			strlen--;
733 
734 		line = newLine.Mid(trimSize, strlen);
735 		int trimEnd = ASString_Find_Last_Not_Of(line, " \t");
736 		if (trimEnd >= 0)
737 		{
738 			int spacesToDelete = line.GetCount() - 1 - trimEnd;
739 			if (spacesToDelete > 0)
740 				line.Remove(trimEnd + 1, spacesToDelete);
741 		}
742 	}
743 
744 
745 	if (line.GetCount() == 0)
746 	{
747 		if (backslashEndsPrevLine)	// must continue to clear variables
748 			line = " ";
749 		else if (emptyLineFill)
750 			return preLineWS(prevFinalLineSpaceTabCount, prevFinalLineTabCount);
751 		else
752 			return line;
753 	}
754 
755 	// handle preprocessor commands
756 
757 	if (isCStyle && !isInComment && (line[0] == '#' || backslashEndsPrevLine))
758 	{
759 		if (line[0] == '#')
760 		{
761 			WString preproc = trim(line.Mid(1));
762 
763 			// When finding a multi-lined #define statement, the original beautifier
764 			// 1. sets its isInDefineDefinition flag
765 			// 2. clones a new beautifier that will be used for the actual indentation
766 			//    of the #define. This clone is put into the activeBeautifierStack in order
767 			//    to be called for the actual indentation.
768 			// The original beautifier will have isInDefineDefinition = true, isInDefine = false
769 			// The cloned beautifier will have   isInDefineDefinition = true, isInDefine = true
770 			if (preprocessorIndent && preproc.Mid(0, 6) == WString("define") &&  *line.Last() == '\\')
771 			{
772 				if (!isInDefineDefinition)
773 				{
774 					ASBeautifier *defineBeautifier;
775 
776 					// this is the original beautifier
777 					isInDefineDefinition = true;
778 
779 					// push a new beautifier into the active stack
780 					// this beautifier will be used for the indentation of this define
781 					defineBeautifier = new ASBeautifier(*this);
782 					activeBeautifierStack->push_back(defineBeautifier);
783 				}
784 				else
785 				{
786 					// the is the cloned beautifier that is in charge of indenting the #define.
787 					isInDefine = true;
788 				}
789 			}
790 			else if (preproc.Mid(0, 2) == WString("if"))
791 			{
792 				// push a new beautifier into the stack
793 				waitingBeautifierStackLengthStack->push_back(waitingBeautifierStack->GetCount());
794 				activeBeautifierStackLengthStack->push_back(activeBeautifierStack->GetCount());
795 				waitingBeautifierStack->push_back(new ASBeautifier(*this));
796 			}
797 			else if (preproc.Mid(0, 4) == WString("else"))
798 			{
799 				if (waitingBeautifierStack && !waitingBeautifierStack->IsEmpty())
800 				{
801 					// MOVE current waiting beautifier to active stack.
802 					activeBeautifierStack->push_back(waitingBeautifierStack->back());
803 					waitingBeautifierStack->pop_back();
804 				}
805 			}
806 			else if (preproc.Mid(0, 4) == WString("elif"))
807 			{
808 				if (waitingBeautifierStack && !waitingBeautifierStack->IsEmpty())
809 				{
810 					// append a COPY current waiting beautifier to active stack, WITHOUT deleting the original.
811 					activeBeautifierStack->push_back(new ASBeautifier(*(waitingBeautifierStack->back())));
812 				}
813 			}
814 			else if (preproc.Mid(0, 5) == WString("endif"))
815 			{
816 				int stackLength;
817 				ASBeautifier *beautifier;
818 
819 				if (waitingBeautifierStackLengthStack && !waitingBeautifierStackLengthStack->IsEmpty())
820 				{
821 					stackLength = waitingBeautifierStackLengthStack->back();
822 					waitingBeautifierStackLengthStack->pop_back();
823 					while ((int) waitingBeautifierStack->GetCount() > stackLength)
824 					{
825 						beautifier = waitingBeautifierStack->back();
826 						waitingBeautifierStack->pop_back();
827 						delete beautifier;
828 					}
829 				}
830 
831 				if (!activeBeautifierStackLengthStack->IsEmpty())
832 				{
833 					stackLength = activeBeautifierStackLengthStack->back();
834 					activeBeautifierStackLengthStack->pop_back();
835 					while ((int) activeBeautifierStack->GetCount() > stackLength)
836 					{
837 						beautifier = activeBeautifierStack->back();
838 						activeBeautifierStack->pop_back();
839 						delete beautifier;
840 					}
841 				}
842 			}
843 		}
844 
845 		// check if the last char is a backslash
846 		if (line.GetCount() > 0)
847 			backslashEndsPrevLine = (line[line.GetCount() - 1] == '\\');
848 		else
849 			backslashEndsPrevLine = false;
850 
851 		// check if this line ends a multi-line #define
852 		// if so, use the #define's cloned beautifier for the line's indentation
853 		// and then remove it from the active beautifier stack and delete it.
854 		if (!backslashEndsPrevLine && isInDefineDefinition && !isInDefine)
855 		{
856 			WString beautifiedLine;
857 			ASBeautifier *defineBeautifier;
858 
859 			isInDefineDefinition = false;
860 			defineBeautifier = activeBeautifierStack->back();
861 			activeBeautifierStack->pop_back();
862 
863 			beautifiedLine = defineBeautifier->beautify(line);
864 			delete defineBeautifier;
865 			return beautifiedLine;
866 		}
867 
868 		// unless this is a multi-line #define, return this precompiler line as is.
869 		if (!isInDefine && !isInDefineDefinition)
870 			return originalLine;
871 	}
872 
873 	// if there exists any worker beautifier in the activeBeautifierStack,
874 	// then use it instead of me to indent the current line.
875 	// variables set by ASFormatter must be updated.
876 	if (!isInDefine && activeBeautifierStack != NULL && !activeBeautifierStack->IsEmpty())
877 	{
878 		activeBeautifierStack->back()->inLineNumber = inLineNumber;
879 		activeBeautifierStack->back()->outLineNumber = outLineNumber;
880 		activeBeautifierStack->back()->lineCommentNoBeautify = lineCommentNoBeautify;
881 		activeBeautifierStack->back()->isNonInStatementArray = isNonInStatementArray;
882 		return activeBeautifierStack->back()->beautify(line);
883 	}
884 
885 	// calculate preliminary indentation based on data from past lines
886 	if (!inStatementIndentStack->IsEmpty())
887 		spaceTabCount = inStatementIndentStack->back();
888 
889 
890 	for (i = 0; i < (int) headerStackSize; i++)
891 	{
892 		isInClass = false;
893 
894 		if (blockIndent || (!(i > 0 && (*headerStack)[i-1] != &AS_OPEN_BRACKET
895 		                      && (*headerStack)[i] == &AS_OPEN_BRACKET)))
896 			++tabCount;
897 
898 		if (!isJavaStyle && !namespaceIndent && i >= 1
899 		        && (*headerStack)[i-1] == &AS_NAMESPACE
900 		        && (*headerStack)[i] == &AS_OPEN_BRACKET)
901 			--tabCount;
902 
903 		if (isCStyle && i >= 1
904 		        && (*headerStack)[i-1] == &AS_CLASS
905 		        && (*headerStack)[i] == &AS_OPEN_BRACKET)
906 		{
907 			if (classIndent)
908 				++tabCount;
909 			isInClass = true;
910 		}
911 
912 		// is the switchIndent option is on, indent switch statements an additional indent.
913 		else if (switchIndent && i > 1 &&
914 		         (*headerStack)[i-1] == &AS_SWITCH &&
915 		         (*headerStack)[i] == &AS_OPEN_BRACKET
916 		        )
917 		{
918 			++tabCount;
919 			isInSwitch = true;
920 		}
921 
922 	}
923 
924 	if (!lineStartsInComment
925 	        && isCStyle
926 	        && isInClass
927 	        && classIndent
928 	        && headerStackSize >= 2
929 	        && (*headerStack)[headerStackSize-2] == &AS_CLASS
930 	        && (*headerStack)[headerStackSize-1] == &AS_OPEN_BRACKET
931 	        && line[0] == '}')
932 		--tabCount;
933 
934 	else if (!lineStartsInComment
935 	         && isInSwitch
936 	         && switchIndent
937 	         && headerStackSize >= 2
938 	         && (*headerStack)[headerStackSize-2] == &AS_SWITCH
939 	         && (*headerStack)[headerStackSize-1] == &AS_OPEN_BRACKET
940 	         && line[0] == '}')
941 		--tabCount;
942 
943 	if (isInClassHeader)
944 	{
945 		isInClassHeaderTab = true;
946 		tabCount += 2;
947 	}
948 
949 	if (isInConditional)
950 	{
951 		--tabCount;
952 	}
953 
954 
955 	// parse characters in the current line.
956 
957 	for (i = 0; i < (int) line.GetCount(); i++)
958 	{
959 		tempCh = line[i];
960 
961 		prevCh = ch;
962 		ch = tempCh;
963 
964 //		outBuffer.append(1, ch);
965 		outBuffer.Cat(ch);
966 
967 		if (isWhiteSpace(ch))
968 			continue;
969 
970 		// check for utf8 characters
971 		// isalnum() will display an assert message in debug if not bypassed here
972 		if (ch < 0)
973 			continue;
974 
975 		// handle special characters (i.e. backslash+character such as \n, \t, ...)
976 		if (isSpecialChar)
977 		{
978 			isSpecialChar = false;
979 			continue;
980 		}
981 		if (!(isInComment || isInLineComment) && line.Mid(i, 2) == WString("\\\\"))
982 		{
983 			outBuffer.Cat('\\');
984 			i++;
985 			continue;
986 		}
987 		if (!(isInComment || isInLineComment) && ch == '\\')
988 		{
989 			isSpecialChar = true;
990 			continue;
991 		}
992 
993 		// handle quotes (such as 'x' and "Hello Dolly")
994 		if (!(isInComment || isInLineComment) && (ch == '"' || ch == '\'')) {
995 			if (!isInQuote)
996 			{
997 				quoteChar = ch;
998 				isInQuote = true;
999 			}
1000 			else if (quoteChar == ch)
1001 			{
1002 				isInQuote = false;
1003 				isInStatement = true;
1004 				continue;
1005 			}
1006 		}
1007 		if (isInQuote)
1008 			continue;
1009 
1010 		// handle comments
1011 
1012 		if (!(isInComment || isInLineComment) && line.Mid(i, 2) == WString("//"))
1013 		{
1014 			isInLineComment = true;
1015 			outBuffer.Cat('/');
1016 			i++;
1017 			continue;
1018 		}
1019 		else if (!(isInComment || isInLineComment) && line.Mid(i, 2) == WString("/*"))
1020 		{
1021 			isInComment = true;
1022 			outBuffer.Cat('*');
1023 			i++;
1024 			int j = ASString_Find_First_Not_Of(line, " \t");
1025 			if (line.Mid(j, 2) != WString("/*"))	// does line start with comment?
1026 				blockCommentNoIndent = true;		// if no, cannot indent continuation lines
1027 			continue;
1028 		}
1029 		else if ((isInComment || isInLineComment) && line.Mid(i, 2) ==  WString("*/"))
1030 		{
1031 			isInComment = false;
1032 			outBuffer.Cat('/');
1033 			i++;
1034 			blockCommentNoIndent = false;		// ok to indent next comment
1035 			continue;
1036 		}
1037 
1038 		if (isInComment || isInLineComment)
1039 			continue;
1040 
1041 		// if we have reached this far then we are NOT in a comment or String of special character...
1042 
1043 		if (probationHeader != NULL)
1044 		{
1045 			if (((probationHeader == &AS_STATIC || probationHeader == &AS_CONST) && ch == '{')
1046 			        || (probationHeader == &AS_SYNCHRONIZED && ch == '('))
1047 			{
1048 				// insert the probation header as a new header
1049 				isInHeader = true;
1050 				headerStack->push_back(probationHeader);
1051 
1052 				// handle the specific probation header
1053 				isInConditional = (probationHeader == &AS_SYNCHRONIZED);
1054 				if (probationHeader == &AS_CONST)
1055 					isImmediatelyAfterConst = true;
1056 
1057 				isInStatement = false;
1058 				// if the probation comes from the previous line, then indent by 1 tab count.
1059 				if (previousLineProbation && ch == '{')
1060 				{
1061 					tabCount++;
1062 					previousLineProbationTab = true;
1063 				}
1064 				previousLineProbation = false;
1065 			}
1066 
1067 			// dismiss the probation header
1068 			probationHeader = NULL;
1069 		}
1070 
1071 		prevNonSpaceCh = currentNonSpaceCh;
1072 		currentNonSpaceCh = ch;
1073 		if (!isLegalNameChar(ch) && ch != ',' && ch != ';')
1074 		{
1075 			prevNonLegalCh = currentNonLegalCh;
1076 			currentNonLegalCh = ch;
1077 		}
1078 
1079 		if (isInHeader)
1080 		{
1081 			isInHeader = false;
1082 			currentHeader = headerStack->back();
1083 		}
1084 		else
1085 			currentHeader = NULL;
1086 
1087 		if (isCStyle && isInTemplate
1088 		        && (ch == '<' || ch == '>')
1089 		        &&  findHeader(line, i, nonAssignmentOperators) == NULL)
1090 		{
1091 			if (ch == '<')
1092 			{
1093 				++templateDepth;
1094 			}
1095 			else if (ch == '>')
1096 			{
1097 				if (--templateDepth <= 0)
1098 				{
1099 					if (isInTemplate)
1100 						ch = ';';
1101 					else
1102 						ch = 't';
1103 					isInTemplate = false;
1104 					templateDepth = 0;
1105 				}
1106 			}
1107 		}
1108 
1109 		// handle parenthesies
1110 		if (ch == '(' || ch == '[' || ch == ')' || ch == ']')
1111 		{
1112 			if (ch == '(' || ch == '[')
1113 			{
1114 				if (parenDepth == 0)
1115 				{
1116 					parenStatementStack->push_back(isInStatement);
1117 					isInStatement = true;
1118 				}
1119 				parenDepth++;
1120 
1121 				inStatementIndentStackSizeStack->push_back(inStatementIndentStack->GetCount());
1122 
1123 				if (currentHeader != NULL)
1124 					registerInStatementIndent(line, i, spaceTabCount, minConditionalIndent/*indentLength*2*/, true);
1125 				else
1126 					registerInStatementIndent(line, i, spaceTabCount, 0, true);
1127 			}
1128 			else if (ch == ')' || ch == ']')
1129 			{
1130 				parenDepth--;
1131 				if (parenDepth == 0)
1132 				{
1133 					isInStatement = parenStatementStack->back();
1134 					parenStatementStack->pop_back();
1135 					ch = ' ';
1136 
1137 					isInConditional = false;
1138 				}
1139 
1140 				if (!inStatementIndentStackSizeStack->IsEmpty())
1141 				{
1142 					int previousIndentStackSize = inStatementIndentStackSizeStack->back();
1143 					inStatementIndentStackSizeStack->pop_back();
1144 					while (previousIndentStackSize < (int) inStatementIndentStack->GetCount())
1145 						inStatementIndentStack->pop_back();
1146 
1147 					if (!parenIndentStack->IsEmpty())
1148 					{
1149 						int poppedIndent = parenIndentStack->back();
1150 						parenIndentStack->pop_back();
1151 
1152 						if (i == 0)
1153 							spaceTabCount = poppedIndent;
1154 					}
1155 				}
1156 			}
1157 
1158 			continue;
1159 		}
1160 
1161 
1162 		if (ch == '{')
1163 		{
1164 			bool isBlockOpener;
1165 			// first, check if '{' is a block-opener or an static-array opener
1166 			isBlockOpener = ((prevNonSpaceCh == '{' && bracketBlockStateStack->back())
1167 			                 || prevNonSpaceCh == '}'
1168 			                 || prevNonSpaceCh == ')'
1169 			                 || prevNonSpaceCh == ';'
1170 			                 || peekNextChar(line, i) == '{'
1171 			                 || isNonInStatementArray
1172 			                 || isInClassHeader
1173 //			                 || isBlockOpener
1174 			                 || isImmediatelyAfterConst
1175 			                 || (isInDefine &&
1176 			                     (prevNonSpaceCh == '('
1177 			                      || prevNonSpaceCh == '_'
1178 			                      || isalnum(prevNonSpaceCh))));
1179 
1180 			isInClassHeader = false;
1181 			if (!isBlockOpener && currentHeader != NULL)
1182 			{
1183 				for (int n = 0; n < nonParenHeaders.GetCount(); n++)
1184 					if (currentHeader == nonParenHeaders[n])
1185 					{
1186 						isBlockOpener = true;
1187 						break;
1188 					}
1189 			}
1190 			bracketBlockStateStack->push_back(isBlockOpener);
1191 			if (!isBlockOpener)
1192 			{
1193 				inStatementIndentStackSizeStack->push_back(inStatementIndentStack->GetCount());
1194 				registerInStatementIndent(line, i, spaceTabCount, 0, true);
1195 				parenDepth++;
1196 				if (i == 0)
1197 					shouldIndentBrackettedLine = false;
1198 
1199 				continue;
1200 			}
1201 
1202 			// this bracket is a block opener...
1203 
1204 			++lineOpeningBlocksNum;
1205 //			if (isInClassHeader)
1206 //			isInClassHeader = false;
1207 
1208 			if (isInClassHeaderTab)
1209 			{
1210 				isInClassHeaderTab = false;
1211 				// decrease tab count if bracket is broken
1212 				int firstChar = ASString_Find_First_Not_Of(line, " \t");
1213 				if(firstChar >= 0)
1214 					if (line[firstChar] == '{' && (int) firstChar == i)
1215 						tabCount -= 2;
1216 			}
1217 
1218 			// do not allow inStatementIndent - should occur for Java files only
1219 			if (inStatementIndentStack->GetCount() > 0)
1220 			{
1221 				spaceTabCount = 0;
1222 				inStatementIndentStack->back() = 0;
1223 			}
1224 
1225 			blockParenDepthStack->push_back(parenDepth);
1226 			blockStatementStack->push_back(isInStatement);
1227 
1228 			inStatementIndentStackSizeStack->push_back(inStatementIndentStack->GetCount());
1229 			if (inStatementIndentStack->GetCount() > 0)
1230 				inStatementIndentStack->back() = 0;
1231 
1232 			blockTabCount += isInStatement ? 1 : 0;
1233 			parenDepth = 0;
1234 			isInStatement = false;
1235 
1236 			tempStacks->push_back(new Vector<const WString*>);
1237 			headerStack->push_back(&AS_OPEN_BRACKET);
1238 			lastLineHeader = &AS_OPEN_BRACKET;
1239 
1240 			continue;
1241 		}
1242 
1243 		//check if a header has been reached
1244 		if (isWhiteSpace(prevCh))
1245 		{
1246 			bool isIndentableHeader = true;
1247 			const WString *newHeader = findHeader(line, i, headers);
1248 			if (newHeader != NULL)
1249 			{
1250 				// if we reached here, then this is a header...
1251 				isInHeader = true;
1252 
1253 				Vector<const WString*> *lastTempStack;
1254 				if (tempStacks->IsEmpty())
1255 					lastTempStack = NULL;
1256 				else
1257 					lastTempStack = tempStacks->back();
1258 
1259 				// if a new block is opened, push a new stack into tempStacks to hold the
1260 				// future list of headers in the new block.
1261 
1262 				// take care of the special case: 'else if (...)'
1263 				if (newHeader == &AS_IF && lastLineHeader == &AS_ELSE)
1264 				{
1265 					headerStack->pop_back();
1266 				}
1267 
1268 				// take care of 'else'
1269 				else if (newHeader == &AS_ELSE)
1270 				{
1271 					if (lastTempStack != NULL)
1272 					{
1273 						int indexOfIf = indexOf(*lastTempStack, &AS_IF);
1274 						if (indexOfIf != -1)
1275 						{
1276 							// recreate the header list in headerStack up to the previous 'if'
1277 							// from the temporary snapshot stored in lastTempStack.
1278 							int restackSize = lastTempStack->GetCount() - indexOfIf - 1;
1279 							for (int r = 0; r < restackSize; r++)
1280 							{
1281 								headerStack->push_back(lastTempStack->back());
1282 								lastTempStack->pop_back();
1283 							}
1284 							if (!closingBracketReached)
1285 								tabCount += restackSize;
1286 						}
1287 						/*
1288 						 * If the above if is not true, i.e. no 'if' before the 'else',
1289 						 * then nothing beautiful will come out of this...
1290 						 * I should think about inserting an Exception here to notify the caller of this...
1291 						 */
1292 					}
1293 				}
1294 
1295 				// check if 'while' closes a previous 'do'
1296 				else if (newHeader == &AS_WHILE)
1297 				{
1298 					if (lastTempStack != NULL)
1299 					{
1300 						int indexOfDo = indexOf(*lastTempStack, &AS_DO);
1301 						if (indexOfDo != -1)
1302 						{
1303 							// recreate the header list in headerStack up to the previous 'do'
1304 							// from the temporary snapshot stored in lastTempStack.
1305 							int restackSize = lastTempStack->GetCount() - indexOfDo - 1;
1306 							for (int r = 0; r < restackSize; r++)
1307 							{
1308 								headerStack->push_back(lastTempStack->back());
1309 								lastTempStack->pop_back();
1310 							}
1311 							if (!closingBracketReached)
1312 								tabCount += restackSize;
1313 						}
1314 					}
1315 				}
1316 				// check if 'catch' closes a previous 'try' or 'catch'
1317 				else if (newHeader == &AS_CATCH || newHeader == &AS_FINALLY)
1318 				{
1319 					if (lastTempStack != NULL)
1320 					{
1321 						int indexOfTry = indexOf(*lastTempStack, &AS_TRY);
1322 						if (indexOfTry == -1)
1323 							indexOfTry = indexOf(*lastTempStack, &AS_CATCH);
1324 						if (indexOfTry != -1)
1325 						{
1326 							// recreate the header list in headerStack up to the previous 'try'
1327 							// from the temporary snapshot stored in lastTempStack.
1328 							int restackSize = lastTempStack->GetCount() - indexOfTry - 1;
1329 							for (int r = 0; r < restackSize; r++)
1330 							{
1331 								headerStack->push_back(lastTempStack->back());
1332 								lastTempStack->pop_back();
1333 							}
1334 
1335 							if (!closingBracketReached)
1336 								tabCount += restackSize;
1337 						}
1338 					}
1339 				}
1340 				else if (newHeader == &AS_CASE)
1341 				{
1342 					isInCase = true;
1343 					--tabCount;
1344 				}
1345 				else if (newHeader == &AS_DEFAULT)
1346 				{
1347 					isInCase = true;
1348 					--tabCount;
1349 				}
1350 				else if (newHeader == &AS_STATIC
1351 				         || newHeader == &AS_SYNCHRONIZED
1352 				         || (newHeader == &AS_CONST && isCStyle))
1353 				{
1354 					if (!headerStack->IsEmpty() &&
1355 					        (headerStack->back() == &AS_STATIC
1356 					         || headerStack->back() == &AS_SYNCHRONIZED
1357 					         || headerStack->back() == &AS_CONST))
1358 					{
1359 						isIndentableHeader = false;
1360 					}
1361 					else
1362 					{
1363 						isIndentableHeader = false;
1364 						probationHeader = newHeader;
1365 					}
1366 				}
1367 				else if (newHeader == &AS_CONST)
1368 				{
1369 					isIndentableHeader = false;
1370 				}
1371 				else if (newHeader == &AS_TEMPLATE)
1372 				{
1373 					if (isCStyle)
1374 						isInTemplate = true;
1375 					isIndentableHeader = false;
1376 				}
1377 
1378 
1379 				if (isIndentableHeader)
1380 				{
1381 					headerStack->push_back(newHeader);
1382 					isInStatement = false;
1383 					if (indexOf(nonParenHeaders, newHeader) == -1)
1384 					{
1385 						isInConditional = true;
1386 					}
1387 					lastLineHeader = newHeader;
1388 				}
1389 				else
1390 					isInHeader = false;
1391 
1392 				outBuffer.Cat(newHeader->Mid(1));
1393 				i += newHeader->GetCount() - 1;
1394 
1395 				continue;
1396 			}
1397 		}
1398 
1399 		if (isCStyle && !isalpha(prevCh)
1400 		        && line.Mid(i, 8) == WString("operator") && !isalnum(line[i+8]))
1401 		{
1402 			isInOperator = true;
1403 			outBuffer.Cat(AS_OPERATOR.Mid(1));
1404 			i += 7;
1405 			continue;
1406 		}
1407 
1408 		// "new" operator is a pointer, not a calculation
1409 		if (!isalpha(prevCh)
1410 		        && line.Mid(i, 3) == WString("new") && !isalnum(line[i+3]))
1411 		{
1412 			if (prevNonSpaceCh == '=' && isInStatement && !inStatementIndentStack->IsEmpty())
1413 				inStatementIndentStack->back() = 0;
1414 		}
1415 
1416 		if (ch == '?')
1417 			isInQuestion = true;
1418 
1419 
1420 		// special handling of 'case' statements
1421 		if (ch == ':')
1422 		{
1423 			if ((int) line.GetCount() > i + 1 && line[i+1] == ':') // look for ::
1424 			{
1425 				++i;
1426 				outBuffer.Cat(':');
1427 				ch = ' ';
1428 				continue;
1429 			}
1430 
1431 			else if (isInQuestion)
1432 			{
1433 				isInQuestion = false;
1434 			}
1435 
1436 			else if (isCStyle && isInClass && prevNonSpaceCh != ')')
1437 			{
1438 				--tabCount;
1439 				// found a 'private:' or 'public:' inside a class definition
1440 				// so do nothing special
1441 			}
1442 
1443 			else if (!isJavaStyle && isInClassHeader)
1444 			{
1445 				// found a 'class A : public B' definition
1446 				// so do nothing special
1447 			}
1448 
1449 			else if (isJavaStyle && lastLineHeader == &AS_FOR)
1450 			{
1451 				// found a java for-each statement
1452 				// so do nothing special
1453 			}
1454 
1455 			else if (isCStyle && prevNonSpaceCh == ')')
1456 			{
1457 				isInClassHeader = true;
1458 				if (i == 0)
1459 					tabCount += 2;
1460 			}
1461 			else
1462 			{
1463 				currentNonSpaceCh = ';'; // so that brackets after the ':' will appear as block-openers
1464 				if (isInCase)
1465 				{
1466 					isInCase = false;
1467 					ch = ';'; // from here on, treat char as ';'
1468 				}
1469 
1470 
1471 				else // is in a label (e.g. 'label1:')
1472 				{
1473 					if (labelIndent)
1474 						--tabCount; // unindent label by one indent
1475 					else
1476 						tabCount = 0; // completely flush indent to left
1477 				}
1478 
1479 
1480 
1481 			}
1482 		}
1483 
1484 		if ((ch == ';'  || (parenDepth > 0 && ch == ','))  && !inStatementIndentStackSizeStack->IsEmpty())
1485 			while ((int) inStatementIndentStackSizeStack->back() + (parenDepth > 0 ? 1 : 0)
1486 			        < (int) inStatementIndentStack->GetCount())
1487 				inStatementIndentStack->pop_back();
1488 
1489 
1490 		// handle ends of statements
1491 		if ((ch == ';' && parenDepth == 0) || ch == '}'/* || (ch == ',' && parenDepth == 0)*/)
1492 		{
1493 			if (ch == '}')
1494 			{
1495 				// first check if this '}' closes a previous block, or a static array...
1496 				if (!bracketBlockStateStack->IsEmpty())
1497 				{
1498 					bool bracketBlockState = bracketBlockStateStack->back();
1499 					bracketBlockStateStack->pop_back();
1500 					if (!bracketBlockState)
1501 					{
1502 						if (!inStatementIndentStackSizeStack->IsEmpty())
1503 						{
1504 							// this bracket is a static array
1505 
1506 							int previousIndentStackSize = inStatementIndentStackSizeStack->back();
1507 							inStatementIndentStackSizeStack->pop_back();
1508 							while (previousIndentStackSize < (int) inStatementIndentStack->GetCount())
1509 								inStatementIndentStack->pop_back();
1510 							parenDepth--;
1511 							if (i == 0)
1512 								shouldIndentBrackettedLine = false;
1513 
1514 							if (!parenIndentStack->IsEmpty())
1515 							{
1516 								int poppedIndent = parenIndentStack->back();
1517 								parenIndentStack->pop_back();
1518 								if (i == 0)
1519 									spaceTabCount = poppedIndent;
1520 							}
1521 						}
1522 						continue;
1523 					}
1524 				}
1525 
1526 				// this bracket is block closer...
1527 
1528 				++lineClosingBlocksNum;
1529 
1530 				if (!inStatementIndentStackSizeStack->IsEmpty())
1531 					inStatementIndentStackSizeStack->pop_back();
1532 
1533 				if (!blockParenDepthStack->IsEmpty())
1534 				{
1535 					parenDepth = blockParenDepthStack->back();
1536 					blockParenDepthStack->pop_back();
1537 					isInStatement = blockStatementStack->back();
1538 					blockStatementStack->pop_back();
1539 
1540 					if (isInStatement)
1541 						blockTabCount--;
1542 				}
1543 
1544 				closingBracketReached = true;
1545 				int headerPlace = indexOf(*headerStack, &AS_OPEN_BRACKET);
1546 				if (headerPlace != -1)
1547 				{
1548 					const WString *popped = headerStack->back();
1549 					while (popped != &AS_OPEN_BRACKET)
1550 					{
1551 						headerStack->pop_back();
1552 						popped = headerStack->back();
1553 					}
1554 					headerStack->pop_back();
1555 
1556 					if (!tempStacks->IsEmpty())
1557 					{
1558 						Vector<const WString*> *temp =  tempStacks->back();
1559 						tempStacks->pop_back();
1560 						delete temp;
1561 					}
1562 				}
1563 
1564 
1565 				ch = ' '; // needed due to cases such as '}else{', so that headers ('else' tn tih case) will be identified...
1566 			}
1567 
1568 			/*
1569 			 * Create a temporary snapshot of the current block's header-list in the
1570 			 * uppermost inner stack in tempStacks, and clear the headerStack up to
1571 			 * the begining of the block.
1572 			 * Thus, the next future statement will think it comes one indent past
1573 			 * the block's '{' unless it specifically checks for a companion-header
1574 			 * (such as a previous 'if' for an 'else' header) within the tempStacks,
1575 			 * and recreates the temporary snapshot by manipulating the tempStacks.
1576 			 */
1577 			if (!tempStacks->back()->IsEmpty())
1578 				while (!tempStacks->back()->IsEmpty())
1579 					tempStacks->back()->pop_back();
1580 			while (!headerStack->IsEmpty() && headerStack->back() != &AS_OPEN_BRACKET)
1581 			{
1582 				tempStacks->back()->push_back(headerStack->back());
1583 				headerStack->pop_back();
1584 			}
1585 
1586 			if (parenDepth == 0 && ch == ';')
1587 				isInStatement = false;
1588 
1589 			previousLastLineHeader = NULL;
1590 			isInClassHeader = false;
1591 			isInQuestion = false;
1592 
1593 			continue;
1594 		}
1595 
1596 
1597 		// check for preBlockStatements ONLY if not within parenthesies
1598 		// (otherwise 'struct XXX' statements would be wrongly interpreted...)
1599 		if (isWhiteSpace(prevCh) && !isInTemplate && parenDepth == 0)
1600 		{
1601 			const WString *newHeader = findHeader(line, i, preBlockStatements);
1602 			if (newHeader != NULL)
1603 			{
1604 				isInClassHeader = true;
1605 				outBuffer.Cat(newHeader->Mid(1));
1606 				i += newHeader->GetCount() - 1;
1607 				headerStack->push_back(newHeader);
1608 			}
1609 		}
1610 
1611 		// Handle operators
1612 
1613 		immediatelyPreviousAssignmentOp = NULL;
1614 
1615 		// Check if an operator has been reached.
1616 		const WString *foundAssignmentOp = findHeader(line, i, assignmentOperators, false);
1617 		if (foundAssignmentOp == &AS_RETURN)
1618 			foundAssignmentOp = findHeader(line, i, assignmentOperators, true);
1619 		const WString *foundNonAssignmentOp = findHeader(line, i, nonAssignmentOperators, false);
1620 
1621 		// Since findHeader's boundry checking was not used above, it is possible
1622 		// that both an assignment op and a non-assignment op where found,
1623 		// e.g. '>>' and '>>='. If this is the case, treat the LONGER one as the
1624 		// found operator.
1625 		if (foundAssignmentOp != NULL && foundNonAssignmentOp != NULL) {
1626 			if (foundAssignmentOp->GetCount() < foundNonAssignmentOp->GetCount())
1627 				foundAssignmentOp = NULL;
1628 			else
1629 				foundNonAssignmentOp = NULL;
1630 		}
1631 
1632 		if (foundNonAssignmentOp != NULL)
1633 		{
1634 			if (foundNonAssignmentOp->GetCount() > 1)
1635 			{
1636 				outBuffer.Cat(foundNonAssignmentOp->Mid(1));
1637 				i += foundNonAssignmentOp->GetCount() - 1;
1638 			}
1639 		}
1640 
1641 		else if (foundAssignmentOp != NULL)
1642 		{
1643 			if (foundAssignmentOp->GetCount() > 1)
1644 			{
1645 				outBuffer.Cat(foundAssignmentOp->Mid(1));
1646 				i += foundAssignmentOp->GetCount() - 1;
1647 			}
1648 
1649 			if (!isInOperator && !isInTemplate && !isNonInStatementArray)
1650 			{
1651 				registerInStatementIndent(line, i, spaceTabCount, 0, false);
1652 				immediatelyPreviousAssignmentOp = foundAssignmentOp;
1653 				isInStatement = true;
1654 			}
1655 		}
1656 
1657 		if (isInOperator)
1658 			isInOperator = false;
1659 	}
1660 
1661 	// handle special cases of unindentation:
1662 
1663 	/*
1664 	 * if '{' doesn't follow an immediately previous '{' in the headerStack
1665 	 * (but rather another header such as "for" or "if", then unindent it
1666 	 * by one indentation relative to its block.
1667 	 */
1668 
1669 	if (!lineStartsInComment
1670 	        && !blockIndent
1671 	        && outBuffer.GetCount() > 0
1672 	        && outBuffer[0] == '{'
1673 	        && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum == lineClosingBlocksNum)
1674 	        && !(headerStack->GetCount() > 1 && (*headerStack)[headerStack->GetCount()-2] == &AS_OPEN_BRACKET)
1675 	        && shouldIndentBrackettedLine)
1676 		--tabCount;
1677 
1678 	else if (!lineStartsInComment
1679 	         && outBuffer.GetCount() > 0
1680 	         && outBuffer[0] == '}'
1681 	         && shouldIndentBrackettedLine)
1682 		--tabCount;
1683 
1684 	// correctly indent one-line-blocks...
1685 	else if (!lineStartsInComment
1686 	         && outBuffer.GetCount() > 0
1687 	         && lineOpeningBlocksNum > 0
1688 	         && lineOpeningBlocksNum == lineClosingBlocksNum
1689 	         && previousLineProbationTab)
1690 		--tabCount; //lineOpeningBlocksNum - (blockIndent ? 1 : 0);
1691 
1692 	if (tabCount < 0)
1693 		tabCount = 0;
1694 
1695 	// take care of extra bracket indentatation option...
1696 	if (bracketIndent && outBuffer.GetCount() > 0 && shouldIndentBrackettedLine)
1697 		if (outBuffer[0] == '{' || outBuffer[0] == '}')
1698 			tabCount++;
1699 
1700 
1701 	if (isInDefine)
1702 	{
1703 		if (outBuffer[0] == '#')
1704 		{
1705 			WString preproc = trim(outBuffer.Mid(1));
1706 
1707 			if (preproc.Mid(0, 6) == WString("define"))
1708 			{
1709 				if (!inStatementIndentStack->IsEmpty()
1710 				        && inStatementIndentStack->back() > 0)
1711 				{
1712 					defineTabCount = tabCount;
1713 				}
1714 				else
1715 				{
1716 					defineTabCount = tabCount - 1;
1717 					tabCount--;
1718 				}
1719 			}
1720 		}
1721 
1722 		tabCount -= defineTabCount;
1723 	}
1724 
1725 	if (tabCount < 0)
1726 		tabCount = 0;
1727 	if (lineCommentNoBeautify || blockCommentNoBeautify)
1728 		tabCount = spaceTabCount = 0;
1729 
1730 	// finally, insert indentations into begining of line
1731 
1732 	prevFinalLineSpaceTabCount = spaceTabCount;
1733 	prevFinalLineTabCount = tabCount;
1734 
1735 	if (shouldForceTabIndentation)
1736 	{
1737 		tabCount += spaceTabCount / indentLength;
1738 		spaceTabCount = spaceTabCount % indentLength;
1739 	}
1740 
1741 	outBuffer = preLineWS(spaceTabCount, tabCount) + outBuffer;
1742 
1743 	if (lastLineHeader != NULL)
1744 		previousLastLineHeader = lastLineHeader;
1745 
1746 	return outBuffer;
1747 }
1748 
1749 
preLineWS(int spaceTabCount,int tabCount)1750 WString ASBeautifier::preLineWS(int spaceTabCount, int tabCount)
1751 {
1752 	WString ws;
1753 
1754 	for (int i = 0; i < tabCount; i++)
1755 		ws += indentString;
1756 
1757 	while ((spaceTabCount--) > 0)
1758 		ws += WString(" ");
1759 
1760 	return ws;
1761 
1762 }
1763 
1764 /**
1765  * register an in-statement indent.
1766  */
registerInStatementIndent(const WString & line,int i,int spaceTabCount,int minIndent,bool updateParenStack)1767 void ASBeautifier::registerInStatementIndent(const WString &line, int i, int spaceTabCount,
1768         int minIndent, bool updateParenStack)
1769 {
1770 	int inStatementIndent;
1771 	int remainingCharNum = line.GetCount() - i;
1772 	int nextNonWSChar = getNextProgramCharDistance(line, i);
1773 
1774 	// if indent is around the last char in the line, indent instead 2 spaces from the previous indent
1775 	if (nextNonWSChar == remainingCharNum)
1776 	{
1777 		int previousIndent = spaceTabCount;
1778 		if (!inStatementIndentStack->IsEmpty())
1779 			previousIndent = inStatementIndentStack->back();
1780 
1781 		inStatementIndentStack->push_back(/*2*/ indentLength + previousIndent);
1782 		if (updateParenStack)
1783 			parenIndentStack->push_back(previousIndent);
1784 		return;
1785 	}
1786 
1787 	if (updateParenStack)
1788 		parenIndentStack->push_back(i + spaceTabCount);
1789 
1790 	inStatementIndent = i + nextNonWSChar + spaceTabCount;
1791 
1792 	if (i + nextNonWSChar < minIndent)
1793 		inStatementIndent = minIndent + spaceTabCount;
1794 
1795 	if (i + nextNonWSChar > maxInStatementIndent)
1796 		inStatementIndent =  indentLength * 2 + spaceTabCount;
1797 
1798 	if (!inStatementIndentStack->IsEmpty() &&
1799 	        inStatementIndent < inStatementIndentStack->back())
1800 		inStatementIndent = inStatementIndentStack->back();
1801 
1802 	if (isNonInStatementArray)
1803 		inStatementIndent = 0;
1804 
1805 	inStatementIndentStack->push_back(inStatementIndent);
1806 }
1807 
1808 /**
1809  * get distance to the next non-white sspace, non-comment character in the line.
1810  * if no such character exists, return the length remaining to the end of the line.
1811  */
getNextProgramCharDistance(const WString & line,int i)1812 int ASBeautifier::getNextProgramCharDistance(const WString &line, int i)
1813 {
1814 	bool inComment = false;
1815 	int  remainingCharNum = line.GetCount() - i;
1816 	int  charDistance;
1817 	wchar ch;
1818 
1819 	for (charDistance = 1; charDistance < remainingCharNum; charDistance++)
1820 	{
1821 		ch = line[i + charDistance];
1822 		if (inComment)
1823 		{
1824 			if (line.Mid(i + charDistance, 2) == WString("*/"))
1825 			{
1826 				charDistance++;
1827 				inComment = false;
1828 			}
1829 			continue;
1830 		}
1831 		else if (isWhiteSpace(ch))
1832 			continue;
1833 		else if (ch == '/')
1834 		{
1835 			if (line.Mid(i + charDistance, 2) == WString("//"))
1836 				return remainingCharNum;
1837 			else if (line.Mid(i + charDistance, 2) == WString("/*"))
1838 			{
1839 				charDistance++;
1840 				inComment = true;
1841 			}
1842 		}
1843 		else
1844 			return charDistance;
1845 	}
1846 
1847 	return charDistance;
1848 }
1849 
1850 
1851 /**
1852  * check if a specific line position contains a header, out of several possible headers.
1853  *
1854  * @return    a pointer to the found header. if no header was found then return NULL.
1855  */
findHeader(const WString & line,int i,const Vector<const WString * > & possibleHeaders,bool checkBoundry)1856 const WString *ASBeautifier::findHeader(const WString &line, int i, const Vector<const WString*> &possibleHeaders, bool checkBoundry)
1857 {
1858 	int maxHeaders = possibleHeaders.GetCount();
1859 	// const WString *header = NULL;
1860 	int p;
1861 
1862 	for (p = 0; p < maxHeaders; p++)
1863 	{
1864 		const WString *header = possibleHeaders[p];
1865 
1866 		if (line.Mid(i, header->GetCount()) == *header)
1867 		{
1868 			// check that this is a header and not a part of a longer word
1869 			// (e.g. not at its begining, not at its middle...)
1870 
1871 			int lineLength = line.GetCount();
1872 			int headerEnd = i + header->GetCount();
1873 			wchar startCh = (*header)[0];   // first char of header
1874 			wchar endCh = 0;                // char just after header
1875 			wchar prevCh = 0;               // char just before header
1876 
1877 			if (headerEnd < lineLength)
1878 			{
1879 				endCh = line[headerEnd];
1880 			}
1881 			if (i > 0)
1882 			{
1883 				prevCh = line[i-1];
1884 			}
1885 
1886 			if (!checkBoundry)
1887 			{
1888 				return header;
1889 			}
1890 			else if (prevCh != 0
1891 			         && isLegalNameChar(startCh)
1892 			         && isLegalNameChar(prevCh))
1893 			{
1894 				return NULL;
1895 			}
1896 			else if (headerEnd >= lineLength
1897 			         || !isLegalNameChar(startCh)
1898 			         || !isLegalNameChar(endCh))
1899 			{
1900 				return header;
1901 			}
1902 			else
1903 			{
1904 				return NULL;
1905 			}
1906 		}
1907 	}
1908 
1909 	return NULL;
1910 }
1911 
1912 /**
1913  * find the index number of a string element in a container of strings
1914  *
1915  * @return              the index number of element in the ocntainer. -1 if element not found.
1916  * @param container     a vector of strings.
1917  * @param element       the element to find .
1918  */
indexOf(Vector<const WString * > & container,const WString * element)1919 int ASBeautifier::indexOf(Vector<const WString*> &container, const WString *element)
1920 {
1921 /*	Vector<const WString*>::const_iterator where;
1922 	where = find(container.begin(), container.end(), element);
1923 
1924 	if (where == container.end())
1925 		return -1;
1926 	else
1927 		return (int) (where - container.begin());
1928 */
1929 
1930 	return FindIndex(container, element);
1931 }
1932 
1933 /**
1934  * trim removes the white space surrounding a line.
1935  *
1936  * @return          the trimmed line.
1937  * @param str       the line to trim.
1938  */
trim(const WString & str)1939 WString ASBeautifier::trim(const WString &str)
1940 {
1941 
1942 	int start = 0;
1943 	int end = str.GetCount() - 1;
1944 
1945 	while (start < end && isWhiteSpace(str[start]))
1946 		start++;
1947 
1948 	while (start <= end && isWhiteSpace(str[end]))
1949 		end--;
1950 
1951 //	WString returnStr(str, start, end + 1 - start);
1952 //	return returnStr;
1953 	return str.Mid(start, end+1-start);
1954 }
1955 
1956 /**
1957 * peek at the next unread character.
1958 *
1959 * @return     	the next unread character.
1960 * @param line   the line to check.
1961 * @param i      the current char position on the line.
1962 */
peekNextChar(WString & line,int i)1963 wchar ASBeautifier::peekNextChar(WString &line, int i)
1964 {
1965 	wchar ch = ' ';
1966 	int peekNum = ASString_Find_First_Not_Of(line, " \t", i + 1);
1967 
1968 	if (peekNum < 0)
1969 		return ch;
1970 
1971 	ch = line[peekNum];
1972 
1973 	return ch;
1974 }
1975 
1976 
1977 }   // end namespace astyle
1978