1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  *
3  *   Copyright (C) 2006-2010 by Jim Pattee <jimp03@email.com>
4  *   Copyright (C) 1998-2002 by Tal Davidson
5  *   <http://www.gnu.org/licenses/lgpl-3.0.html>
6  *
7  *   This file is a part of Artistic Style - an indentation and
8  *   reformatting tool for C, C++, C# and Java source files.
9  *   <http://astyle.sourceforge.net>
10  *
11  *   Artistic Style is free software: you can redistribute it and/or modify
12  *   it under the terms of the GNU Lesser General Public License as published
13  *   by the Free Software Foundation, either version 3 of the License, or
14  *   (at your option) any later version.
15  *
16  *   Artistic Style 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 License
22  *   along with Artistic Style.  If not, see <http://www.gnu.org/licenses/>.
23  *
24  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
25  */
26 
27 #include "astyle.h"
28 
29 #include <algorithm>
30 #include <fstream>
31 #include <iostream>
32 
33 
34 namespace astyle
35 {
36 // static member variables
37 int ASFormatter::formatterFileType = 9;		// initialized with an invalid type
38 vector<const string*>* ASFormatter::headers = NULL;
39 vector<const string*>* ASFormatter::nonParenHeaders = NULL;
40 vector<const string*>* ASFormatter::preDefinitionHeaders = NULL;
41 vector<const string*>* ASFormatter::preCommandHeaders = NULL;
42 vector<const string*>* ASFormatter::operators = NULL;
43 vector<const string*>* ASFormatter::assignmentOperators = NULL;
44 vector<const string*>* ASFormatter::castOperators = NULL;
45 
46 /**
47  * Constructor of ASFormatter
48  */
ASFormatter()49 ASFormatter::ASFormatter()
50 {
51 	sourceIterator = NULL;
52 	enhancer = new ASEnhancer;
53 	preBracketHeaderStack = NULL;
54 	bracketTypeStack = NULL;
55 	parenStack = NULL;
56 	structStack = NULL;
57 	lineCommentNoIndent = false;
58 	formattingStyle = STYLE_NONE;
59 	bracketFormatMode = NONE_MODE;
60 	pointerAlignment = ALIGN_NONE;
61 	lineEnd = LINEEND_DEFAULT;
62 	shouldPadOperators = false;
63 	shouldPadParensOutside = false;
64 	shouldPadParensInside = false;
65 	shouldPadHeader = false;
66 	shouldUnPadParens = false;
67 	shouldBreakOneLineBlocks = true;
68 	shouldBreakOneLineStatements = true;
69 	shouldConvertTabs = false;
70 	shouldIndentCol1Comments = false;
71 	shouldBreakBlocks = false;
72 	shouldBreakClosingHeaderBlocks = false;
73 	shouldBreakClosingHeaderBrackets = false;
74 	shouldDeleteEmptyLines = false;
75 	shouldBreakElseIfs = false;
76 	shouldAddBrackets = false;
77 	shouldAddOneLineBrackets = false;
78 
79 	// initialize ASFormatter static member vectors
80 	formatterFileType = 9;		// reset to an invalid type
81 	initVector(headers);
82 	initVector(nonParenHeaders);
83 	initVector(preDefinitionHeaders);
84 	initVector(preCommandHeaders);
85 	initVector(operators);
86 	initVector(assignmentOperators);
87 	initVector(castOperators);
88 
89 	// the following prevents warning messages with cppcheck
90 	// it will NOT compile if activated
91 //	init();
92 }
93 
94 /**
95  * Destructor of ASFormatter
96  */
~ASFormatter()97 ASFormatter::~ASFormatter()
98 {
99 	// delete ASFormatter stack vectors
100 	deleteContainer(preBracketHeaderStack);
101 	deleteContainer(bracketTypeStack);
102 	deleteContainer(parenStack);
103 	deleteContainer(structStack);
104 
105 	// delete static member vectors using swap to eliminate memory leak reporting
106 	// delete ASFormatter static member vectors
107 	formatterFileType = 9;		// reset to an invalid type
108 	deleteVector(headers);
109 	deleteVector(nonParenHeaders);
110 	deleteVector(preDefinitionHeaders);
111 	deleteVector(preCommandHeaders);
112 	deleteVector(operators);
113 	deleteVector(assignmentOperators);
114 	deleteVector(castOperators);
115 
116 	// delete ASBeautifier static member vectors
117 	// must be done when the ASFormatter object is deleted (not ASBeautifier)
118 	ASBeautifier::deleteStaticVectors();
119 
120 	delete enhancer;
121 }
122 
123 /**
124  * initialize the ASFormatter.
125  *
126  * init() should be called every time a ASFormatter object is to start
127  * formatting a NEW source file.
128  * init() recieves a pointer to a ASSourceIterator object that will be
129  * used to iterate through the source code.
130  *
131  * @param sourceIterator     a pointer to the ASSourceIterator or ASStreamIterator object.
132  */
init(ASSourceIterator * si)133 void ASFormatter::init(ASSourceIterator *si)
134 {
135 	buildLanguageVectors();
136 	fixOptionVariableConflicts();
137 
138 	ASBeautifier::init(si);
139 	enhancer->init(getFileType(),
140 	               getIndentLength(),
141 	               getIndentString(),
142 	               getCaseIndent(),
143 	               getEmptyLineFill());
144 	sourceIterator = si;
145 
146 	initContainer(preBracketHeaderStack, new vector<const string*>);
147 	initContainer(parenStack, new vector<int>);
148 	initContainer(structStack, new vector<bool>);
149 	parenStack->push_back(0);               // parenStack must contain this default entry
150 	initContainer(bracketTypeStack, new vector<BracketType>);
151 	bracketTypeStack->push_back(NULL_TYPE);
152 
153 	currentHeader = NULL;
154 	currentLine = "";
155 	readyFormattedLine = "";
156 	formattedLine = "";
157 	currentChar = ' ';
158 	previousChar = ' ';
159 	previousCommandChar = ' ';
160 	previousNonWSChar = ' ';
161 	quoteChar = '"';
162 	charNum = 0;
163 	leadingSpaces = 0;
164 	formattedLineCommentNum = 0;
165 	preprocBracketTypeStackSize = 0;
166 	spacePadNum = 0;
167 	nextLineSpacePadNum = 0;
168 	currentLineFirstBracketNum = string::npos;
169 	previousReadyFormattedLineLength = string::npos;
170 	templateDepth = 0;
171 	traceLineNumber = 0;
172 	horstmannIndentChars = 0;
173 	tabIncrementIn = 0;
174 	previousBracketType = NULL_TYPE;
175 	previousOperator = NULL;
176 
177 	isVirgin = true;
178 	isInLineComment = false;
179 	isInComment = false;
180 	noTrimCommentContinuation = false;
181 	isInPreprocessor = false;
182 	doesLineStartComment = false;
183 	lineEndsInCommentOnly = false;
184 	lineIsLineCommentOnly = false;
185 	lineIsEmpty = false;
186 	isImmediatelyPostCommentOnly = false;
187 	isImmediatelyPostEmptyLine = false;
188 	isInQuote = false;
189 	isInVerbatimQuote = false;
190 	haveLineContinuationChar = false;
191 	isInQuoteContinuation = false;
192 	isSpecialChar = false;
193 	isNonParenHeader = false;
194 	foundNamespaceHeader = false;
195 	foundClassHeader = false;
196 	foundStructHeader = false;
197 	foundInterfaceHeader = false;
198 	foundPreDefinitionHeader = false;
199 	foundPreCommandHeader = false;
200 	foundCastOperator = false;
201 	foundQuestionMark = false;
202 	isInLineBreak = false;
203 	endOfCodeReached = false;
204 	isInExecSQL = false;
205 	isInAsm = false;
206 	isInAsmOneLine = false;
207 	isInAsmBlock = false;
208 	isLineReady = false;
209 	isPreviousBracketBlockRelated = false;
210 	isInPotentialCalculation = false;
211 	shouldReparseCurrentChar = false;
212 	needHeaderOpeningBracket = false;
213 	shouldBreakLineAtNextChar = false;
214 	passedSemicolon = false;
215 	passedColon = false;
216 	clearNonInStatement = false;
217 	isInTemplate = false;
218 	isInBlParen = false;
219 	isImmediatelyPostComment = false;
220 	isImmediatelyPostLineComment = false;
221 	isImmediatelyPostEmptyBlock = false;
222 	isImmediatelyPostPreprocessor = false;
223 	isImmediatelyPostReturn = false;
224 	isImmediatelyPostOperator = false;
225 	isCharImmediatelyPostReturn = false;
226 	isCharImmediatelyPostOperator = false;
227 	isCharImmediatelyPostComment = false;
228 	isPreviousCharPostComment = false;
229 	isCharImmediatelyPostLineComment = false;
230 	isCharImmediatelyPostOpenBlock = false;
231 	isCharImmediatelyPostCloseBlock = false;
232 	isCharImmediatelyPostTemplate = false;
233 	breakCurrentOneLineBlock = false;
234 	isInHorstmannRunIn = false;
235 	currentLineBeginsWithBracket = false;
236 	isPrependPostBlockEmptyLineRequested = false;
237 	isAppendPostBlockEmptyLineRequested = false;
238 	prependEmptyLine = false;
239 	appendOpeningBracket = false;
240 	foundClosingHeader = false;
241 	isImmediatelyPostHeader = false;
242 	isInHeader = false;
243 	isInCase = false;
244 	isJavaStaticConstructor = false;
245 }
246 
247 /**
248  * build vectors for each programing language
249  * depending on the file extension.
250  */
buildLanguageVectors()251 void ASFormatter::buildLanguageVectors()
252 {
253 	if (getFileType() == formatterFileType)  // don't build unless necessary
254 		return;
255 
256 	formatterFileType = getFileType();
257 
258 	headers->clear();
259 	nonParenHeaders->clear();
260 	preDefinitionHeaders->clear();
261 	preCommandHeaders->clear();
262 	operators->clear();
263 	assignmentOperators->clear();
264 	castOperators->clear();
265 
266 	ASResource::buildHeaders(headers, getFileType());
267 	ASResource::buildNonParenHeaders(nonParenHeaders, getFileType());
268 	ASResource::buildPreDefinitionHeaders(preDefinitionHeaders, getFileType());
269 	ASResource::buildPreCommandHeaders(preCommandHeaders, getFileType());
270 	if (operators->size() == 0)
271 		ASResource::buildOperators(operators);
272 	if (assignmentOperators->size() == 0)
273 		ASResource::buildAssignmentOperators(assignmentOperators);
274 	if (castOperators->size() == 0)
275 		ASResource::buildCastOperators(castOperators);
276 }
277 
278 /**
279  * set the variables for each preefined style.
280  * this will override any previous settings.
281  */
fixOptionVariableConflicts()282 void ASFormatter::fixOptionVariableConflicts()
283 {
284 	if (formattingStyle == STYLE_ALLMAN)
285 	{
286 		setBracketFormatMode(BREAK_MODE);
287 		setBlockIndent(false);
288 		setBracketIndent(false);
289 	}
290 	else if (formattingStyle == STYLE_JAVA)
291 	{
292 		setBracketFormatMode(ATTACH_MODE);
293 		setBlockIndent(false);
294 		setBracketIndent(false);
295 	}
296 	else if (formattingStyle == STYLE_KandR)
297 	{
298 		setBracketFormatMode(LINUX_MODE);
299 		setBlockIndent(false);
300 		setBracketIndent(false);
301 	}
302 	else if (formattingStyle == STYLE_STROUSTRUP)
303 	{
304 		setBracketFormatMode(STROUSTRUP_MODE);
305 		setBlockIndent(false);
306 		setBracketIndent(false);
307 		if (!getIndentManuallySet())
308 		{
309 			if (getIndentString() == "\t")
310 				setTabIndentation(5, getForceTabIndentation());
311 			else
312 				setSpaceIndentation(5);
313 		}
314 	}
315 	else if (formattingStyle == STYLE_WHITESMITH)
316 	{
317 		setBracketFormatMode(BREAK_MODE);
318 		setBlockIndent(false);
319 		setBracketIndent(true);
320 		setClassIndent(true);
321 		setSwitchIndent(true);
322 	}
323 	else if (formattingStyle == STYLE_BANNER)
324 	{
325 		setBracketFormatMode(ATTACH_MODE);
326 		setBlockIndent(false);
327 		setBracketIndent(true);
328 		setClassIndent(true);
329 		setSwitchIndent(true);
330 	}
331 	else if (formattingStyle == STYLE_GNU)
332 	{
333 		setBracketFormatMode(BREAK_MODE);
334 		setBlockIndent(true);
335 		setBracketIndent(false);
336 		if (!getIndentManuallySet())
337 		{
338 			if (getIndentString() == "\t")
339 				setTabIndentation(2, getForceTabIndentation());
340 			else
341 				setSpaceIndentation(2);
342 		}
343 	}
344 	else if (formattingStyle == STYLE_LINUX)
345 	{
346 		setBracketFormatMode(LINUX_MODE);
347 		setBlockIndent(false);
348 		setBracketIndent(false);
349 		if (!getIndentManuallySet())
350 		{
351 			if (getIndentString() == "\t")
352 				setTabIndentation(8, getForceTabIndentation());
353 			else
354 				setSpaceIndentation(8);
355 		}
356 		if (!getMinConditionalManuallySet())
357 			setMinConditionalIndentLength(getIndentLength() / 2);
358 	}
359 	else if (formattingStyle == STYLE_HORSTMANN)
360 	{
361 		setBracketFormatMode(HORSTMANN_MODE);
362 		setBlockIndent(false);
363 		setBracketIndent(false);
364 		setSwitchIndent(true);
365 		if (!getIndentManuallySet())
366 		{
367 			if (getIndentString() == "\t")
368 				setTabIndentation(3, getForceTabIndentation());
369 			else
370 				setSpaceIndentation(3);
371 		}
372 	}
373 	else if (formattingStyle == STYLE_1TBS)
374 	{
375 		setBracketFormatMode(LINUX_MODE);
376 		setBlockIndent(false);
377 		setBracketIndent(false);
378 		setAddBracketsMode(true);
379 	}
380 
381 	// add-one-line-brackets implies keep-one-line-blocks
382 	if (shouldAddOneLineBrackets)
383 		setBreakOneLineBlocksMode(false);
384 	// cannot have both indent-blocks and indent-brackets, default to indent-blocks
385 	if (getBlockIndent())
386 		setBracketIndent(false);
387 }
388 
389 /**
390  * get the next formatted line.
391  *
392  * @return    formatted line.
393  */
394 
nextLine()395 string ASFormatter::nextLine()
396 {
397 	const string *newHeader;
398 	bool isInVirginLine = isVirgin;
399 	isCharImmediatelyPostComment = false;
400 	isPreviousCharPostComment = false;
401 	isCharImmediatelyPostLineComment = false;
402 	isCharImmediatelyPostOpenBlock = false;
403 	isCharImmediatelyPostCloseBlock = false;
404 	isCharImmediatelyPostTemplate = false;
405 	traceLineNumber++;
406 
407 	while (!isLineReady)
408 	{
409 		if (shouldReparseCurrentChar)
410 			shouldReparseCurrentChar = false;
411 		else if (!getNextChar())
412 		{
413 			breakLine();
414 			return beautify(readyFormattedLine);
415 		}
416 		else // stuff to do when reading a new character...
417 		{
418 			// make sure that a virgin '{' at the begining of the file will be treated as a block...
419 			if (isInVirginLine && currentChar == '{'
420 			        && currentLineBeginsWithBracket	// lineBeginsWith('{')
421 			        && previousCommandChar == ' ')
422 				previousCommandChar = '{';
423 			if (clearNonInStatement)
424 			{
425 				isNonInStatementArray = false;
426 				clearNonInStatement = false;
427 			}
428 			if (isInHorstmannRunIn)
429 				isInLineBreak = false;
430 			if (!isWhiteSpace(currentChar))
431 				isInHorstmannRunIn = false;
432 			isPreviousCharPostComment = isCharImmediatelyPostComment;
433 			isCharImmediatelyPostComment = false;
434 			isCharImmediatelyPostTemplate = false;
435 			isCharImmediatelyPostReturn = false;
436 			isCharImmediatelyPostOperator = false;
437 			isCharImmediatelyPostOpenBlock = false;
438 			isCharImmediatelyPostCloseBlock = false;
439 		}
440 
441 //		if (inLineNumber >= 7)
442 //			int x = 1;
443 
444 		if (shouldBreakLineAtNextChar && !isWhiteSpace(currentChar))
445 		{
446 			isInLineBreak = true;
447 			shouldBreakLineAtNextChar = false;
448 		}
449 
450 		if (isInExecSQL && !passedSemicolon)
451 		{
452 			if (currentChar == ';')
453 				passedSemicolon = true;
454 			appendCurrentChar();
455 			continue;
456 		}
457 
458 		if (isInLineComment)
459 		{
460 			formatLineCommentBody();
461 			continue;
462 		}
463 		else if (isInComment)
464 		{
465 			formatCommentBody();
466 			continue;
467 		}
468 
469 		// not in line comment or comment
470 
471 		else if (isInQuote)
472 		{
473 			formatQuoteBody();
474 			continue;
475 		}
476 
477 		if (isSequenceReached("//"))
478 		{
479 			formatLineCommentOpener();
480 			continue;
481 		}
482 		else if (isSequenceReached("/*"))
483 		{
484 			formatCommentOpener();
485 			continue;
486 		}
487 		else if (currentChar == '"' || currentChar == '\'')
488 		{
489 			formatQuoteOpener();
490 			continue;
491 		}
492 		// treat these preprocessor statements as a line comment
493 		else if (currentChar =='#')
494 		{
495 			if (isSequenceReached("#region")
496 			        || isSequenceReached("#endregion")
497 			        || isSequenceReached("#error")
498 			        || isSequenceReached("#warning"))
499 			{
500 				// check for horstmann run-in
501 				if (formattedLine[0] == '{')
502 				{
503 					isInLineBreak = true;
504 					isInHorstmannRunIn = false;
505 				}
506 				isInLineComment = true;
507 				appendCurrentChar();
508 				continue;
509 			}
510 		}
511 
512 		if (isInPreprocessor)
513 		{
514 			appendCurrentChar();
515 			continue;
516 		}
517 
518 		// handle white space - needed to simplify the rest.
519 		if (isWhiteSpace(currentChar))
520 		{
521 			appendCurrentChar();
522 			continue;
523 		}
524 
525 		/* not in MIDDLE of quote or comment or SQL or white-space of any type ... */
526 
527 		// check if in preprocessor
528 		// ** isInPreprocessor will be automatically reset at the begining
529 		//    of a new line in getnextChar()
530 		if (currentChar == '#')
531 		{
532 			isInPreprocessor = true;
533 			// check for horstmann run-in
534 			if (formattedLine[0] == '{')
535 			{
536 				isInLineBreak = true;
537 				isInHorstmannRunIn = false;
538 			}
539 			processPreprocessor();
540 			//  need to fall thru here to reset the variables
541 		}
542 
543 		/* not in preprocessor ... */
544 
545 		if (isImmediatelyPostComment)
546 		{
547 			isImmediatelyPostComment = false;
548 			isCharImmediatelyPostComment = true;
549 		}
550 
551 		if (isImmediatelyPostLineComment)
552 		{
553 			isImmediatelyPostLineComment = false;
554 			isCharImmediatelyPostLineComment = true;
555 		}
556 
557 		if (isImmediatelyPostReturn)
558 		{
559 			isImmediatelyPostReturn = false;
560 			isCharImmediatelyPostReturn = true;
561 		}
562 
563 		if (isImmediatelyPostOperator)
564 		{
565 			isImmediatelyPostOperator = false;
566 			isCharImmediatelyPostOperator = true;
567 		}
568 
569 		// reset isImmediatelyPostHeader information
570 		if (isImmediatelyPostHeader)
571 		{
572 			// should brackets be added
573 			if (currentChar != '{' && shouldAddBrackets)
574 			{
575 				bool bracketsAdded = addBracketsToStatement();
576 				if (bracketsAdded && !shouldAddOneLineBrackets)
577 				{
578 					size_t firstText = currentLine.find_first_not_of(" \t");
579 					assert(firstText != string::npos);
580 					if ((int) firstText == charNum)
581 						breakCurrentOneLineBlock = true;
582 				}
583 			}
584 
585 			// Make sure headers are broken from their succeeding blocks
586 			// (e.g.
587 			//     if (isFoo) DoBar();
588 			//  should become
589 			//     if (isFoo)
590 			//         DoBar;
591 			// )
592 			// But treat else if() as a special case which should not be broken!
593 			if (shouldBreakOneLineStatements
594 			        && isOkToBreakBlock(bracketTypeStack->back()))
595 			{
596 				// if may break 'else if()'s, then simply break the line
597 				if (shouldBreakElseIfs)
598 					isInLineBreak = true;
599 			}
600 
601 			isImmediatelyPostHeader = false;
602 		}
603 
604 		if (passedSemicolon)    // need to break the formattedLine
605 		{
606 			passedSemicolon = false;
607 			if (parenStack->back() == 0 && currentChar != ';') // allow ;;
608 			{
609 				// does a one-line statement have ending comments?
610 				if (isBracketType(bracketTypeStack->back(), SINGLE_LINE_TYPE))
611 				{
612 					size_t blockEnd = currentLine.rfind(AS_CLOSE_BRACKET);
613 					assert(blockEnd != string::npos);
614 					// move ending comments to this formattedLine
615 					if (isBeforeAnyLineEndComment(blockEnd))
616 					{
617 						size_t commentStart = currentLine.find_first_not_of(" \t", blockEnd + 1);
618 						assert(commentStart != string::npos);
619 						assert((currentLine.compare(commentStart, 2, "//") == 0)
620 						       || (currentLine.compare(commentStart, 2, "/*") == 0));
621 						size_t commentLength = currentLine.length() - commentStart;
622 						formattedLine.append(getIndentLength() - 1, ' ');
623 						formattedLine.append(currentLine, commentStart, commentLength);
624 						currentLine.erase(commentStart, commentLength);
625 					}
626 				}
627 				isInExecSQL = false;
628 				shouldReparseCurrentChar = true;
629 				isInLineBreak = true;
630 				if (needHeaderOpeningBracket)
631 				{
632 					isCharImmediatelyPostCloseBlock = true;
633 					needHeaderOpeningBracket = false;
634 				}
635 				continue;
636 			}
637 		}
638 
639 		if (passedColon)
640 		{
641 			passedColon = false;
642 			if (parenStack->back() == 0 && !isBeforeAnyComment())
643 			{
644 				shouldReparseCurrentChar = true;
645 				isInLineBreak = true;
646 				continue;
647 			}
648 		}
649 
650 		// Check if in template declaration, e.g. foo<bar> or foo<bar,fig>
651 		// If so, set isInTemplate to true
652 		if (!isInTemplate && currentChar == '<')
653 		{
654 			int maxTemplateDepth = 0;
655 			templateDepth = 0;
656 			for (size_t i = charNum;
657 			        i < currentLine.length();
658 			        i++)
659 			{
660 				char currentChar = currentLine[i];
661 
662 				if (currentChar == '<')
663 				{
664 					templateDepth++;
665 					maxTemplateDepth++;
666 				}
667 				else if (currentChar == '>')
668 				{
669 					templateDepth--;
670 					if (templateDepth == 0)
671 					{
672 						// this is a template!
673 						isInTemplate = true;
674 						templateDepth = maxTemplateDepth;
675 						break;
676 					}
677 				}
678 				else if (currentLine.compare(i, 2, "&&") == 0
679 				         || currentLine.compare(i, 2, "||") == 0)
680 				{
681 					// this is not a template -> leave...
682 					isInTemplate = false;
683 					break;
684 				}
685 				else if (currentChar == ','       // comma,     e.g. A<int, char>
686 				         || currentChar == '&'    // reference, e.g. A<int&>
687 				         || currentChar == '*'    // pointer,   e.g. A<int*>
688 				         || currentChar == ':'    // ::,        e.g. std::string
689 				         || currentChar == '['    // []         e.g. string[]
690 				         || currentChar == ']'    // []         e.g. string[]
691 				         || currentChar == '('    // (...)      e.g. function definition
692 				         || currentChar == ')')   // (...)      e.g. function definition
693 				{
694 					continue;
695 				}
696 				else if (!isLegalNameChar(currentChar) && !isWhiteSpace(currentChar))
697 				{
698 					// this is not a template -> leave...
699 					isInTemplate = false;
700 					break;
701 				}
702 			}
703 		}
704 
705 		// handle parenthesies
706 		if (currentChar == '(' || currentChar == '[' || (isInTemplate && currentChar == '<'))
707 		{
708 			parenStack->back()++;
709 			if (currentChar == '[')
710 				isInBlParen = true;
711 		}
712 		else if (currentChar == ')' || currentChar == ']' || (isInTemplate && currentChar == '>'))
713 		{
714 			parenStack->back()--;
715 			if (isInTemplate && currentChar == '>')
716 			{
717 				templateDepth--;
718 				if (templateDepth == 0)
719 				{
720 					isInTemplate = false;
721 					isCharImmediatelyPostTemplate = true;
722 				}
723 			}
724 
725 			// check if this parenthesis closes a header, e.g. if (...), while (...)
726 			if (isInHeader && parenStack->back() == 0)
727 			{
728 				isInHeader = false;
729 				isImmediatelyPostHeader = true;
730 			}
731 			if (currentChar == ']')
732 				isInBlParen = false;
733 			if (currentChar == ')')
734 			{
735 				foundCastOperator = false;
736 				if (parenStack->back() == 0)
737 					isInAsm = false;
738 			}
739 		}
740 
741 		// handle brackets
742 		if (currentChar == '{' || currentChar == '}')
743 		{
744 			// if appendOpeningBracket this was already done for the original bracket
745 			if (currentChar == '{' && !appendOpeningBracket)
746 			{
747 				BracketType newBracketType = getBracketType();
748 				foundNamespaceHeader = false;
749 				foundClassHeader = false;
750 				foundStructHeader = false;
751 				foundInterfaceHeader = false;
752 				foundPreDefinitionHeader = false;
753 				foundPreCommandHeader = false;
754 				isInPotentialCalculation = false;
755 				isJavaStaticConstructor = false;
756 				needHeaderOpeningBracket = false;
757 
758 				isPreviousBracketBlockRelated = !isBracketType(newBracketType, ARRAY_TYPE);
759 				bracketTypeStack->push_back(newBracketType);
760 				preBracketHeaderStack->push_back(currentHeader);
761 				currentHeader = NULL;
762 				structStack->push_back(isInIndentableStruct);
763 				if (isBracketType(newBracketType, STRUCT_TYPE) && isCStyle())
764 					isInIndentableStruct = isStructAccessModified(currentLine, charNum);
765 				else
766 					isInIndentableStruct = false;
767 			}
768 
769 			// this must be done before the bracketTypeStack is popped
770 			BracketType bracketType = bracketTypeStack->back();
771 			bool isOpeningArrayBracket = (isBracketType(bracketType, ARRAY_TYPE)
772 			                              && bracketTypeStack->size() >= 2
773 			                              && !isBracketType((*bracketTypeStack)[bracketTypeStack->size()-2], ARRAY_TYPE)
774 			                             );
775 
776 			if (currentChar == '}')
777 			{
778 				// if a request has been made to append a post block empty line,
779 				// but the block exists immediately before a closing bracket,
780 				// then there is no need for the post block empty line.
781 				isAppendPostBlockEmptyLineRequested = false;
782 				breakCurrentOneLineBlock = false;
783 				isInAsmBlock = false;
784 
785 				// added for release 1.24
786 				// TODO: remove at the appropriate time
787 				assert(isInAsm == false);
788 				assert(isInAsmOneLine == false);
789 				assert(isInQuote == false);
790 				isInAsm = isInAsmOneLine = isInQuote = false;
791 				// end remove
792 
793 				if (bracketTypeStack->size() > 1)
794 				{
795 					previousBracketType = bracketTypeStack->back();
796 					bracketTypeStack->pop_back();
797 					isPreviousBracketBlockRelated = !isBracketType(bracketType, ARRAY_TYPE);
798 				}
799 				else
800 				{
801 					previousBracketType = NULL_TYPE;
802 					isPreviousBracketBlockRelated = false;
803 				}
804 
805 				if (!preBracketHeaderStack->empty())
806 				{
807 					currentHeader = preBracketHeaderStack->back();
808 					preBracketHeaderStack->pop_back();
809 				}
810 				else
811 					currentHeader = NULL;
812 
813 				if (!structStack->empty())
814 				{
815 					isInIndentableStruct = structStack->back();
816 					structStack->pop_back();
817 				}
818 				else
819 					isInIndentableStruct = false;
820 
821 				if (isBracketType(bracketType, ARRAY_NIS_TYPE) && !isBracketType(bracketType, SINGLE_LINE_TYPE))
822 					clearNonInStatement = true;
823 			}
824 
825 			// format brackets
826 			appendOpeningBracket = false;
827 			if (isBracketType(bracketType, ARRAY_TYPE))
828 			{
829 				formatArrayBrackets(bracketType, isOpeningArrayBracket);
830 			}
831 			else
832 			{
833 				if (currentChar == '{')
834 					formatOpeningBracket(bracketType);
835 				else
836 					formatClosingBracket(bracketType);
837 			}
838 			continue;
839 		}
840 
841 		if ((((previousCommandChar == '{' && isPreviousBracketBlockRelated)
842 		        || ((previousCommandChar == '}'
843 		             && !isImmediatelyPostEmptyBlock
844 		             && isPreviousBracketBlockRelated
845 		             && !isPreviousCharPostComment       // Fixes wrongly appended newlines after '}' immediately after comments
846 		             && peekNextChar() != ' '
847 		             && !isBracketType(previousBracketType,  DEFINITION_TYPE))
848 		            && !isBracketType(bracketTypeStack->back(),  DEFINITION_TYPE)))
849 		        && isOkToBreakBlock(bracketTypeStack->back()))
850 		        // check for array
851 		        || (isBracketType(bracketTypeStack->back(), ARRAY_TYPE)
852 		            && !isBracketType(bracketTypeStack->back(), SINGLE_LINE_TYPE)
853 		            && isNonInStatementArray))
854 		{
855 			isCharImmediatelyPostOpenBlock = (previousCommandChar == '{');
856 			isCharImmediatelyPostCloseBlock = (previousCommandChar == '}');
857 
858 			if (isCharImmediatelyPostOpenBlock
859 			        && !isCharImmediatelyPostComment
860 			        && !isCharImmediatelyPostLineComment)
861 			{
862 				previousCommandChar = ' ';
863 
864 				if (bracketFormatMode == NONE_MODE)
865 				{
866 					if (shouldBreakOneLineBlocks
867 					        && isBracketType(bracketTypeStack->back(),  SINGLE_LINE_TYPE))
868 						isInLineBreak = true;
869 					else if (currentLineBeginsWithBracket)
870 						formatRunIn();
871 					else
872 						breakLine();
873 				}
874 				else if (bracketFormatMode == HORSTMANN_MODE
875 				         && currentChar != '#')
876 					formatRunIn();
877 				else
878 					isInLineBreak = true;
879 			}
880 			else if (isCharImmediatelyPostCloseBlock
881 			         && shouldBreakOneLineStatements
882 			         && (isLegalNameChar(currentChar) && currentChar != '.')
883 			         && !isCharImmediatelyPostComment)
884 			{
885 				previousCommandChar = ' ';
886 				isInLineBreak = true;
887 			}
888 		}
889 
890 		// reset block handling flags
891 		isImmediatelyPostEmptyBlock = false;
892 
893 		// look for headers
894 		bool isPotentialHeader = isCharPotentialHeader(currentLine, charNum);
895 
896 		if (isPotentialHeader && !isInTemplate)
897 		{
898 			isNonParenHeader = false;
899 			foundClosingHeader = false;
900 			newHeader = findHeader(headers);
901 
902 			if (newHeader != NULL)
903 			{
904 				char peekChar = ASBase::peekNextChar(currentLine, charNum + newHeader->length() - 1);
905 
906 				// is not a header if part of a definition
907 				if (peekChar == ',' || peekChar == ')')
908 					newHeader = NULL;
909 				// the following accessor definitions are NOT headers
910 				// goto default; is NOT a header
911 				else if ((newHeader == &AS_GET || newHeader == &AS_SET || newHeader == &AS_DEFAULT)
912 				         && peekChar == ';')
913 				{
914 					newHeader = NULL;
915 				}
916 			}
917 
918 			if (newHeader != NULL)
919 			{
920 				const string *previousHeader;
921 
922 				// recognize closing headers of do..while, if..else, try..catch..finally
923 				if ((newHeader == &AS_ELSE && currentHeader == &AS_IF)
924 				        || (newHeader == &AS_WHILE && currentHeader == &AS_DO)
925 				        || (newHeader == &AS_CATCH && currentHeader == &AS_TRY)
926 				        || (newHeader == &AS_CATCH && currentHeader == &AS_CATCH)
927 				        || (newHeader == &AS_FINALLY && currentHeader == &AS_TRY)
928 				        || (newHeader == &AS_FINALLY && currentHeader == &AS_CATCH)
929 				        || (newHeader == &AS_SET && currentHeader == &AS_GET)
930 				        || (newHeader == &AS_REMOVE && currentHeader == &AS_ADD))
931 					foundClosingHeader = true;
932 
933 				previousHeader = currentHeader;
934 				currentHeader = newHeader;
935 				needHeaderOpeningBracket = true;
936 
937 				if (foundClosingHeader && previousNonWSChar == '}')
938 				{
939 					if (isOkToBreakBlock(bracketTypeStack->back()))
940 						isLineBreakBeforeClosingHeader();
941 
942 					// get the adjustment for a comment following the closing header
943 					if (isInLineBreak)
944 						nextLineSpacePadNum = getNextLineCommentAdjustment();
945 					else
946 						spacePadNum = getCurrentLineCommentAdjustment();
947 				}
948 
949 				// check if the found header is non-paren header
950 				isNonParenHeader = findHeader(nonParenHeaders) != NULL;
951 
952 				// join 'else if' statements
953 				if (currentHeader == &AS_IF && previousHeader == &AS_ELSE && isInLineBreak
954 				        && !shouldBreakElseIfs && !isCharImmediatelyPostLineComment)
955 				{
956 					// 'else' must be last thing on the line, but must not be #else
957 					size_t start = formattedLine.length() >= 6 ? formattedLine.length()-6 : 0;
958 					if (formattedLine.find("else", start) != string::npos
959 					        && formattedLine.find("#else", start) == string::npos)
960 					{
961 						appendSpacePad();
962 						isInLineBreak = false;
963 					}
964 				}
965 
966 				appendSequence(*currentHeader);
967 				goForward(currentHeader->length() - 1);
968 				// if a paren-header is found add a space after it, if needed
969 				// this checks currentLine, appendSpacePad() checks formattedLine
970 				// in C# 'catch' can be either a paren or non-paren header
971 				if (shouldPadHeader
972 				        && (!isNonParenHeader || (currentHeader == &AS_CATCH && peekNextChar() == '('))
973 				        && charNum < (int) currentLine.length() && !isWhiteSpace(currentLine[charNum+1]))
974 					appendSpacePad();
975 
976 				// Signal that a header has been reached
977 				// *** But treat a closing while() (as in do...while)
978 				//     as if it were NOT a header since a closing while()
979 				//     should never have a block after it!
980 				if (!(foundClosingHeader && currentHeader == &AS_WHILE))
981 				{
982 					isInHeader = true;
983 
984 					// in C# 'catch' and 'delegate' can be a paren or non-paren header
985 					if (isNonParenHeader && !isSharpStyleWithParen(currentHeader))
986 					{
987 						isImmediatelyPostHeader = true;
988 						isInHeader = false;
989 					}
990 				}
991 
992 				if (shouldBreakBlocks
993 				        && isOkToBreakBlock(bracketTypeStack->back()))
994 				{
995 					if (previousHeader == NULL
996 					        && !foundClosingHeader
997 					        && !isCharImmediatelyPostOpenBlock
998 					        && !isImmediatelyPostCommentOnly)
999 					{
1000 						isPrependPostBlockEmptyLineRequested = true;
1001 					}
1002 
1003 					if (currentHeader == &AS_ELSE
1004 					        || currentHeader == &AS_CATCH
1005 					        || currentHeader == &AS_FINALLY
1006 					        || foundClosingHeader)
1007 					{
1008 						isPrependPostBlockEmptyLineRequested = false;
1009 					}
1010 
1011 					if (shouldBreakClosingHeaderBlocks
1012 					        && isCharImmediatelyPostCloseBlock
1013 					        && !isImmediatelyPostCommentOnly
1014 					        && currentHeader != &AS_WHILE)    // closing do-while block
1015 					{
1016 						isPrependPostBlockEmptyLineRequested = true;
1017 					}
1018 
1019 				}
1020 
1021 				continue;
1022 			}
1023 			else if ((newHeader = findHeader(preDefinitionHeaders)) != NULL
1024 			         && parenStack->back() == 0)
1025 			{
1026 				if (newHeader == &AS_NAMESPACE)
1027 					foundNamespaceHeader = true;
1028 				if (newHeader == &AS_CLASS)
1029 					foundClassHeader = true;
1030 				if (newHeader == &AS_STRUCT)
1031 					foundStructHeader = true;
1032 				if (newHeader == &AS_INTERFACE)
1033 					foundInterfaceHeader = true;
1034 				foundPreDefinitionHeader = true;
1035 				appendSequence(*newHeader);
1036 				goForward(newHeader->length() - 1);
1037 
1038 				continue;
1039 			}
1040 			else if ((newHeader = findHeader(preCommandHeaders)) != NULL)
1041 			{
1042 				if (!(*newHeader == AS_CONST && previousCommandChar != ')')) // 'const' member functions is a command bracket
1043 					foundPreCommandHeader = true;
1044 				appendSequence(*newHeader);
1045 				goForward(newHeader->length() - 1);
1046 
1047 				continue;
1048 			}
1049 			else if ((newHeader = findHeader(castOperators)) != NULL)
1050 			{
1051 				foundCastOperator = true;
1052 				appendSequence(*newHeader);
1053 				goForward(newHeader->length() - 1);
1054 				continue;
1055 			}
1056 		}   // (isPotentialHeader && !isInTemplate)
1057 
1058 		if (isInLineBreak)          // OK to break line here
1059 		{
1060 			breakLine();
1061 			if (isInVirginLine)		// adjust for the first line
1062 			{
1063 				lineCommentNoBeautify = lineCommentNoIndent;
1064 				lineCommentNoIndent = false;
1065 			}
1066 		}
1067 
1068 		if (previousNonWSChar == '}' || currentChar == ';')
1069 		{
1070 			if (currentChar == ';')
1071 			{
1072 				if ((shouldBreakOneLineStatements
1073 				        || isBracketType(bracketTypeStack->back(),  SINGLE_LINE_TYPE))
1074 				        && isOkToBreakBlock(bracketTypeStack->back()))
1075 				{
1076 					passedSemicolon = true;
1077 				}
1078 
1079 				// append post block empty line for unbracketed header
1080 				if (shouldBreakBlocks && currentHeader != NULL && parenStack->back() == 0)
1081 				{
1082 					isAppendPostBlockEmptyLineRequested = true;
1083 				}
1084 			}
1085 
1086 			// end of block if a closing bracket was found
1087 			// or an opening bracket was not found (';' closes)
1088 			if (currentChar != ';'
1089 			        || (needHeaderOpeningBracket && parenStack->back() == 0))
1090 				currentHeader = NULL;
1091 
1092 			foundQuestionMark = false;
1093 			foundNamespaceHeader = false;
1094 			foundClassHeader = false;
1095 			foundStructHeader = false;
1096 			foundInterfaceHeader = false;
1097 			foundPreDefinitionHeader = false;
1098 			foundPreCommandHeader = false;
1099 			foundCastOperator = false;
1100 			isInPotentialCalculation = false;
1101 			isSharpAccessor = false;
1102 			isSharpDelegate = false;
1103 			isInExtern = false;
1104 			nonInStatementBracket = 0;
1105 		}
1106 
1107 		if (currentChar == ':' && shouldBreakOneLineStatements)
1108 		{
1109 			if (isInCase
1110 			        && previousChar != ':'          // not part of '::'
1111 			        && peekNextChar() != ':')       // not part of '::'
1112 			{
1113 				isInCase = false;
1114 				passedColon = true;
1115 			}
1116 			else if (isCStyle()                     // for C/C++ only
1117 			         && !foundQuestionMark          // not in a ... ? ... : ... sequence
1118 			         && !foundPreDefinitionHeader   // not in a definition block (e.g. class foo : public bar
1119 			         && previousCommandChar != ')'  // not immediately after closing paren of a method header, e.g. ASFormatter::ASFormatter(...) : ASBeautifier(...)
1120 			         && previousChar != ':'         // not part of '::'
1121 			         && peekNextChar() != ':'       // not part of '::'
1122 			         && !isdigit(peekNextChar())    // not a bit field
1123 			         && !isInAsm                    // not in extended assembler
1124 			         && !isInAsmOneLine             // not in extended assembler
1125 			         && !isInAsmBlock)              // not in extended assembler
1126 			{
1127 				passedColon = true;
1128 			}
1129 		}
1130 
1131 		if (currentChar == '?')
1132 			foundQuestionMark = true;
1133 
1134 		if (isPotentialHeader &&  !isInTemplate)
1135 		{
1136 			if (findKeyword(currentLine, charNum, AS_CASE)
1137 			        || findKeyword(currentLine, charNum, AS_DEFAULT))
1138 				isInCase = true;
1139 
1140 			if (findKeyword(currentLine, charNum, AS_NEW))
1141 				isInPotentialCalculation = false;
1142 
1143 			if (findKeyword(currentLine, charNum, AS_RETURN))
1144 			{
1145 				isInPotentialCalculation = true;	// return is the same as an = sign
1146 				isImmediatelyPostReturn = true;
1147 			}
1148 
1149 			if (findKeyword(currentLine, charNum, AS_OPERATOR))
1150 				isImmediatelyPostOperator = true;
1151 
1152 			if (isCStyle() && findKeyword(currentLine, charNum, AS_EXTERN))
1153 				isInExtern = true;
1154 
1155 			if (isCStyle() && isExecSQL(currentLine, charNum))
1156 				isInExecSQL = true;
1157 
1158 			if (isCStyle())
1159 			{
1160 				if (findKeyword(currentLine, charNum, AS_ASM)
1161 				        || findKeyword(currentLine, charNum, AS__ASM__))
1162 				{
1163 					isInAsm = true;
1164 				}
1165 				else if (findKeyword(currentLine, charNum, AS_MS_ASM)		// microsoft specific
1166 				         || findKeyword(currentLine, charNum, AS_MS__ASM))
1167 				{
1168 					int index = 4;
1169 					if (peekNextChar() == '_')	// check for __asm
1170 						index = 5;
1171 
1172 					char peekedChar = ASBase::peekNextChar(currentLine, charNum + index);
1173 					if (peekedChar == '{' || peekedChar == ' ')
1174 						isInAsmBlock = true;
1175 					else
1176 						isInAsmOneLine = true;
1177 				}
1178 			}
1179 
1180 			if (isJavaStyle()
1181 			        && (findKeyword(currentLine, charNum, AS_STATIC)
1182 			            && isNextCharOpeningBracket(charNum + 6)))
1183 				isJavaStaticConstructor = true;
1184 
1185 			if (isSharpStyle()
1186 			        && (findKeyword(currentLine, charNum, AS_DELEGATE)
1187 			            || findKeyword(currentLine, charNum, AS_UNCHECKED)))
1188 				isSharpDelegate = true;
1189 
1190 			// append the entire name
1191 			string name = getCurrentWord(currentLine, charNum);
1192 			appendSequence(name);
1193 			goForward(name.length() - 1);
1194 
1195 			continue;
1196 
1197 		}   // (isPotentialHeader &&  !isInTemplate)
1198 
1199 		// determine if this is a potential calculation
1200 
1201 		bool isPotentialOperator = isCharPotentialOperator(currentChar);
1202 		newHeader = NULL;
1203 
1204 		if (isPotentialOperator)
1205 		{
1206 			newHeader = findOperator(operators);
1207 
1208 			if (newHeader != NULL)
1209 			{
1210 				// correct mistake of two >> closing a template
1211 				if (isInTemplate && (newHeader == &AS_GR_GR || newHeader == &AS_GR_GR_GR))
1212 					newHeader = &AS_GR;
1213 
1214 				if (!isInPotentialCalculation)
1215 				{
1216 					// must determine if newHeader is an assignment operator
1217 					// do NOT use findOperator!!!
1218 					if (find(assignmentOperators->begin(), assignmentOperators->end(), newHeader)
1219 					        != assignmentOperators->end())
1220 					{
1221 						char peekedChar = peekNextChar();
1222 						isInPotentialCalculation = (!(newHeader == &AS_EQUAL && peekedChar == '*')
1223 						                            && !(newHeader == &AS_EQUAL && peekedChar == '&'));
1224 					}
1225 				}
1226 			}
1227 		}
1228 
1229 		// process pointers and references
1230 		// check new header to elimnate things like '&&' sequence
1231 		if (isCStyle()
1232 		        && (newHeader == &AS_MULT || newHeader == &AS_BIT_AND)
1233 		        && isPointerOrReference()
1234 		        && !isDereferenceOrAddressOf())
1235 		{
1236 			formatPointerOrReference();
1237 			continue;
1238 		}
1239 
1240 		if (shouldPadOperators && newHeader != NULL)
1241 		{
1242 			padOperators(newHeader);
1243 			continue;
1244 		}
1245 
1246 		// pad commas and semi-colons
1247 		if (currentChar == ';'
1248 		        || (currentChar == ',' && shouldPadOperators))
1249 		{
1250 			char nextChar = ' ';
1251 			if (charNum + 1 < (int) currentLine.length())
1252 				nextChar = currentLine[charNum+1];
1253 			if (!isWhiteSpace(nextChar)
1254 			        && nextChar != '}'
1255 			        && nextChar != ')'
1256 			        && nextChar != ']'
1257 			        && nextChar != '>'
1258 			        && nextChar != ';'
1259 			        && !isBeforeAnyComment()
1260 			        /* && !(isBracketType(bracketTypeStack->back(), ARRAY_TYPE)) */
1261 			   )
1262 			{
1263 				appendCurrentChar();
1264 				appendSpaceAfter();
1265 				continue;
1266 			}
1267 		}
1268 
1269 		if ((shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens)
1270 		        && (currentChar == '(' || currentChar == ')'))
1271 		{
1272 			padParens();
1273 			continue;
1274 		}
1275 
1276 		appendCurrentChar();
1277 	}   // end of while loop  *  end of while loop  *  end of while loop  *  end of while loop
1278 
1279 	// return a beautified (i.e. correctly indented) line.
1280 
1281 	string beautifiedLine;
1282 	size_t readyFormattedLineLength = trim(readyFormattedLine).length();
1283 
1284 	if (prependEmptyLine                // prepend a blank line before this formatted line
1285 	        && readyFormattedLineLength > 0
1286 	        && previousReadyFormattedLineLength > 0)
1287 	{
1288 		isLineReady = true;             // signal a waiting readyFormattedLine
1289 		beautifiedLine = beautify("");
1290 		previousReadyFormattedLineLength = 0;
1291 	}
1292 	else                                // format the current formatted line
1293 	{
1294 		isLineReady = false;
1295 		horstmannIndentInStatement = horstmannIndentChars;
1296 		beautifiedLine = beautify(readyFormattedLine);
1297 		previousReadyFormattedLineLength = readyFormattedLineLength;
1298 		// the enhancer is not called for new empty lines
1299 		// or no-indent line comments
1300 		if (!lineCommentNoBeautify)
1301 			enhancer->enhance(beautifiedLine, isInBeautifySQL);
1302 		horstmannIndentChars = 0;
1303 		lineCommentNoBeautify = lineCommentNoIndent;
1304 		lineCommentNoIndent = false;
1305 		isInBeautifySQL = isInExecSQL;
1306 	}
1307 
1308 	prependEmptyLine = false;
1309 	return beautifiedLine;
1310 }
1311 
1312 
1313 /**
1314  * check if there are any indented lines ready to be read by nextLine()
1315  *
1316  * @return    are there any indented lines ready?
1317  */
hasMoreLines() const1318 bool ASFormatter::hasMoreLines() const
1319 {
1320 	return !endOfCodeReached;
1321 }
1322 
1323 /**
1324  * comparison function for BracketType enum
1325  */
isBracketType(BracketType a,BracketType b) const1326 bool ASFormatter::isBracketType(BracketType a, BracketType b) const
1327 {
1328 	return ((a & b) == b);
1329 }
1330 
1331 /**
1332  * set the formatting style.
1333  *
1334  * @param mode         the formatting style.
1335  */
setFormattingStyle(FormatStyle style)1336 void ASFormatter::setFormattingStyle(FormatStyle style)
1337 {
1338 	formattingStyle = style;
1339 }
1340 
1341 /**
1342  * set the add brackets mode.
1343  * options:
1344  *    true     brackets added to headers for single line statements.
1345  *    false    brackets NOT added to headers for single line statements.
1346  *
1347  * @param mode         the bracket formatting mode.
1348  */
setAddBracketsMode(bool state)1349 void ASFormatter::setAddBracketsMode(bool state)
1350 {
1351 	shouldAddBrackets = state;
1352 }
1353 
1354 /**
1355  * set the add one line brackets mode.
1356  * options:
1357  *    true     one line brackets added to headers for single line statements.
1358  *    false    one line brackets NOT added to headers for single line statements.
1359  *
1360  * @param mode         the bracket formatting mode.
1361  */
setAddOneLineBracketsMode(bool state)1362 void ASFormatter::setAddOneLineBracketsMode(bool state)
1363 {
1364 	shouldAddBrackets = state;
1365 	shouldAddOneLineBrackets = state;
1366 }
1367 
1368 /**
1369  * set the bracket formatting mode.
1370  * options:
1371  *
1372  * @param mode         the bracket formatting mode.
1373  */
setBracketFormatMode(BracketMode mode)1374 void ASFormatter::setBracketFormatMode(BracketMode mode)
1375 {
1376 	bracketFormatMode = mode;
1377 }
1378 
1379 /**
1380  * set closing header bracket breaking mode
1381  * options:
1382  *    true     brackets just before closing headers (e.g. 'else', 'catch')
1383  *             will be broken, even if standard brackets are attached.
1384  *    false    closing header brackets will be treated as standard brackets.
1385  *
1386  * @param state         the closing header bracket breaking mode.
1387  */
setBreakClosingHeaderBracketsMode(bool state)1388 void ASFormatter::setBreakClosingHeaderBracketsMode(bool state)
1389 {
1390 	shouldBreakClosingHeaderBrackets = state;
1391 }
1392 
1393 /**
1394  * set 'else if()' breaking mode
1395  * options:
1396  *    true     'else' headers will be broken from their succeeding 'if' headers.
1397  *    false    'else' headers will be attached to their succeeding 'if' headers.
1398  *
1399  * @param state         the 'else if()' breaking mode.
1400  */
setBreakElseIfsMode(bool state)1401 void ASFormatter::setBreakElseIfsMode(bool state)
1402 {
1403 	shouldBreakElseIfs = state;
1404 }
1405 
1406 /**
1407  * set operator padding mode.
1408  * options:
1409  *    true     statement operators will be padded with spaces around them.
1410  *    false    statement operators will not be padded.
1411  *
1412  * @param state         the padding mode.
1413  */
setOperatorPaddingMode(bool state)1414 void ASFormatter::setOperatorPaddingMode(bool state)
1415 {
1416 	shouldPadOperators = state;
1417 }
1418 
1419 /**
1420  * set parenthesis outside padding mode.
1421  * options:
1422  *    true     statement parenthesiss will be padded with spaces around them.
1423  *    false    statement parenthesiss will not be padded.
1424  *
1425  * @param state         the padding mode.
1426  */
setParensOutsidePaddingMode(bool state)1427 void ASFormatter::setParensOutsidePaddingMode(bool state)
1428 {
1429 	shouldPadParensOutside = state;
1430 }
1431 
1432 /**
1433  * set parenthesis inside padding mode.
1434  * options:
1435  *    true     statement parenthesis will be padded with spaces around them.
1436  *    false    statement parenthesis will not be padded.
1437  *
1438  * @param state         the padding mode.
1439  */
setParensInsidePaddingMode(bool state)1440 void ASFormatter::setParensInsidePaddingMode(bool state)
1441 {
1442 	shouldPadParensInside = state;
1443 }
1444 
1445 /**
1446  * set header padding mode.
1447  * options:
1448  *    true     headers will be padded with spaces around them.
1449  *    false    headers will not be padded.
1450  *
1451  * @param state         the padding mode.
1452  */
setParensHeaderPaddingMode(bool state)1453 void ASFormatter::setParensHeaderPaddingMode(bool state)
1454 {
1455 	shouldPadHeader = state;
1456 }
1457 
1458 /**
1459  * set parenthesis unpadding mode.
1460  * options:
1461  *    true     statement parenthesis will be unpadded with spaces removed around them.
1462  *    false    statement parenthesis will not be unpadded.
1463  *
1464  * @param state         the padding mode.
1465  */
setParensUnPaddingMode(bool state)1466 void ASFormatter::setParensUnPaddingMode(bool state)
1467 {
1468 	shouldUnPadParens = state;
1469 }
1470 
1471 /**
1472  * set option to break/not break one-line blocks
1473  *
1474  * @param state        true = break, false = don't break.
1475  */
setBreakOneLineBlocksMode(bool state)1476 void ASFormatter::setBreakOneLineBlocksMode(bool state)
1477 {
1478 	shouldBreakOneLineBlocks = state;
1479 }
1480 
1481 /**
1482  * set option to break/not break lines consisting of multiple statements.
1483  *
1484  * @param state        true = break, false = don't break.
1485  */
setSingleStatementsMode(bool state)1486 void ASFormatter::setSingleStatementsMode(bool state)
1487 {
1488 	shouldBreakOneLineStatements = state;
1489 }
1490 
1491 /**
1492  * set option to convert tabs to spaces.
1493  *
1494  * @param state        true = convert, false = don't convert.
1495  */
setTabSpaceConversionMode(bool state)1496 void ASFormatter::setTabSpaceConversionMode(bool state)
1497 {
1498 	shouldConvertTabs = state;
1499 }
1500 
1501 /**
1502  * set option to indent comments in column 1.
1503  *
1504  * @param state        true = indent, false = don't indent.
1505  */
setIndentCol1CommentsMode(bool state)1506 void ASFormatter::setIndentCol1CommentsMode(bool state)
1507 {
1508 	shouldIndentCol1Comments = state;
1509 }
1510 
1511 /**
1512  * set option to force all line ends to a particular style.
1513  *
1514  * @param fmt           format enum value
1515  */
setLineEndFormat(LineEndFormat fmt)1516 void ASFormatter::setLineEndFormat(LineEndFormat fmt)
1517 {
1518 	lineEnd = fmt;
1519 }
1520 
1521 /**
1522  * set option to break unrelated blocks of code with empty lines.
1523  *
1524  * @param state        true = convert, false = don't convert.
1525  */
setBreakBlocksMode(bool state)1526 void ASFormatter::setBreakBlocksMode(bool state)
1527 {
1528 	shouldBreakBlocks = state;
1529 }
1530 
1531 /**
1532  * set option to break closing header blocks of code (such as 'else', 'catch', ...) with empty lines.
1533  *
1534  * @param state        true = convert, false = don't convert.
1535  */
setBreakClosingHeaderBlocksMode(bool state)1536 void ASFormatter::setBreakClosingHeaderBlocksMode(bool state)
1537 {
1538 	shouldBreakClosingHeaderBlocks = state;
1539 }
1540 
1541 /**
1542  * set option to delete empty lines.
1543  *
1544  * @param state        true = delete, false = don't delete.
1545  */
setDeleteEmptyLinesMode(bool state)1546 void ASFormatter::setDeleteEmptyLinesMode(bool state)
1547 {
1548 	shouldDeleteEmptyLines = state;
1549 }
1550 
1551 /**
1552  * set the pointer alignment.
1553  * options:
1554  *
1555  * @param alignment    the pointer alignment.
1556  */
setPointerAlignment(PointerAlign alignment)1557 void ASFormatter::setPointerAlignment(PointerAlign alignment)
1558 {
1559 	pointerAlignment = alignment;
1560 }
1561 
1562 /**
1563  * jump over several characters.
1564  *
1565  * @param i       the number of characters to jump over.
1566  */
goForward(int i)1567 void ASFormatter::goForward(int i)
1568 {
1569 	while (--i >= 0)
1570 		getNextChar();
1571 }
1572 
1573 /**
1574  * peek at the next unread character.
1575  *
1576  * @return     the next unread character.
1577  */
peekNextChar() const1578 char ASFormatter::peekNextChar() const
1579 {
1580 	char ch = ' ';
1581 	size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
1582 
1583 	if (peekNum == string::npos)
1584 		return ch;
1585 
1586 	ch = currentLine[peekNum];
1587 
1588 	return ch;
1589 }
1590 
1591 /**
1592  * check if current placement is before a comment
1593  *
1594  * @return     is before a comment.
1595  */
isBeforeComment() const1596 bool ASFormatter::isBeforeComment() const
1597 {
1598 	bool foundComment = false;
1599 	size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
1600 
1601 	if (peekNum == string::npos)
1602 		return foundComment;
1603 
1604 	foundComment = (currentLine.compare(peekNum, 2, "/*") == 0);
1605 
1606 	return foundComment;
1607 }
1608 
1609 /**
1610  * check if current placement is before a comment or line-comment
1611  *
1612  * @return     is before a comment or line-comment.
1613  */
isBeforeAnyComment() const1614 bool ASFormatter::isBeforeAnyComment() const
1615 {
1616 	bool foundComment = false;
1617 	size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
1618 
1619 	if (peekNum == string::npos)
1620 		return foundComment;
1621 
1622 	foundComment = (currentLine.compare(peekNum, 2, "/*") == 0
1623 	                || currentLine.compare(peekNum, 2, "//") == 0);
1624 
1625 	return foundComment;
1626 }
1627 
1628 /**
1629  * check if current placement is before a comment or line-comment
1630  * if a block comment it must be at the end of the line
1631  *
1632  * @return     is before a comment or line-comment.
1633  */
isBeforeAnyLineEndComment(int startPos) const1634 bool ASFormatter::isBeforeAnyLineEndComment(int startPos) const
1635 {
1636 	bool foundLineEndComment = false;
1637 	size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1);
1638 
1639 	if (peekNum != string::npos)
1640 	{
1641 		if (currentLine.compare(peekNum, 2, "//") == 0)
1642 			foundLineEndComment = true;
1643 		else if (currentLine.compare(peekNum, 2, "/*") == 0)
1644 		{
1645 			// comment must be closed on this line with nothing after it
1646 			size_t endNum = currentLine.find("*/", peekNum + 2);
1647 			if (endNum != string::npos)
1648 			{
1649 				size_t nextChar = currentLine.find_first_not_of(" \t", endNum + 2);
1650 				if (nextChar == string::npos)
1651 					foundLineEndComment = true;
1652 			}
1653 		}
1654 	}
1655 	return foundLineEndComment;
1656 }
1657 
1658 /**
1659  * check if current placement is before a comment followed by a line-comment
1660  *
1661  * @return     is before a multiple line-end comment.
1662  */
isBeforeMultipleLineEndComments(int startPos) const1663 bool ASFormatter::isBeforeMultipleLineEndComments(int startPos) const
1664 {
1665 	bool foundMultipleLineEndComment = false;
1666 	size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1);
1667 
1668 	if (peekNum != string::npos)
1669 	{
1670 		if (currentLine.compare(peekNum, 2, "/*") == 0)
1671 		{
1672 			// comment must be closed on this line with nothing after it
1673 			size_t endNum = currentLine.find("*/", peekNum + 2);
1674 			if (endNum != string::npos)
1675 			{
1676 				size_t nextChar = currentLine.find_first_not_of(" \t", endNum + 2);
1677 				if (nextChar != string::npos
1678 				        && currentLine.compare(nextChar, 2, "//") == 0)
1679 					foundMultipleLineEndComment = true;
1680 			}
1681 		}
1682 	}
1683 	return foundMultipleLineEndComment;
1684 }
1685 
1686 
1687 /**
1688  * get the next character, increasing the current placement in the process.
1689  * the new character is inserted into the variable currentChar.
1690  *
1691  * @return   whether succeded to recieve the new character.
1692  */
getNextChar()1693 bool ASFormatter::getNextChar()
1694 {
1695 	isInLineBreak = false;
1696 	previousChar = currentChar;
1697 
1698 	if (!isWhiteSpace(currentChar))
1699 	{
1700 		previousNonWSChar = currentChar;
1701 		if (!isInComment && !isInLineComment && !isInQuote
1702 		        && !isImmediatelyPostComment
1703 		        && !isImmediatelyPostLineComment
1704 		        && !isInPreprocessor
1705 		        && !isSequenceReached("/*")
1706 		        && !isSequenceReached("//"))
1707 			previousCommandChar = currentChar;
1708 	}
1709 
1710 	if (charNum + 1 < (int) currentLine.length()
1711 	        && (!isWhiteSpace(peekNextChar()) || isInComment || isInLineComment))
1712 	{
1713 		currentChar = currentLine[++charNum];
1714 
1715 		if (shouldConvertTabs && currentChar == '\t')
1716 			convertTabToSpaces();
1717 
1718 		return true;
1719 	}
1720 
1721 	// end of line has been reached
1722 	return getNextLine();
1723 }
1724 
1725 /**
1726  * get the next line of input, increasing the current placement in the process.
1727  *
1728  * @param sequence         the sequence to append.
1729  * @return   whether succeded in reading the next line.
1730  */
getNextLine(bool emptyLineWasDeleted)1731 bool ASFormatter::getNextLine(bool emptyLineWasDeleted /*false*/)
1732 {
1733 	if (sourceIterator->hasMoreLines())
1734 	{
1735 		if (appendOpeningBracket)
1736 			currentLine = "{";		// append bracket that was removed from the previous line
1737 		else
1738 			currentLine = sourceIterator->nextLine(emptyLineWasDeleted);
1739 		// reset variables for new line
1740 		inLineNumber++;
1741 		isInCase = false;
1742 		isInAsmOneLine = false;
1743 		isInQuoteContinuation = isInVerbatimQuote | haveLineContinuationChar;
1744 		haveLineContinuationChar= false;
1745 		isImmediatelyPostEmptyLine = lineIsEmpty;
1746 		previousChar = ' ';
1747 
1748 		if (currentLine.length() == 0)
1749 		{
1750 			currentLine = string(" ");        // a null is inserted if this is not done
1751 		}
1752 
1753 		// unless reading in the first line of the file, break a new line.
1754 		if (!isVirgin)
1755 			isInLineBreak = true;
1756 		else
1757 			isVirgin = false;
1758 
1759 		// check if is in preprocessor before line trimming
1760 		// a blank line after a \ will remove the flag
1761 		isImmediatelyPostPreprocessor = isInPreprocessor;
1762 		if (previousNonWSChar != '\\'
1763 		        || isEmptyLine(currentLine))
1764 			isInPreprocessor = false;
1765 
1766 		if (passedSemicolon)
1767 			isInExecSQL = false;
1768 		initNewLine();
1769 		currentChar = currentLine[charNum];
1770 		if (isInHorstmannRunIn && previousNonWSChar == '{')
1771 			isInLineBreak = false;
1772 		isInHorstmannRunIn = false;
1773 
1774 		if (shouldConvertTabs && currentChar == '\t')
1775 			convertTabToSpaces();
1776 
1777 		// check for an empty line inside a command bracket.
1778 		// if yes then read the next line (calls getNextLine recursively).
1779 		// must be after initNewLine.
1780 		if (shouldDeleteEmptyLines
1781 		        && lineIsEmpty
1782 		        && isBracketType((*bracketTypeStack)[bracketTypeStack->size()-1], COMMAND_TYPE))
1783 		{
1784 			// but do NOT delete an empty line between comments if blocks are being broken
1785 			if (!(shouldBreakBlocks || shouldBreakClosingHeaderBlocks)
1786 			        || !isImmediatelyPostCommentOnly
1787 			        || !commentAndHeaderFollows())
1788 			{
1789 				isInPreprocessor = isImmediatelyPostPreprocessor;		// restore
1790 				lineIsEmpty = false;
1791 				return getNextLine(true);
1792 			}
1793 		}
1794 
1795 		return true;
1796 	}
1797 	else
1798 	{
1799 		endOfCodeReached = true;
1800 		return false;
1801 	}
1802 }
1803 
1804 /**
1805  * jump over the leading white space in the current line,
1806  * IF the line does not begin a comment or is in a preprocessor definition.
1807  */
initNewLine()1808 void ASFormatter::initNewLine()
1809 {
1810 	size_t len = currentLine.length();
1811 	size_t indent = getIndentLength();
1812 	charNum = 0;
1813 
1814 	if (isInPreprocessor || isInQuoteContinuation)
1815 		return;
1816 
1817 	// SQL continuation lines must be adjusted so the leading spaces
1818 	// is equivalent to the opening EXEC SQL
1819 	if (isInExecSQL)
1820 	{
1821 		// replace leading tabs with spaces
1822 		// so that continuation indent will be spaces
1823 		size_t tabCount = 0;
1824 		size_t i;
1825 		for (i = 0; i < currentLine.length(); i++)
1826 		{
1827 			if (!isWhiteSpace(currentLine[i]))		// stop at first text
1828 				break;
1829 			if (currentLine[i] == '\t')
1830 			{
1831 				size_t numSpaces = indent - ((tabCount + i) % indent);
1832 				currentLine.replace(i, 1, numSpaces, ' ');
1833 				tabCount++;
1834 				i += indent - 1;
1835 			}
1836 		}
1837 		// correct the format if EXEC SQL is not a hanging indent
1838 		if (i < leadingSpaces)
1839 			currentLine.insert((size_t)0, leadingSpaces - i, ' ');
1840 		trimContinuationLine();
1841 		return;
1842 	}
1843 
1844 	// comment continuation lines must be adjusted so the leading spaces
1845 	// is equivalent to the opening comment
1846 	if (isInComment)
1847 	{
1848 		if (noTrimCommentContinuation)
1849 			leadingSpaces = tabIncrementIn = 0;
1850 		trimContinuationLine();
1851 		return;
1852 	}
1853 
1854 	// compute leading spaces
1855 	isImmediatelyPostCommentOnly = lineIsLineCommentOnly || lineEndsInCommentOnly;
1856 	lineIsLineCommentOnly = false;
1857 	lineEndsInCommentOnly = false;
1858 	doesLineStartComment = false;
1859 	currentLineBeginsWithBracket = false;
1860 	lineIsEmpty = false;
1861 	currentLineFirstBracketNum = string::npos;
1862 	tabIncrementIn = 0;
1863 
1864 	for (charNum = 0; isWhiteSpace(currentLine[charNum]) && charNum + 1 < (int) len; charNum++)
1865 	{
1866 		if (currentLine[charNum] == '\t')
1867 			tabIncrementIn += indent - 1 - ((tabIncrementIn + charNum) % indent);
1868 	}
1869 	leadingSpaces = charNum + tabIncrementIn;
1870 
1871 	if (isSequenceReached("/*"))
1872 	{
1873 		doesLineStartComment = true;
1874 	}
1875 	else if (isSequenceReached("//"))
1876 	{
1877 		lineIsLineCommentOnly = true;
1878 	}
1879 	else if (isSequenceReached("{"))
1880 	{
1881 		currentLineBeginsWithBracket = true;
1882 		currentLineFirstBracketNum = charNum;
1883 		size_t firstText = currentLine.find_first_not_of(" \t", charNum + 1);
1884 		if (firstText != string::npos)
1885 		{
1886 			if (currentLine.compare(firstText, 2, "//") == 0)
1887 				lineIsLineCommentOnly = true;
1888 			else if (currentLine.compare(firstText, 2, "/*") == 0
1889 			         || isExecSQL(currentLine, firstText))
1890 			{
1891 				// get the extra adjustment
1892 				size_t j;
1893 				for (j = charNum + 1; isWhiteSpace(currentLine[j]) && j < firstText; j++)
1894 				{
1895 					if (currentLine[j] == '\t')
1896 						tabIncrementIn += indent - 1 - ((tabIncrementIn + j) % indent);
1897 				}
1898 				leadingSpaces = j + tabIncrementIn;
1899 				if (currentLine.compare(firstText, 2, "/*") == 0)
1900 					doesLineStartComment = true;
1901 			}
1902 		}
1903 	}
1904 	else if (isWhiteSpace(currentLine[charNum]) && !(charNum + 1 < (int) currentLine.length()))
1905 	{
1906 		lineIsEmpty = true;
1907 	}
1908 }
1909 
1910 /**
1911  * append a string sequence to the current formatted line.
1912  * Unless disabled (via canBreakLine == false), first check if a
1913  * line-break has been registered, and if so break the
1914  * formatted line, and only then append the sequence into
1915  * the next formatted line.
1916  *
1917  * @param sequence         the sequence to append.
1918  * @param canBreakLine     if true, a registered line-break
1919  */
appendSequence(const string & sequence,bool canBreakLine)1920 void ASFormatter::appendSequence(const string &sequence, bool canBreakLine)
1921 {
1922 	if (canBreakLine && isInLineBreak)
1923 		breakLine();
1924 	formattedLine.append(sequence);
1925 }
1926 
1927 /**
1928  * append a space to the current formattedline, UNLESS the
1929  * last character is already a white-space character.
1930  */
appendSpacePad()1931 void ASFormatter::appendSpacePad()
1932 {
1933 	int len = formattedLine.length();
1934 	if (len > 0 && !isWhiteSpace(formattedLine[len-1]))
1935 	{
1936 		formattedLine.append(1, ' ');
1937 		spacePadNum++;
1938 	}
1939 }
1940 
1941 /**
1942  * append a space to the current formattedline, UNLESS the
1943  * next character is already a white-space character.
1944  */
appendSpaceAfter()1945 void ASFormatter::appendSpaceAfter()
1946 {
1947 	int len = currentLine.length();
1948 	if (charNum + 1 < len && !isWhiteSpace(currentLine[charNum+1]))
1949 	{
1950 		formattedLine.append(1, ' ');
1951 		spacePadNum++;
1952 	}
1953 }
1954 
1955 /**
1956  * register a line break for the formatted line.
1957  */
breakLine()1958 void ASFormatter::breakLine()
1959 {
1960 	isLineReady = true;
1961 	isInLineBreak = false;
1962 	spacePadNum = nextLineSpacePadNum;
1963 	nextLineSpacePadNum = 0;
1964 	formattedLineCommentNum = string::npos;
1965 
1966 	// queue an empty line prepend request if one exists
1967 	prependEmptyLine = isPrependPostBlockEmptyLineRequested;
1968 
1969 	readyFormattedLine =  formattedLine;
1970 	if (isAppendPostBlockEmptyLineRequested)
1971 	{
1972 		isAppendPostBlockEmptyLineRequested = false;
1973 		isPrependPostBlockEmptyLineRequested = true;
1974 	}
1975 	else
1976 	{
1977 		isPrependPostBlockEmptyLineRequested = false;
1978 	}
1979 
1980 	formattedLine = "";
1981 }
1982 
1983 /**
1984  * check if the currently reached open-bracket (i.e. '{')
1985  * opens a:
1986  * - a definition type block (such as a class or namespace),
1987  * - a command block (such as a method block)
1988  * - a static array
1989  * this method takes for granted that the current character
1990  * is an opening bracket.
1991  *
1992  * @return    the type of the opened block.
1993  */
getBracketType()1994 BracketType ASFormatter::getBracketType()
1995 {
1996 	assert(currentChar == '{');
1997 
1998 	BracketType returnVal;
1999 
2000 	if ((previousNonWSChar == '='
2001 	        || isBracketType(bracketTypeStack->back(),  ARRAY_TYPE))
2002 	        && previousCommandChar != ')')
2003 		returnVal = ARRAY_TYPE;
2004 	else if (foundPreDefinitionHeader)
2005 	{
2006 		returnVal = DEFINITION_TYPE;
2007 		if (foundNamespaceHeader)
2008 			returnVal = (BracketType)(returnVal | NAMESPACE_TYPE);
2009 		else if (foundClassHeader)
2010 			returnVal = (BracketType)(returnVal | CLASS_TYPE);
2011 		else if (foundStructHeader)
2012 			returnVal = (BracketType)(returnVal | STRUCT_TYPE);
2013 		else if (foundInterfaceHeader)
2014 			returnVal = (BracketType)(returnVal | INTERFACE_TYPE);
2015 	}
2016 	else
2017 	{
2018 		bool isCommandType = (foundPreCommandHeader
2019 		                      || (currentHeader != NULL && isNonParenHeader)
2020 		                      || (previousCommandChar == ')')
2021 		                      || (previousCommandChar == ':' && !foundQuestionMark)
2022 		                      || (previousCommandChar == ';')
2023 		                      || ((previousCommandChar == '{' ||  previousCommandChar == '}')
2024 		                          && isPreviousBracketBlockRelated)
2025 		                      || isJavaStaticConstructor
2026 		                      || isSharpDelegate);
2027 
2028 		// C# methods containing 'get', 'set', 'add', and 'remove' do NOT end with parens
2029 		if (!isCommandType && isSharpStyle() && isNextWordSharpNonParenHeader(charNum + 1))
2030 		{
2031 			isCommandType = true;
2032 			isSharpAccessor = true;
2033 		}
2034 
2035 		if (!isCommandType && isInExtern)
2036 			returnVal = EXTERN_TYPE;
2037 		else
2038 			returnVal = (isCommandType ? COMMAND_TYPE : ARRAY_TYPE);
2039 	}
2040 
2041 	if (isOneLineBlockReached(currentLine, charNum))
2042 		returnVal = (BracketType)(returnVal | SINGLE_LINE_TYPE);
2043 
2044 	if (isBracketType(returnVal, ARRAY_TYPE) && isNonInStatementArrayBracket())
2045 	{
2046 		returnVal = (BracketType)(returnVal | ARRAY_NIS_TYPE);
2047 		isNonInStatementArray = true;
2048 		nonInStatementBracket = formattedLine.length() - 1;
2049 	}
2050 
2051 	return returnVal;
2052 }
2053 
2054 /**
2055  * check if a line is empty
2056  *
2057  * @return        whether line is empty
2058  */
isEmptyLine(const string & line) const2059 bool ASFormatter::isEmptyLine(const string &line) const
2060 {
2061 	return line.find_first_not_of(" \t") == string::npos;
2062 }
2063 
2064 /**
2065  * Check if the currently reached  '*' or '&' character is
2066  * a pointer-or-reference symbol, or another operator.
2067  * A pointer dereference (*) or an "address of" character (&)
2068  * counts as a pointer or reference because it is not an
2069  * arithmetic operator.
2070  *
2071  * @return        whether current character is a reference-or-pointer
2072  */
isPointerOrReference() const2073 bool ASFormatter::isPointerOrReference() const
2074 {
2075 	assert(currentChar == '*' || currentChar == '&');
2076 
2077 	if (!isCStyle())
2078 		return false;
2079 
2080 	if (currentChar == '&' && previousChar == '&')
2081 		return false;
2082 
2083 	if (previousNonWSChar == '=' || isCharImmediatelyPostReturn)
2084 		return true;
2085 
2086 	if (currentHeader == &AS_CATCH)
2087 		return true;
2088 
2089 	// get the last legal word (may be a number)
2090 	string lastWord = getPreviousWord(currentLine, charNum);
2091 	if (lastWord.empty())
2092 		lastWord[0] = ' ';
2093 	char nextChar = peekNextChar();
2094 
2095 	// check for preceding or following numeric values
2096 	if (isdigit(lastWord[0])
2097 	        || isdigit(nextChar))
2098 		return false;
2099 
2100 	// checks on other chars
2101 	if (isLegalNameChar(lastWord[0])
2102 	        && isLegalNameChar(nextChar)
2103 	        && parenStack->back() > 0)
2104 	{
2105 		// if followed by an assignment it is a pointer or reference
2106 		size_t nextNum = currentLine.find_first_of("=;)", charNum + 1);
2107 		if (nextNum != string::npos && currentLine[nextNum] == '=')
2108 			return true;
2109 
2110 		// if a function definition it is a pointer or reference
2111 		// otherwise it is an arithmetic operator
2112 		if (!isBracketType(bracketTypeStack->back(), COMMAND_TYPE))
2113 			return true;
2114 		else
2115 			return false;
2116 	}
2117 
2118 	if (nextChar == '-'
2119 	        || nextChar == '+')
2120 	{
2121 		size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);
2122 		if (nextNum != string::npos)
2123 		{
2124 			if (currentLine.compare(nextNum, 2, "++") != 0
2125 			        && currentLine.compare(nextNum, 2, "--") != 0)
2126 				return false;
2127 		}
2128 	}
2129 
2130 	bool isPR = (!isInPotentialCalculation
2131 	             || isBracketType(bracketTypeStack->back(), DEFINITION_TYPE)
2132 	             || (!isLegalNameChar(previousNonWSChar)
2133 	                 && !(previousNonWSChar == ')' && nextChar == '(')
2134 	                 && !(previousNonWSChar == ')' && currentChar == '*')
2135 	                 && previousNonWSChar != ']')
2136 	            );
2137 
2138 	if (!isPR)
2139 	{
2140 		isPR |= (!isWhiteSpace(nextChar)
2141 		         && nextChar != '-'
2142 		         && nextChar != '('
2143 		         && nextChar != '['
2144 		         && !isLegalNameChar(nextChar));
2145 	}
2146 
2147 	return isPR;
2148 }
2149 
2150 /**
2151  * Check if the currently reached  '*' or '&' character is
2152  * a dereferenced pointer or "address of" symbol.
2153  * NOTE: this MUST be a pointer or reference as determined by
2154  * the function isPointerOrReference().
2155  *
2156  * @return        whether current character is a dereference or address of
2157  */
isDereferenceOrAddressOf() const2158 bool ASFormatter::isDereferenceOrAddressOf() const
2159 {
2160 	assert(isPointerOrReference());
2161 
2162 	if (previousNonWSChar == '='
2163 	        || previousNonWSChar == ','
2164 	        || previousNonWSChar == '.'
2165 	        || previousNonWSChar == '>'
2166 	        || previousNonWSChar == '<'
2167 	        || isCharImmediatelyPostReturn)
2168 		return true;
2169 
2170 	// check for **
2171 	if (currentChar == '*'
2172 	        && (int) currentLine.length() > charNum
2173 	        && currentLine[charNum+1] == '*')
2174 	{
2175 		if (previousNonWSChar == '(')
2176 			return true;
2177 		if ((int) currentLine.length() < charNum + 2)
2178 			return true;
2179 		return false;
2180 	}
2181 
2182 	// check first char on the line
2183 	if (charNum == (int) currentLine.find_first_not_of(" \t"))
2184 		return true;
2185 
2186 	size_t nextChar = currentLine.find_first_not_of(" \t", charNum+1);
2187 	if (nextChar != string::npos
2188 	        && (currentLine[nextChar] == ')'
2189 	            || currentLine[nextChar] == '>'
2190 	            || currentLine[nextChar] == ','))
2191 		return false;
2192 
2193 	string lastWord = getPreviousWord(currentLine, charNum);
2194 	if (lastWord == "else" || lastWord == "delete")
2195 		return true;
2196 
2197 	bool isDA = (!(isLegalNameChar(previousNonWSChar) || previousNonWSChar == '>')
2198 	             || !isLegalNameChar(peekNextChar())
2199 	             || (ispunct(previousNonWSChar) && previousNonWSChar != '.')
2200 	             || isCharImmediatelyPostReturn);
2201 
2202 	return isDA;
2203 }
2204 
2205 /**
2206  * Check if the currently reached  '*' or '&' character is
2207  * centered with one space on each side.
2208  * Only spaces are checked, not tabs.
2209  * If true then a space wil be deleted on the output.
2210  *
2211  * @return        whether current character is centered.
2212  */
isPointerOrReferenceCentered() const2213 bool ASFormatter::isPointerOrReferenceCentered() const
2214 {
2215 	assert(currentLine[charNum] == '*' || currentLine[charNum] == '&');
2216 
2217 	int prNum = charNum;
2218 	int lineLength = (int) currentLine.length();
2219 	// check space before
2220 	if (prNum < 1
2221 	        || currentLine[prNum-1] != ' ')
2222 		return false;
2223 
2224 	// check no space before that
2225 	if (prNum < 2
2226 	        || currentLine[prNum-2] == ' ')
2227 		return false;
2228 
2229 	// check for **
2230 	if (prNum + 1 < lineLength
2231 	        && currentLine[prNum+1] == '*')
2232 		prNum++;
2233 
2234 	// check space after
2235 	if (prNum + 1 < lineLength
2236 	        && currentLine[prNum+1] != ' ')
2237 		return false;
2238 
2239 	// check no space after that
2240 	if (prNum + 2 < lineLength
2241 	        && currentLine[prNum+2] == ' ')
2242 		return false;
2243 
2244 	return true;
2245 }
2246 
2247 /**
2248  * check if the currently reached '+' or '-' character is a unary operator
2249  * this method takes for granted that the current character
2250  * is a '+' or '-'.
2251  *
2252  * @return        whether the current '+' or '-' is a unary operator.
2253  */
isUnaryOperator() const2254 bool ASFormatter::isUnaryOperator() const
2255 {
2256 	assert(currentChar == '+' || currentChar == '-');
2257 
2258 	return ((isCharImmediatelyPostReturn || !isLegalNameChar(previousCommandChar))
2259 	        && previousCommandChar != '.'
2260 	        && previousCommandChar != '\"'
2261 	        && previousCommandChar != '\''
2262 	        && previousCommandChar != ')'
2263 	        && previousCommandChar != ']');
2264 }
2265 
2266 
2267 /**
2268  * check if the currently reached '+' or '-' character is
2269  * part of an exponent, i.e. 0.2E-5.
2270  *
2271  * this method takes for granted that the current character
2272  * is a '+' or '-'.
2273  *
2274  * @return        whether the current '+' or '-' is in an exponent.
2275  */
isInExponent() const2276 bool ASFormatter::isInExponent() const
2277 {
2278 	assert(currentChar == '+' || currentChar == '-');
2279 
2280 	int formattedLineLength = formattedLine.length();
2281 	if (formattedLineLength >= 2)
2282 	{
2283 		char prevPrevFormattedChar = formattedLine[formattedLineLength - 2];
2284 		char prevFormattedChar = formattedLine[formattedLineLength - 1];
2285 
2286 		return ((prevFormattedChar == 'e' || prevFormattedChar == 'E')
2287 		        && (prevPrevFormattedChar == '.' || isdigit(prevPrevFormattedChar)));
2288 	}
2289 	else
2290 		return false;
2291 }
2292 
2293 /**
2294  * check if an array bracket should NOT have an in-statement indent
2295  *
2296  * @return        the array is non in-statement
2297  */
isNonInStatementArrayBracket() const2298 bool ASFormatter::isNonInStatementArrayBracket() const
2299 {
2300 	bool returnVal = false;
2301 	char nextChar = peekNextChar();
2302 	// if this opening bracket begins the line there will be no inStatement indent
2303 	if (currentLineBeginsWithBracket
2304 	        && charNum == (int) currentLineFirstBracketNum
2305 	        && nextChar != '}')
2306 		returnVal = true;
2307 	// if an opening bracket ends the line there will be no inStatement indent
2308 	if (isWhiteSpace(nextChar)
2309 	        || isBeforeAnyLineEndComment(charNum)
2310 	        || nextChar == '{')
2311 		returnVal = true;
2312 
2313 	// Java "new Type [] {...}" IS an inStatement indent
2314 	if (isJavaStyle() && previousNonWSChar == ']')
2315 		returnVal = false;
2316 
2317 	// trace
2318 	//if (isNonInStatementArray)
2319 	//	cout << traceLineNumber << " " << 'x' << endl;
2320 	//else
2321 	//	cout << traceLineNumber << " " << ' ' << endl
2322 
2323 	return returnVal;
2324 }
2325 
2326 /**
2327  * check if a one-line bracket has been reached,
2328  * i.e. if the currently reached '{' character is closed
2329  * with a complimentry '}' elsewhere on the current line,
2330  *.
2331  * @return        has a one-line bracket been reached?
2332  */
isOneLineBlockReached(string & line,int startChar) const2333 bool ASFormatter::isOneLineBlockReached(string& line, int startChar) const
2334 {
2335 	assert(line[startChar] == '{');
2336 
2337 	bool isInComment = false;
2338 	bool isInQuote = false;
2339 	int bracketCount = 1;
2340 	int lineLength = line.length();
2341 	char quoteChar = ' ';
2342 
2343 	for (int i = startChar + 1; i < lineLength; ++i)
2344 	{
2345 		char ch = line[i];
2346 
2347 		if (isInComment)
2348 		{
2349 			if (line.compare(i, 2, "*/") == 0)
2350 			{
2351 				isInComment = false;
2352 				++i;
2353 			}
2354 			continue;
2355 		}
2356 
2357 		if (ch == '\\')
2358 		{
2359 			++i;
2360 			continue;
2361 		}
2362 
2363 		if (isInQuote)
2364 		{
2365 			if (ch == quoteChar)
2366 				isInQuote = false;
2367 			continue;
2368 		}
2369 
2370 		if (ch == '"' || ch == '\'')
2371 		{
2372 			isInQuote = true;
2373 			quoteChar = ch;
2374 			continue;
2375 		}
2376 
2377 		if (line.compare(i, 2, "//") == 0)
2378 			break;
2379 
2380 		if (line.compare(i, 2, "/*") == 0)
2381 		{
2382 			isInComment = true;
2383 			++i;
2384 			continue;
2385 		}
2386 
2387 		if (ch == '{')
2388 			++bracketCount;
2389 		else if (ch == '}')
2390 			--bracketCount;
2391 
2392 		if (bracketCount == 0)
2393 			return true;
2394 	}
2395 
2396 	return false;
2397 }
2398 
2399 /**
2400  * peek at the next word to determine if it is a C# non-paren header.
2401  * will look ahead in the input file if necessary.
2402  *
2403  * @param       char position on currentLine to start the search
2404  * @return      true if the next word is get or set.
2405  */
isNextWordSharpNonParenHeader(int startChar) const2406 bool ASFormatter::isNextWordSharpNonParenHeader(int startChar) const
2407 {
2408 	// look ahead to find the next non-comment text
2409 	string nextText = peekNextText(currentLine.substr(startChar));
2410 	if (nextText.length() == 0)
2411 		return false;
2412 	if (nextText[0] == '[')
2413 		return true;
2414 	if (!isCharPotentialHeader(nextText, 0))
2415 		return false;
2416 	if (findKeyword(nextText, 0, AS_GET) || findKeyword(nextText, 0, AS_SET)
2417 	        || findKeyword(nextText, 0, AS_ADD) || findKeyword(nextText, 0, AS_REMOVE))
2418 		return true;
2419 	return false;
2420 }
2421 
2422 /**
2423  * peek at the next char to determine if it is an opening bracket.
2424  * will look ahead in the input file if necessary.
2425  * this determines a java static constructor.
2426  *
2427  * @param       char position on currentLine to start the search
2428  * @return      true if the next word is an opening bracket.
2429  */
isNextCharOpeningBracket(int startChar) const2430 bool ASFormatter::isNextCharOpeningBracket(int startChar) const
2431 {
2432 	bool retVal = false;
2433 	string nextText = peekNextText(currentLine.substr(startChar));
2434 	if (nextText.compare(0, 1, "{") == 0)
2435 		retVal = true;
2436 	return retVal;
2437 }
2438 
2439 /**
2440  * get the next non-whitespace substring on following lines, bypassing all comments.
2441  *
2442  * @param   the first line to check
2443  * @return  the next non-whitespace substring.
2444  */
peekNextText(const string & firstLine,bool endOnEmptyLine) const2445 string ASFormatter::peekNextText(const string& firstLine, bool endOnEmptyLine /*false*/) const
2446 {
2447 	bool isFirstLine = true;
2448 	bool needReset = false;
2449 	string nextLine = firstLine;
2450 	size_t firstChar= string::npos;
2451 
2452 	// find the first non-blank text, bypassing all comments.
2453 	bool isInComment = false;
2454 	while (sourceIterator->hasMoreLines())
2455 	{
2456 		if (isFirstLine)
2457 			isFirstLine = false;
2458 		else
2459 		{
2460 			nextLine = sourceIterator->peekNextLine();
2461 			needReset = true;
2462 		}
2463 
2464 		firstChar = nextLine.find_first_not_of(" \t");
2465 		if (firstChar == string::npos)
2466 		{
2467 			if (endOnEmptyLine && !isInComment)
2468 				break;
2469 			continue;
2470 		}
2471 
2472 		if (nextLine.compare(firstChar, 2, "/*") == 0)
2473 			isInComment = true;
2474 
2475 		if (isInComment)
2476 		{
2477 			firstChar = nextLine.find("*/", firstChar);
2478 			if (firstChar == string::npos)
2479 				continue;
2480 			firstChar += 2;
2481 			isInComment = false;
2482 			firstChar = nextLine.find_first_not_of(" \t", firstChar);
2483 			if (firstChar == string::npos)
2484 				continue;
2485 		}
2486 
2487 		if (nextLine.compare(firstChar, 2, "//") == 0)
2488 			continue;
2489 
2490 		// found the next text
2491 		break;
2492 	}
2493 
2494 	if (needReset)
2495 		sourceIterator->peekReset();
2496 	if (firstChar == string::npos)
2497 		nextLine = "";
2498 	else
2499 		nextLine = nextLine.substr(firstChar);
2500 	return nextLine;
2501 }
2502 
2503 /**
2504  * adjust comment position because of adding or deleting spaces
2505  * the spaces are added or deleted to formattedLine
2506  * spacePadNum contains the adjustment
2507  */
adjustComments(void)2508 void ASFormatter::adjustComments(void)
2509 {
2510 	assert(spacePadNum != 0);
2511 	assert(currentLine.compare(charNum, 2, "//") == 0
2512 	       || currentLine.compare(charNum, 2, "/*") == 0);
2513 
2514 
2515 	// block comment must be closed on this line with nothing after it
2516 	if (currentLine.compare(charNum, 2, "/*") == 0)
2517 	{
2518 		size_t endNum = currentLine.find("*/", charNum + 2);
2519 		if (endNum == string::npos)
2520 			return;
2521 		if (currentLine.find_first_not_of(" \t", endNum + 2) != string::npos)
2522 			return;
2523 	}
2524 
2525 	size_t len = formattedLine.length();
2526 	// don't adjust a tab
2527 	if (formattedLine[len-1] == '\t')
2528 		return;
2529 	// if spaces were removed, need to add spaces before the comment
2530 	if (spacePadNum < 0)
2531 	{
2532 		int adjust = -spacePadNum;          // make the number positive
2533 		formattedLine.append(adjust, ' ');
2534 	}
2535 	// if spaces were added, need to delete extra spaces before the comment
2536 	// if cannot be done put the comment one space after the last text
2537 	else if (spacePadNum > 0)
2538 	{
2539 		int adjust = spacePadNum;
2540 		size_t lastText = formattedLine.find_last_not_of(' ');
2541 		if (lastText != string::npos
2542 		        && lastText < len - adjust - 1)
2543 			formattedLine.resize(len - adjust);
2544 		else if (len > lastText + 2)
2545 			formattedLine.resize(lastText + 2);
2546 		else if (len < lastText + 2)
2547 			formattedLine.append(len - lastText, ' ');
2548 	}
2549 }
2550 
2551 /**
2552  * append the current bracket inside the end of line comments
2553  * currentChar contains the bracket, it will be appended to formattedLine
2554  * formattedLineCommentNum is the comment location on formattedLine
2555  * returns true f appended, false if not
2556  */
appendCharInsideComments(void)2557 void ASFormatter::appendCharInsideComments(void)
2558 {
2559 	if (formattedLineCommentNum == string::npos)    // does the comment start on the previous line?
2560 	{
2561 		appendCurrentChar();                        // don't attach
2562 		return; // false;
2563 	}
2564 	assert(formattedLine.compare(formattedLineCommentNum, 2, "//") == 0
2565 	       || formattedLine.compare(formattedLineCommentNum, 2, "/*") == 0);
2566 
2567 	// find the previous non space char
2568 	size_t end = formattedLineCommentNum;
2569 	size_t beg = formattedLine.find_last_not_of(" \t", end-1);
2570 	if (beg == string::npos)                // is the previous line comment only?
2571 	{
2572 		appendCurrentChar();                // don't attach
2573 		return; // false;
2574 	}
2575 	beg++;
2576 
2577 	// insert the bracket
2578 	if (end - beg < 3)                      // is there room to insert?
2579 		formattedLine.insert(beg, 3-end+beg, ' ');
2580 	if (formattedLine[beg] == '\t')         // don't pad with a tab
2581 		formattedLine.insert(beg, 1, ' ');
2582 	formattedLine[beg+1] = currentChar;
2583 
2584 	if (isBeforeComment())
2585 		breakLine();
2586 	else if (isCharImmediatelyPostLineComment)
2587 		shouldBreakLineAtNextChar = true;
2588 	return; // true;
2589 }
2590 
2591 /**
2592  * add or remove space padding to operators
2593  * currentChar contains the paren
2594  * the operators and necessary padding will be appended to formattedLine
2595  * the calling function should have a continue statement after calling this method
2596  *
2597  * @param *newOperator     the operator to be padded
2598  */
padOperators(const string * newOperator)2599 void ASFormatter::padOperators(const string *newOperator)
2600 {
2601 	assert(newOperator != NULL);
2602 
2603 	bool shouldPad = (newOperator != &AS_COLON_COLON
2604 	                  && newOperator != &AS_PAREN_PAREN
2605 	                  && newOperator != &AS_BLPAREN_BLPAREN
2606 	                  && newOperator != &AS_PLUS_PLUS
2607 	                  && newOperator != &AS_MINUS_MINUS
2608 	                  && newOperator != &AS_NOT
2609 	                  && newOperator != &AS_BIT_NOT
2610 	                  && newOperator != &AS_ARROW
2611 	                  && !(newOperator == &AS_MINUS && isInExponent())
2612 	                  && !((newOperator == &AS_PLUS || newOperator == &AS_MINUS)  // check for unary plus or minus
2613 	                       && (previousNonWSChar == '('
2614 	                           || previousNonWSChar == '='
2615 	                           || previousNonWSChar == ','))
2616 	                  && !(newOperator == &AS_PLUS && isInExponent())
2617 	                  && !isCharImmediatelyPostOperator
2618 	                  && !((newOperator == &AS_MULT || newOperator == &AS_BIT_AND)
2619 	                       && isPointerOrReference())
2620 	                  && !(newOperator == &AS_MULT
2621 	                       && (previousNonWSChar == '.'
2622 	                           || previousNonWSChar == '>'))    // check for ->
2623 	                  && !((isInTemplate || isCharImmediatelyPostTemplate)
2624 	                       && (newOperator == &AS_LS || newOperator == &AS_GR))
2625 	                  && !(newOperator == &AS_GCC_MIN_ASSIGN
2626 	                       && ASBase::peekNextChar(currentLine, charNum+1) == '>')
2627 	                  && !(newOperator == &AS_GR && previousNonWSChar == '?')
2628 	                  && !isInCase
2629 	                  && !isInAsm
2630 	                  && !isInAsmOneLine
2631 	                  && !isInAsmBlock
2632 	                 );
2633 
2634 	// pad before operator
2635 	if (shouldPad
2636 	        && !isInBlParen
2637 	        && !(newOperator == &AS_COLON && !foundQuestionMark)
2638 	        && !(newOperator == &AS_QUESTION && isSharpStyle() // check for C# nullable type (e.g. int?)
2639 	             && currentLine.find(':', charNum+1) == string::npos)
2640 	   )
2641 		appendSpacePad();
2642 	appendSequence(*newOperator);
2643 	goForward(newOperator->length() - 1);
2644 
2645 	// since this block handles '()' and '[]',
2646 	// the parenStack must be updated here accordingly!
2647 	if (newOperator == &AS_PAREN_PAREN
2648 	        || newOperator == &AS_BLPAREN_BLPAREN)
2649 		parenStack->back()--;
2650 
2651 	currentChar = (*newOperator)[newOperator->length() - 1];
2652 	// pad after operator
2653 	// but do not pad after a '-' that is a unary-minus.
2654 	if (shouldPad
2655 	        && !isInBlParen
2656 	        && !isBeforeAnyComment()
2657 	        && !(newOperator == &AS_PLUS && isUnaryOperator())
2658 	        && !(newOperator == &AS_MINUS && isUnaryOperator())
2659 	        && !(currentLine.compare(charNum + 1, 1,  ";") == 0)
2660 	        && !(currentLine.compare(charNum + 1, 2, "::") == 0)
2661 	        && !(newOperator == &AS_QUESTION && isSharpStyle() // check for C# nullable type (e.g. int?)
2662 	             && currentLine[charNum+1] == '[')
2663 	   )
2664 		appendSpaceAfter();
2665 
2666 	previousOperator = newOperator;
2667 	return;
2668 }
2669 
2670 /**
2671  * format pointer or reference
2672  * currentChar contains the pointer or reference
2673  * the symbol and necessary padding will be appended to formattedLine
2674  * the calling function should have a continue statement after calling this method
2675  */
formatPointerOrReference(void)2676 void ASFormatter::formatPointerOrReference(void)
2677 {
2678 	assert(currentChar == '*' || currentChar == '&');
2679 	assert(isCStyle());
2680 
2681 	// check for cast
2682 	char peekedChar = peekNextChar();
2683 	if (currentChar == '*'
2684 	        && (int) currentLine.length() > charNum
2685 	        && currentLine[charNum+1] == '*')
2686 	{
2687 		size_t nextChar = currentLine.find_first_not_of(" \t", charNum+2);
2688 		if (nextChar == string::npos)
2689 			peekedChar = ' ';
2690 		else
2691 			peekedChar = currentLine[nextChar];
2692 	}
2693 	if (peekedChar == ')' || peekedChar =='>' || peekedChar ==',')
2694 	{
2695 		formatPointerOrReferenceCast();
2696 		return;
2697 	}
2698 
2699 	// do this before bumping charNum
2700 	bool isOldPRCentered = isPointerOrReferenceCentered();
2701 
2702 	if (pointerAlignment == ALIGN_TYPE)
2703 	{
2704 		size_t prevCh = formattedLine.find_last_not_of(" \t");
2705 		if (prevCh == string::npos)
2706 			prevCh = 0;
2707 		if (formattedLine.length() == 0 || prevCh == formattedLine.length() - 1)
2708 			appendCurrentChar();
2709 		else
2710 		{
2711 			// exchange * or & with character following the type
2712 			// this may not work every time with a tab character
2713 			string charSave = formattedLine.substr(prevCh+1, 1);
2714 			formattedLine[prevCh+1] = currentChar;
2715 			formattedLine.append(charSave);
2716 		}
2717 		if (isSequenceReached("**"))
2718 		{
2719 			formattedLine.insert(prevCh+2, "*");
2720 			goForward(1);
2721 		}
2722 		// if no space after * then add one
2723 		if (charNum < (int) currentLine.length() - 1
2724 		        && !isWhiteSpace(currentLine[charNum+1])
2725 		        && currentLine[charNum+1] != ')')
2726 			appendSpacePad();
2727 		// if old pointer or reference is centered, remove a space
2728 		if (isOldPRCentered
2729 		        && isWhiteSpace(formattedLine[formattedLine.length()-1]))
2730 		{
2731 			formattedLine.erase(formattedLine.length()-1, 1);
2732 			spacePadNum--;
2733 		}
2734 	}
2735 	else if (pointerAlignment == ALIGN_MIDDLE)
2736 	{
2737 		// compute current whitespace before
2738 		size_t wsBefore = currentLine.find_last_not_of(" \t", charNum - 1);
2739 		if (wsBefore == string::npos)
2740 			wsBefore = 0;
2741 		else
2742 			wsBefore = charNum - wsBefore - 1;
2743 		// adjust for **
2744 		string sequenceToInsert = currentChar == '*' ? "*" : "&";
2745 		if (isSequenceReached("**"))
2746 		{
2747 			sequenceToInsert = "**";
2748 			goForward(1);
2749 		}
2750 		size_t charNumSave = charNum;
2751 		// goForward() to convert tabs to spaces, if necessary,
2752 		// and move following characters to preceding characters
2753 		// this may not work every time with tab characters
2754 		for (size_t i = charNum+1; i < currentLine.length() && isWhiteSpace(currentLine[i]); i++)
2755 		{
2756 			goForward(1);
2757 			formattedLine.append(1, currentLine[i]);
2758 		}
2759 		// whitespace should be at least 2 chars
2760 		size_t wsAfter = currentLine.find_first_not_of(" \t", charNumSave + 1);
2761 		if (wsAfter == string::npos)
2762 			wsAfter = 0;
2763 		else
2764 			wsAfter = wsAfter - charNumSave - 1;
2765 		if (wsBefore + wsAfter < 2)
2766 		{
2767 			size_t charsToAppend = (2 - (wsBefore + wsAfter));
2768 			formattedLine.append(charsToAppend, ' ');
2769 			spacePadNum += charsToAppend;
2770 			if (wsBefore == 0) wsBefore++;
2771 			if (wsAfter == 0) wsAfter++;
2772 		}
2773 		// insert the pointer or reference char
2774 		size_t padAfter = (wsBefore + wsAfter) / 2;
2775 		formattedLine.insert(formattedLine.length() - padAfter, sequenceToInsert);
2776 	}
2777 	else if (pointerAlignment == ALIGN_NAME)
2778 	{
2779 		size_t startNum = formattedLine.find_last_not_of(" \t");
2780 		string sequenceToInsert = currentChar == '*' ? "*" : "&";
2781 		if (isSequenceReached("**"))
2782 		{
2783 			sequenceToInsert = "**";
2784 			goForward(1);
2785 		}
2786 		// goForward() to convert tabs to spaces, if necessary,
2787 		// and move following characters to preceding characters
2788 		// this may not work every time with tab characters
2789 		for (size_t i = charNum+1; i < currentLine.length() && isWhiteSpace(currentLine[i]); i++)
2790 		{
2791 			goForward(1);
2792 			formattedLine.append(1, currentLine[i]);
2793 		}
2794 		appendSequence(sequenceToInsert, false);
2795 		// if no space before * then add one
2796 		if (startNum != string::npos
2797 		        && !isWhiteSpace(formattedLine[startNum+1]))
2798 		{
2799 			formattedLine.insert(startNum+1 , 1, ' ');
2800 			spacePadNum++;
2801 		}
2802 		// if old pointer or reference is centered, remove a space
2803 		if (isOldPRCentered
2804 		        && formattedLine.length() > startNum+1
2805 		        && isWhiteSpace(formattedLine[startNum+1]))
2806 		{
2807 			formattedLine.erase(startNum+1, 1);
2808 			spacePadNum--;
2809 		}
2810 	}
2811 	else	// pointerAlignment == ALIGN_NONE
2812 	{
2813 		appendCurrentChar();
2814 	}
2815 	return;
2816 }
2817 
2818 /**
2819  * format pointer or reference cast
2820  * currentChar contains the pointer or reference
2821  * NOTE: the pointers and references in function definitions
2822  *       are processed as a cast (e.g. void foo(void*, void*))
2823  *       is processed here.
2824  */
formatPointerOrReferenceCast(void)2825 void ASFormatter::formatPointerOrReferenceCast(void)
2826 {
2827 	assert(currentChar == '*' || currentChar == '&');
2828 	assert(isCStyle());
2829 
2830 	string sequenceToInsert = currentChar == '*' ? "*" : "&";
2831 	if (isSequenceReached("**"))
2832 	{
2833 		sequenceToInsert = "**";
2834 		goForward(1);
2835 	}
2836 	if (pointerAlignment == ALIGN_NONE)
2837 	{
2838 		appendSequence(sequenceToInsert, false);
2839 		return;
2840 	}
2841 	// remove trailing whitespace
2842 	size_t prevCh = formattedLine.find_last_not_of(" \t");
2843 	if (prevCh == string::npos)
2844 		prevCh = 0;
2845 	if (formattedLine.length() > 0 && isWhiteSpace(formattedLine[prevCh+1]))
2846 	{
2847 		spacePadNum -= (formattedLine.length() - 1 - prevCh);
2848 		formattedLine.erase(prevCh+1);
2849 	}
2850 	if (pointerAlignment == ALIGN_TYPE)
2851 	{
2852 		appendSequence(sequenceToInsert, false);
2853 	}
2854 	else if (pointerAlignment == ALIGN_MIDDLE
2855 	         || pointerAlignment == ALIGN_NAME)
2856 	{
2857 		appendSpacePad();
2858 		appendSequence(sequenceToInsert, false);
2859 	}
2860 	else
2861 		appendSequence(sequenceToInsert, false);
2862 }
2863 
2864 /**
2865  * add or remove space padding to parens
2866  * currentChar contains the paren
2867  * the parens and necessary padding will be appended to formattedLine
2868  * the calling function should have a continue statement after calling this method
2869  */
padParens(void)2870 void ASFormatter::padParens(void)
2871 {
2872 	assert(currentChar == '(' || currentChar == ')');
2873 
2874 	int spacesOutsideToDelete = 0;
2875 	int spacesInsideToDelete = 0;
2876 
2877 	if (currentChar == '(')
2878 	{
2879 		spacesOutsideToDelete = formattedLine.length() - 1;
2880 		spacesInsideToDelete = 0;
2881 
2882 		// compute spaces outside the opening paren to delete
2883 		if (shouldUnPadParens)
2884 		{
2885 			char lastChar = ' ';
2886 			bool prevIsParenHeader = false;
2887 			size_t i = formattedLine.find_last_not_of(" \t");
2888 			if (i != string::npos)
2889 			{
2890 				// if last char is a bracket the previous whitespace is an indent
2891 				if (formattedLine[i] == '{')
2892 					spacesOutsideToDelete = 0;
2893 				else
2894 				{
2895 					spacesOutsideToDelete -= i;
2896 					lastChar = formattedLine[i];
2897 					// if previous word is a header, it will be a paren header
2898 					string prevWord = getPreviousWord(formattedLine, formattedLine.length());
2899 					const string* prevWordH = NULL;
2900 					if (shouldPadHeader
2901 					        && prevWord.length() > 0
2902 					        && isCharPotentialHeader(prevWord, 0))
2903 						prevWordH = ASBeautifier::findHeader(prevWord, 0, headers);
2904 					if (prevWordH != NULL)
2905 					{
2906 						prevIsParenHeader = true;
2907 						// trace
2908 						//cout << traceLineNumber << " " << *prevWordH << endl;
2909 					}
2910 					else if (prevWord == "return"   // don't unpad return statements
2911 					         || prevWord == "*")    // don't unpad multiply or pointer
2912 					{
2913 						prevIsParenHeader = true;
2914 						// trace
2915 						//cout << traceLineNumber << " " << prevWord << endl;
2916 					}
2917 					// don't unpad variables
2918 					else if (prevWord == "bool"
2919 					         || prevWord ==  "int"
2920 					         || prevWord ==  "void"
2921 					         || prevWord ==  "void*"
2922 					         || (prevWord.length() >= 6     // check end of word for _t
2923 					             && prevWord.compare(prevWord.length()-2, 2, "_t") == 0)
2924 					         || prevWord ==  "BOOL"
2925 					         || prevWord ==  "DWORD"
2926 					         || prevWord ==  "HWND"
2927 					         || prevWord ==  "INT"
2928 					         || prevWord ==  "LPSTR"
2929 					         || prevWord ==  "VOID"
2930 					         || prevWord ==  "LPVOID"
2931 					        )
2932 					{
2933 						prevIsParenHeader = true;
2934 						// trace
2935 						//cout << traceLineNumber << " " << prevWord << endl;
2936 					}
2937 				}
2938 			}
2939 			// do not unpad operators, but leave them if already padded
2940 			if (shouldPadParensOutside || prevIsParenHeader)
2941 				spacesOutsideToDelete--;
2942 			else if (lastChar == '|'          // check for ||
2943 			         || lastChar == '&'      // check for &&
2944 			         || lastChar == ','
2945 			         || (lastChar == '>' && !foundCastOperator)
2946 			         || lastChar == '<'
2947 			         || lastChar == '?'
2948 			         || lastChar == ':'
2949 			         || lastChar == ';'
2950 			         || lastChar == '='
2951 			         || lastChar == '+'
2952 			         || lastChar == '-'
2953 			         || (lastChar == '*' && isInPotentialCalculation)
2954 			         || lastChar == '/'
2955 			         || lastChar == '%')
2956 				spacesOutsideToDelete--;
2957 
2958 			if (spacesOutsideToDelete > 0)
2959 			{
2960 				formattedLine.erase(i + 1, spacesOutsideToDelete);
2961 				spacePadNum -= spacesOutsideToDelete;
2962 			}
2963 		}
2964 
2965 		// pad open paren outside
2966 		char peekedCharOutside = peekNextChar();
2967 		if (shouldPadParensOutside)
2968 			if (!(currentChar == '(' && peekedCharOutside == ')'))
2969 				appendSpacePad();
2970 
2971 		appendCurrentChar();
2972 
2973 		// unpad open paren inside
2974 		if (shouldUnPadParens)
2975 		{
2976 			size_t j = currentLine.find_first_not_of(" \t", charNum + 1);
2977 			if (j != string::npos)
2978 				spacesInsideToDelete = j - charNum - 1;
2979 			if (shouldPadParensInside)
2980 				spacesInsideToDelete--;
2981 			if (spacesInsideToDelete > 0)
2982 			{
2983 				currentLine.erase(charNum + 1, spacesInsideToDelete);
2984 				spacePadNum -= spacesInsideToDelete;
2985 			}
2986 			// convert tab to space if requested
2987 			if (shouldConvertTabs
2988 			        && (int)currentLine.length() > charNum
2989 			        && currentLine[charNum+1] == '\t')
2990 				currentLine[charNum+1] = ' ';
2991 
2992 		}
2993 
2994 		// pad open paren inside
2995 		char peekedCharInside = peekNextChar();
2996 		if (shouldPadParensInside)
2997 			if (!(currentChar == '(' && peekedCharInside == ')'))
2998 				appendSpaceAfter();
2999 		// trace
3000 		//if(spacesOutsideToDelete > 0 || spacesInsideToDelete > 0)
3001 		//    cout << traceLineNumber << " " << spacesOutsideToDelete << '(' << spacesInsideToDelete << endl;
3002 	}
3003 	else if (currentChar == ')' /*|| currentChar == ']'*/)
3004 	{
3005 		spacesOutsideToDelete = 0;
3006 		spacesInsideToDelete = formattedLine.length();
3007 
3008 		// unpad close paren inside
3009 		if (shouldUnPadParens)
3010 		{
3011 			size_t i = formattedLine.find_last_not_of(" \t");
3012 			if (i != string::npos)
3013 				spacesInsideToDelete = formattedLine.length() - 1 - i;
3014 			if (shouldPadParensInside)
3015 				spacesInsideToDelete--;
3016 			if (spacesInsideToDelete > 0)
3017 			{
3018 				formattedLine.erase(i + 1, spacesInsideToDelete);
3019 				spacePadNum -= spacesInsideToDelete;
3020 			}
3021 		}
3022 
3023 		// pad close paren inside
3024 		if (shouldPadParensInside)
3025 			if (!(previousChar == '(' && currentChar == ')'))
3026 				appendSpacePad();
3027 
3028 		appendCurrentChar();
3029 
3030 		// unpad close paren outside
3031 		if (shouldUnPadParens)
3032 		{
3033 			// may have end of line comments
3034 			size_t j = currentLine.find_first_not_of(" \t", charNum + 1);
3035 			if (j != string::npos)
3036 				if (currentLine[j] == '[' || currentLine[j] == ']')
3037 					spacesOutsideToDelete = j - charNum - 1;
3038 			if (shouldPadParensOutside)
3039 				spacesOutsideToDelete--;
3040 
3041 			if (spacesOutsideToDelete > 0)
3042 			{
3043 				currentLine.erase(charNum + 1, spacesOutsideToDelete);
3044 				spacePadNum -= spacesOutsideToDelete;
3045 			}
3046 		}
3047 
3048 		// pad close paren outside
3049 		char peekedCharOutside = peekNextChar();
3050 		if (shouldPadParensOutside)
3051 			if (peekedCharOutside != ';'
3052 			        && peekedCharOutside != ','
3053 			        && peekedCharOutside != '.'
3054 			        && peekedCharOutside != '-')    // check for ->
3055 				appendSpaceAfter();
3056 
3057 		// trace
3058 		//if(spacesInsideToDelete > 0)
3059 		//	cout << traceLineNumber << " " << spacesInsideToDelete << ')' << 0 << endl;
3060 	}
3061 	return;
3062 }
3063 
3064 /**
3065  * format opening bracket as attached or broken
3066  * currentChar contains the bracket
3067  * the brackets will be appended to the current formattedLine or a new formattedLine as necessary
3068  * the calling function should have a continue statement after calling this method
3069  *
3070  * @param bracketType    the type of bracket to be formatted.
3071  */
formatOpeningBracket(BracketType bracketType)3072 void ASFormatter::formatOpeningBracket(BracketType bracketType)
3073 {
3074 	assert(!isBracketType(bracketType, ARRAY_TYPE));
3075 	assert(currentChar == '{');
3076 
3077 	parenStack->push_back(0);
3078 
3079 	bool breakBracket = isCurrentBracketBroken();
3080 
3081 	if (breakBracket)
3082 	{
3083 		if (isBeforeAnyComment() && isOkToBreakBlock(bracketType))
3084 		{
3085 			// if comment is at line end leave the comment on this line
3086 			if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBracket)	// lineBeginsWith('{')
3087 			{
3088 				currentChar = ' ';              // remove bracket from current line
3089 				currentLine[charNum] = currentChar;
3090 				appendOpeningBracket = true;    // append bracket to following line
3091 			}
3092 			// else put comment after the bracket
3093 			else if (!isBeforeMultipleLineEndComments(charNum))
3094 				breakLine();
3095 		}
3096 		else if (!isBracketType(bracketType, SINGLE_LINE_TYPE))
3097 			breakLine();
3098 		else if (shouldBreakOneLineBlocks && peekNextChar() != '}')
3099 			breakLine();
3100 		else if (!isInLineBreak)
3101 			appendSpacePad();
3102 
3103 		appendCurrentChar();
3104 
3105 		// should a following comment break from the bracket?
3106 		// must break the line AFTER the bracket
3107 		if (isBeforeComment()
3108 		        && formattedLine[0] == '{'
3109 		        && isOkToBreakBlock(bracketType)
3110 		        && (bracketFormatMode == BREAK_MODE
3111 		            || bracketFormatMode == LINUX_MODE
3112 		            || bracketFormatMode == STROUSTRUP_MODE))
3113 		{
3114 			shouldBreakLineAtNextChar = true;
3115 		}
3116 
3117 	}
3118 	else    // attach bracket
3119 	{
3120 		// are there comments before the bracket?
3121 		if (isCharImmediatelyPostComment || isCharImmediatelyPostLineComment)
3122 		{
3123 			if (isOkToBreakBlock(bracketType)
3124 			        && !(isCharImmediatelyPostComment && isCharImmediatelyPostLineComment)	// don't attach if two comments on the line
3125 			        && peekNextChar() != '}'        // don't attach { }
3126 			        && previousCommandChar != '{'   // don't attach { {
3127 			        && previousCommandChar != '}'   // don't attach } {
3128 			        && previousCommandChar != ';')  // don't attach ; {
3129 			{
3130 				appendCharInsideComments();
3131 			}
3132 			else
3133 			{
3134 				appendCurrentChar();            // don't attach
3135 			}
3136 		}
3137 		else if (previousCommandChar == '{'
3138 		         || previousCommandChar == '}'
3139 		         || previousCommandChar == ';')  // '}' , ';' chars added for proper handling of '{' immediately after a '}' or ';'
3140 		{
3141 			appendCurrentChar();                // don't attach
3142 		}
3143 		else
3144 		{
3145 			// if a blank line preceeds this don't attach
3146 			if (isEmptyLine(formattedLine))
3147 				appendCurrentChar();            // don't attach
3148 			else if (isOkToBreakBlock(bracketType)
3149 			         && !(isImmediatelyPostPreprocessor
3150 			              && currentLineBeginsWithBracket))		// lineBeginsWith('{')
3151 			{
3152 				if (peekNextChar() != '}')
3153 				{
3154 					appendSpacePad();
3155 					appendCurrentChar(false);       // OK to attach
3156 					// should a following comment attach with the bracket?
3157 					// insert spaces to reposition the comment
3158 					if (isBeforeComment()
3159 					        && !isBeforeMultipleLineEndComments(charNum)
3160 					        && (!isBeforeAnyLineEndComment(charNum)	|| currentLineBeginsWithBracket))	// lineBeginsWith('{')
3161 					{
3162 						breakLine();
3163 						currentLine.insert(charNum+1, charNum+1, ' ');
3164 					}
3165 				}
3166 				else
3167 				{
3168 					appendSpacePad();
3169 					appendCurrentChar();
3170 				}
3171 			}
3172 			else
3173 			{
3174 				if (!isInLineBreak)
3175 					appendSpacePad();
3176 				appendCurrentChar();            // don't attach
3177 			}
3178 		}
3179 	}
3180 }
3181 
3182 /**
3183  * format closing bracket
3184  * currentChar contains the bracket
3185  * the calling function should have a continue statement after calling this method
3186  *
3187  * @param bracketType    the type of bracket to be formatted.
3188  */
formatClosingBracket(BracketType bracketType)3189 void ASFormatter::formatClosingBracket(BracketType bracketType)
3190 {
3191 	assert(!isBracketType(bracketType, ARRAY_TYPE));
3192 	assert(currentChar == '}');
3193 
3194 	// parenStack must contain one entry
3195 	if (parenStack->size() > 1)
3196 		parenStack->pop_back();
3197 
3198 	// mark state of immediately after empty block
3199 	// this state will be used for locating brackets that appear immedately AFTER an empty block (e.g. '{} \n}').
3200 	if (previousCommandChar == '{')
3201 		isImmediatelyPostEmptyBlock = true;
3202 
3203 	if ((!(previousCommandChar == '{' && isPreviousBracketBlockRelated))    // this '{' does not close an empty block
3204 	        && isOkToBreakBlock(bracketType)                                // astyle is allowed to break on line blocks
3205 	        && !isImmediatelyPostEmptyBlock)                                // this '}' does not immediately follow an empty block
3206 	{
3207 		breakLine();
3208 		appendCurrentChar();
3209 	}
3210 	else
3211 	{
3212 		appendCurrentChar();
3213 	}
3214 
3215 	// if a declaration follows a definition, space pad
3216 	if (isLegalNameChar(peekNextChar()))
3217 		appendSpaceAfter();
3218 
3219 	if (shouldBreakBlocks && currentHeader != NULL && parenStack->back() == 0)
3220 	{
3221 		isAppendPostBlockEmptyLineRequested = true;
3222 	}
3223 }
3224 
3225 /**
3226  * format array brackets as attached or broken
3227  * determine if the brackets can have an inStatement indent
3228  * currentChar contains the bracket
3229  * the brackets will be appended to the current formattedLine or a new formattedLine as necessary
3230  * the calling function should have a continue statement after calling this method
3231  *
3232  * @param bracketType            the type of bracket to be formatted, must be an ARRAY_TYPE.
3233  * @param isOpeningArrayBracket  indicates if this is the opening bracket for the array block.
3234  */
formatArrayBrackets(BracketType bracketType,bool isOpeningArrayBracket)3235 void ASFormatter::formatArrayBrackets(BracketType bracketType, bool isOpeningArrayBracket)
3236 {
3237 	assert(isBracketType(bracketType, ARRAY_TYPE));
3238 	assert(currentChar == '{' || currentChar == '}');
3239 
3240 	if (currentChar == '{')
3241 	{
3242 		// is this the first opening bracket in the array?
3243 		if (isOpeningArrayBracket)
3244 		{
3245 			if (bracketFormatMode == ATTACH_MODE
3246 			        || bracketFormatMode == LINUX_MODE
3247 			        || bracketFormatMode == STROUSTRUP_MODE)
3248 			{
3249 				// don't attach to a preprocessor directive
3250 				if (isImmediatelyPostPreprocessor && currentLineBeginsWithBracket)	// lineBeginsWith('{')
3251 				{
3252 					isInLineBreak = true;
3253 					appendCurrentChar();                // don't attach
3254 				}
3255 				else if (isCharImmediatelyPostComment)
3256 				{
3257 					// TODO: attach bracket to line-end comment
3258 					appendCurrentChar();                // don't attach
3259 				}
3260 				else if (isCharImmediatelyPostLineComment)
3261 				{
3262 					appendCharInsideComments();
3263 				}
3264 				else
3265 				{
3266 					// if a blank line preceeds this don't attach
3267 					if (isEmptyLine(formattedLine))
3268 						appendCurrentChar();            // don't attach
3269 					else
3270 					{
3271 						// if bracket is broken or not an assignment
3272 						if (currentLineBeginsWithBracket 	// lineBeginsWith('{')
3273 						        && !isBracketType(bracketTypeStack->back(), SINGLE_LINE_TYPE))
3274 						{
3275 							appendSpacePad();
3276 							appendCurrentChar(false);       // OK to attach
3277 
3278 							if (currentLineBeginsWithBracket
3279 							        && (int)currentLineFirstBracketNum == charNum)
3280 								shouldBreakLineAtNextChar = true;
3281 						}
3282 						else
3283 						{
3284 							appendSpacePad();
3285 							appendCurrentChar();
3286 						}
3287 					}
3288 				}
3289 			}
3290 			else if (bracketFormatMode == BREAK_MODE)
3291 			{
3292 				if (isWhiteSpace(peekNextChar()))
3293 					breakLine();
3294 				else if (isBeforeAnyComment())
3295 				{
3296 					// do not break unless comment is at line end
3297 					if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBracket)
3298 					{
3299 						currentChar = ' ';              // remove bracket from current line
3300 						appendOpeningBracket = true;    // append bracket to following line
3301 					}
3302 				}
3303 				if (!isInLineBreak)
3304 					appendSpacePad();
3305 				appendCurrentChar();
3306 
3307 				if (currentLineBeginsWithBracket
3308 				        && (int)currentLineFirstBracketNum == charNum
3309 				        && !isBracketType(bracketTypeStack->back(), SINGLE_LINE_TYPE))
3310 					shouldBreakLineAtNextChar = true;
3311 			}
3312 			else if (bracketFormatMode == HORSTMANN_MODE)
3313 			{
3314 				if (isWhiteSpace(peekNextChar()))
3315 					breakLine();
3316 				else if (isBeforeAnyComment())
3317 				{
3318 					// do not break unless comment is at line end
3319 					if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBracket)	// lineBeginsWith('{')
3320 					{
3321 						currentChar = ' ';              // remove bracket from current line
3322 						appendOpeningBracket = true;    // append bracket to following line
3323 					}
3324 				}
3325 				if (!isInLineBreak)
3326 					appendSpacePad();
3327 				appendCurrentChar();
3328 			}
3329 			else if (bracketFormatMode == NONE_MODE)
3330 			{
3331 				if (currentLineBeginsWithBracket)       // lineBeginsWith('{')
3332 				{
3333 					appendCurrentChar();                // don't attach
3334 				}
3335 				else
3336 				{
3337 					appendSpacePad();
3338 					appendCurrentChar(false);           // OK to attach
3339 				}
3340 			}
3341 		}
3342 		else	     // not the first opening bracket
3343 		{
3344 			if (bracketFormatMode == HORSTMANN_MODE)
3345 			{
3346 				if (previousNonWSChar == '{'
3347 				        && bracketTypeStack->size() > 2
3348 				        && !isBracketType((*bracketTypeStack)[bracketTypeStack->size()-2], SINGLE_LINE_TYPE))
3349 					formatArrayRunIn();
3350 			}
3351 			else if (!isInLineBreak
3352 			         && !isWhiteSpace(peekNextChar())
3353 			         && previousNonWSChar == '{'
3354 			         && bracketTypeStack->size() > 2
3355 			         && !isBracketType((*bracketTypeStack)[bracketTypeStack->size()-2], SINGLE_LINE_TYPE))
3356 				formatArrayRunIn();
3357 
3358 			appendCurrentChar();
3359 		}
3360 	}
3361 	else if (currentChar == '}')
3362 	{
3363 		// does this close the first opening bracket in the array?
3364 		if (!isBracketType(bracketType, SINGLE_LINE_TYPE) )
3365 			breakLine();
3366 		appendCurrentChar();
3367 
3368 		// if a declaration follows an enum definition, space pad
3369 		char peekedChar = peekNextChar();
3370 		if (isLegalNameChar(peekedChar)
3371 		        || peekedChar == '[')
3372 			appendSpaceAfter();
3373 	}
3374 }
3375 
3376 /**
3377  * determine if a run-in can be attached.
3378  * if it can insert the indents in formattedLine and reset the current line break.
3379  */
formatRunIn()3380 void ASFormatter::formatRunIn()
3381 {
3382 	assert(bracketFormatMode == HORSTMANN_MODE || bracketFormatMode == NONE_MODE);
3383 
3384 	// keep one line blocks returns true without indenting the run-in
3385 	if (!isOkToBreakBlock(bracketTypeStack->back()))
3386 		return; // true;
3387 
3388 	size_t lastText = formattedLine.find_last_not_of(" \t");
3389 	if (lastText == string::npos || formattedLine[lastText] != '{')
3390 		return; // false;
3391 
3392 	// make sure the bracket is broken
3393 	if (formattedLine.find_first_not_of(" \t{") != string::npos)
3394 		return; // false;
3395 
3396 	if (isBracketType(bracketTypeStack->back(), NAMESPACE_TYPE))
3397 		return; // false;
3398 
3399 	bool extraIndent = false;
3400 	isInLineBreak = true;
3401 
3402 	// cannot attach a class modifier without indent-classes
3403 	if (isCStyle()
3404 	        && isCharPotentialHeader(currentLine, charNum)
3405 	        && (isBracketType(bracketTypeStack->back(), CLASS_TYPE)
3406 	            || (isBracketType(bracketTypeStack->back(), STRUCT_TYPE)
3407 	                && isInIndentableStruct)))
3408 	{
3409 		if (findKeyword(currentLine, charNum, AS_PUBLIC)
3410 		        || findKeyword(currentLine, charNum, AS_PRIVATE)
3411 		        || findKeyword(currentLine, charNum, AS_PROTECTED))
3412 		{
3413 			if (!getClassIndent())
3414 				return; // false;
3415 		}
3416 		else if (getClassIndent())
3417 			extraIndent = true;
3418 	}
3419 
3420 	// cannot attach a 'case' statement without indent-switches
3421 	if (!getSwitchIndent()
3422 	        && isCharPotentialHeader(currentLine, charNum)
3423 	        && (findKeyword(currentLine, charNum, AS_CASE)
3424 	            || findKeyword(currentLine, charNum, AS_DEFAULT)))
3425 		return; // false;
3426 
3427 	// extra indent for switch statements
3428 	if (getSwitchIndent()
3429 	        && !preBracketHeaderStack->empty()
3430 	        && preBracketHeaderStack->back() == &AS_SWITCH
3431 	        && ((isLegalNameChar(currentChar)
3432 	             && !findKeyword(currentLine, charNum, AS_CASE))
3433 	            || isSequenceReached("//")
3434 	            || isSequenceReached("/*")))
3435 		extraIndent = true;
3436 
3437 	isInLineBreak = false;
3438 	// remove for extra whitespace
3439 	if (formattedLine.length() > lastText+1
3440 	        && formattedLine.find_first_not_of(" \t", lastText+1) == string::npos)
3441 		formattedLine.erase(lastText+1);
3442 
3443 	if (getIndentString() == "\t")
3444 	{
3445 		appendChar('\t', false);
3446 		horstmannIndentChars = 2;	// one for { and one for tab
3447 		if (extraIndent)
3448 		{
3449 			appendChar('\t', false);
3450 			horstmannIndentChars++;
3451 		}
3452 	}
3453 	else
3454 	{
3455 		int indent = getIndentLength();
3456 		formattedLine.append(indent-1, ' ');
3457 		horstmannIndentChars = indent;
3458 		if (extraIndent)
3459 		{
3460 			formattedLine.append(indent, ' ');
3461 			horstmannIndentChars += indent;
3462 		}
3463 	}
3464 	isInHorstmannRunIn = true;
3465 }
3466 
3467 /**
3468  * remove whitepace and add indentation for an array run-in.
3469  */
formatArrayRunIn()3470 void ASFormatter::formatArrayRunIn()
3471 {
3472 	assert(isBracketType(bracketTypeStack->back(), ARRAY_TYPE));
3473 
3474 	// make sure the bracket is broken
3475 	if (formattedLine.find_first_not_of(" \t{") != string::npos)
3476 		return;
3477 
3478 	size_t lastText = formattedLine.find_last_not_of(" \t");
3479 	if (lastText == string::npos || formattedLine[lastText] != '{')
3480 		return;
3481 
3482 	// check for extra whitespace
3483 	if (formattedLine.length() > lastText+1
3484 	        && formattedLine.find_first_not_of(" \t", lastText+1) == string::npos)
3485 		formattedLine.erase(lastText+1);
3486 
3487 	if (getIndentString() == "\t")
3488 	{
3489 		appendChar('\t', false);
3490 		horstmannIndentChars = 2;	// one for { and one for tab
3491 	}
3492 	else
3493 	{
3494 		int indent = getIndentLength();
3495 		formattedLine.append(indent-1, ' ');
3496 		horstmannIndentChars = indent;
3497 	}
3498 	isInHorstmannRunIn = true;
3499 	isInLineBreak = false;
3500 }
3501 
3502 /**
3503  * delete a bracketTypeStack vector object
3504  * BracketTypeStack did not work with the DeleteContainer template
3505  */
deleteContainer(vector<BracketType> * & container)3506 void ASFormatter::deleteContainer(vector<BracketType>* &container)
3507 {
3508 	if (container != NULL)
3509 	{
3510 		container->clear();
3511 		delete (container);
3512 		container = NULL;
3513 	}
3514 }
3515 
3516 /**
3517  * delete a vector object
3518  * T is the type of vector
3519  * used for all vectors except bracketTypeStack
3520  */
3521 template<typename T>
deleteContainer(T & container)3522 void ASFormatter::deleteContainer(T &container)
3523 {
3524 	if (container != NULL)
3525 	{
3526 		container->clear();
3527 		delete (container);
3528 		container = NULL;
3529 	}
3530 }
3531 
3532 /**
3533  * initialize a BracketType vector object
3534  * BracketType did not work with the DeleteContainer template
3535  */
initContainer(vector<BracketType> * & container,vector<BracketType> * value)3536 void ASFormatter::initContainer(vector<BracketType>* &container, vector<BracketType>* value)
3537 {
3538 	if (container != NULL)
3539 		deleteContainer(container);
3540 	container = value;
3541 }
3542 
3543 /**
3544  * initialize a vector object
3545  * T is the type of vector
3546  * used for all vectors except bracketTypeStack
3547  */
3548 template<typename T>
initContainer(T & container,T value)3549 void ASFormatter::initContainer(T &container, T value)
3550 {
3551 	// since the ASFormatter object is never deleted,
3552 	// the existing vectors must be deleted before creating new ones
3553 	if (container != NULL)
3554 		deleteContainer(container);
3555 	container = value;
3556 }
3557 
3558 /**
3559  * convert a tab to spaces.
3560  * charNum points to the current character to convert to spaces.
3561  * tabIncrementIn is the increment that must be added for tab indent characters
3562  *     to get the correct column for the current tab.
3563  * replaces the tab in currentLine with the required number of spaces.
3564  * replaces the value of currentChar.
3565  */
convertTabToSpaces()3566 void ASFormatter::convertTabToSpaces()
3567 {
3568 	assert(currentLine[charNum] == '\t');
3569 
3570 	// do NOT replace if in quotes
3571 	if (isInQuote || isInQuoteContinuation)
3572 		return;
3573 
3574 	size_t indent = getIndentLength();
3575 	size_t numSpaces = indent - ((tabIncrementIn + charNum) % indent);
3576 	currentLine.replace(charNum, 1, numSpaces, ' ');
3577 	currentChar = currentLine[charNum];
3578 }
3579 
3580 /**
3581 * is it ok to break this block?
3582 */
isOkToBreakBlock(BracketType bracketType) const3583 bool ASFormatter::isOkToBreakBlock(BracketType bracketType) const
3584 {
3585 	// Actually, there should not be an ARRAY_TYPE bracket here.
3586 	// But this will avoid breaking a one line block when there is.
3587 	// Otherwise they will be formatted differently on consecutive runs.
3588 	if (isBracketType(bracketType, ARRAY_TYPE)
3589 	        && isBracketType(bracketType, SINGLE_LINE_TYPE))
3590 		return false;
3591 	if (!isBracketType(bracketType, SINGLE_LINE_TYPE)
3592 	        || shouldBreakOneLineBlocks
3593 	        || breakCurrentOneLineBlock)
3594 		return true;
3595 	return false;
3596 }
3597 
3598 /**
3599 * check if a sharp header is a paren or nonparen header
3600 */
isSharpStyleWithParen(const string * header) const3601 bool ASFormatter::isSharpStyleWithParen(const string* header) const
3602 {
3603 	if (isSharpStyle() && peekNextChar() == '('
3604 	        && (header == &AS_CATCH
3605 	            || header == &AS_DELEGATE))
3606 		return true;
3607 	return false;
3608 }
3609 
3610 /**
3611  * check for a following header when a comment is reached.
3612  * if a header follows, the comments are kept as part of the header block.
3613  * firstLine must contain the start of the comment.
3614  */
checkForFollowingHeader(const string & firstLine)3615 void ASFormatter::checkForFollowingHeader(const string& firstLine)
3616 {
3617 	// look ahead to find the next non-comment text
3618 	string nextText = peekNextText(firstLine, true);
3619 	if (nextText.length() == 0 || !isCharPotentialHeader(nextText, 0))
3620 		return;
3621 
3622 	const string* newHeader = ASBeautifier::findHeader(nextText, 0, headers);
3623 
3624 	if (newHeader == NULL)
3625 		return;
3626 
3627 	// may need to break if a header follows
3628 	bool isClosingHeader = (newHeader == &AS_ELSE
3629 	                        || newHeader == &AS_CATCH
3630 	                        || newHeader == &AS_FINALLY);
3631 
3632 	// if a closing header, reset break unless break is requested
3633 	if (isClosingHeader)
3634 	{
3635 		if (!shouldBreakClosingHeaderBlocks)
3636 			isPrependPostBlockEmptyLineRequested = false;
3637 	}
3638 	// if an opening header, break before the comment
3639 	else
3640 	{
3641 		isPrependPostBlockEmptyLineRequested = true;
3642 	}
3643 }
3644 
3645 /**
3646  * process preprocessor statements.
3647  * charNum should be the index of the preprocessor directive.
3648  *
3649  * delete bracketTypeStack entries added by #if if a #else is found.
3650  * prevents double entries in the bracketTypeStack.
3651  */
processPreprocessor()3652 void ASFormatter::processPreprocessor()
3653 {
3654 	assert(currentChar == '#');
3655 
3656 	const int preproc = charNum + 1;
3657 
3658 	if (currentLine.compare(preproc, 2, "if") == 0)
3659 	{
3660 		preprocBracketTypeStackSize = bracketTypeStack->size();
3661 	}
3662 	else if (currentLine.compare(preproc, 4, "else") == 0)
3663 	{
3664 		// delete stack entries added in #if
3665 		// should be replaced by #else
3666 		if (preprocBracketTypeStackSize > 0)
3667 		{
3668 			int addedPreproc = bracketTypeStack->size() - preprocBracketTypeStackSize;
3669 			for (int i=0; i < addedPreproc; i++)
3670 				bracketTypeStack->pop_back();
3671 		}
3672 	}
3673 }
3674 
3675 /**
3676  * determine if the next line starts a comment
3677  * and a header follows the comment or comments
3678  */
commentAndHeaderFollows() const3679 bool ASFormatter::commentAndHeaderFollows() const
3680 {
3681 	// is the next line a comment
3682 	string nextLine = sourceIterator->peekNextLine();
3683 	size_t firstChar = nextLine.find_first_not_of(" \t");
3684 	if (firstChar == string::npos
3685 	        || !(nextLine.compare(firstChar, 2, "//") == 0
3686 	             || nextLine.compare(firstChar, 2, "/*") == 0))
3687 	{
3688 		sourceIterator->peekReset();
3689 		return false;
3690 	}
3691 
3692 	// if next line is a comment, find the next non-comment text
3693 	string nextText = peekNextText(nextLine, true);
3694 	if (nextText.length() == 0 || !isCharPotentialHeader(nextText, 0))
3695 		return false;
3696 
3697 	const string* newHeader = ASBeautifier::findHeader(nextText, 0, headers);
3698 
3699 	if (newHeader == NULL)
3700 		return false;
3701 
3702 	bool isClosingHeader = (newHeader == &AS_ELSE
3703 	                        || newHeader == &AS_CATCH
3704 	                        || newHeader == &AS_FINALLY);
3705 
3706 	if (isClosingHeader && !shouldBreakClosingHeaderBlocks)
3707 		return false;
3708 
3709 	return true;
3710 }
3711 
3712 /**
3713  * determine if a bracket should be attached or broken
3714  * uses brackets in the bracketTypeStack
3715  * the last bracket in the bracketTypeStack is the one being formatted
3716  * returns true if the bracket should be broken
3717  */
isCurrentBracketBroken() const3718 bool ASFormatter::isCurrentBracketBroken() const
3719 {
3720 	assert(bracketTypeStack->size() > 0);
3721 
3722 	bool breakBracket = false;
3723 	size_t bracketTypeStackEnd = bracketTypeStack->size()-1;
3724 
3725 	if (isBracketType((*bracketTypeStack)[bracketTypeStackEnd], EXTERN_TYPE))
3726 	{
3727 		if (currentLineBeginsWithBracket
3728 		        || bracketFormatMode == HORSTMANN_MODE)
3729 			breakBracket = true;
3730 	}
3731 	else if (bracketFormatMode == NONE_MODE)
3732 	{
3733 		if (currentLineBeginsWithBracket
3734 		        && (int)currentLineFirstBracketNum == charNum)		// lineBeginsWith('{')
3735 			breakBracket = true;
3736 	}
3737 	else if (bracketFormatMode == BREAK_MODE || bracketFormatMode == HORSTMANN_MODE)
3738 	{
3739 		breakBracket = true;
3740 	}
3741 	else if (bracketFormatMode == LINUX_MODE || bracketFormatMode == STROUSTRUP_MODE)
3742 	{
3743 		// break a class if Linux
3744 		if (isBracketType((*bracketTypeStack)[bracketTypeStackEnd], CLASS_TYPE))
3745 		{
3746 			if (bracketFormatMode == LINUX_MODE)
3747 				breakBracket = true;
3748 		}
3749 		// break a namespace or interface if Linux
3750 		else if (isBracketType((*bracketTypeStack)[bracketTypeStackEnd], NAMESPACE_TYPE)
3751 		         || isBracketType((*bracketTypeStack)[bracketTypeStackEnd], INTERFACE_TYPE))
3752 		{
3753 			if (bracketFormatMode == LINUX_MODE)
3754 				breakBracket = true;
3755 		}
3756 		// break the first bracket if a function
3757 		else if (bracketTypeStackEnd == 1
3758 		         && isBracketType((*bracketTypeStack)[bracketTypeStackEnd], COMMAND_TYPE))
3759 		{
3760 			breakBracket = true;
3761 		}
3762 		else if (bracketTypeStackEnd > 1)
3763 		{
3764 			// break the first bracket after a namespace or extern if a function
3765 			if (isBracketType((*bracketTypeStack)[bracketTypeStackEnd-1], NAMESPACE_TYPE)
3766 			        || isBracketType((*bracketTypeStack)[bracketTypeStackEnd-1], EXTERN_TYPE))
3767 			{
3768 				if (isBracketType((*bracketTypeStack)[bracketTypeStackEnd], COMMAND_TYPE))
3769 					breakBracket = true;
3770 			}
3771 			// if not C style then break the first bracket after a class if a function
3772 			else if (!isCStyle())
3773 			{
3774 				if ((isBracketType((*bracketTypeStack)[bracketTypeStackEnd-1], CLASS_TYPE)
3775 				        || isBracketType((*bracketTypeStack)[bracketTypeStackEnd-1], ARRAY_TYPE)
3776 				        || isBracketType((*bracketTypeStack)[bracketTypeStackEnd-1], STRUCT_TYPE))
3777 				        && isBracketType((*bracketTypeStack)[bracketTypeStackEnd], COMMAND_TYPE))
3778 					breakBracket = true;
3779 			}
3780 		}
3781 	}
3782 	return breakBracket;
3783 }
3784 
3785 /**
3786  * format comment body
3787  * the calling function should have a continue statement after calling this method
3788  */
formatCommentBody()3789 void ASFormatter::formatCommentBody()
3790 {
3791 	assert(isInComment);
3792 
3793 	if (isSequenceReached("*/"))
3794 	{
3795 		isInComment = false;
3796 		noTrimCommentContinuation = false;
3797 		isImmediatelyPostComment = true;
3798 		appendSequence(AS_CLOSE_COMMENT);
3799 		goForward(1);
3800 		if (doesLineStartComment
3801 		        && (currentLine.find_first_not_of(" \t", charNum+1) == string::npos))
3802 			lineEndsInCommentOnly = true;
3803 		if (peekNextChar() == '}'
3804 		        && previousCommandChar != ';'
3805 		        && !isBracketType(bracketTypeStack->back(),  ARRAY_TYPE)
3806 		        && isOkToBreakBlock(bracketTypeStack->back()))
3807 			breakLine();
3808 	}
3809 	else
3810 	{
3811 		appendCurrentChar();
3812 		// append the comment up to the next tab or comment end
3813 		// tabs must be checked for convert-tabs before appending
3814 		while (charNum + 1 < (int) currentLine.length()
3815 		        && currentLine[charNum+1] != '\t'
3816 		        && currentLine.compare(charNum+1, 2, "*/") != 0)
3817 		{
3818 			currentChar = currentLine[++charNum];
3819 			appendCurrentChar();
3820 		}
3821 	}
3822 }
3823 
3824 /**
3825  * format a comment opener
3826  * the comment opener will be appended to the current formattedLine or a new formattedLine as necessary
3827  * the calling function should have a continue statement after calling this method
3828  */
formatCommentOpener()3829 void ASFormatter::formatCommentOpener()
3830 {
3831 	assert(isSequenceReached("/*"));
3832 
3833 	isInComment = true;
3834 	isImmediatelyPostLineComment = false;
3835 
3836 	if (spacePadNum != 0)
3837 		adjustComments();
3838 	formattedLineCommentNum = formattedLine.length();
3839 
3840 	// must be done BEFORE appendSequence
3841 	if (previousCommandChar == '{'
3842 	        && !isImmediatelyPostComment
3843 	        && !isImmediatelyPostLineComment)
3844 	{
3845 		if (bracketFormatMode == NONE_MODE)
3846 		{
3847 			// should a run-in statement be attached?
3848 			if (currentLineBeginsWithBracket)
3849 				formatRunIn();
3850 		}
3851 		else if (bracketFormatMode == ATTACH_MODE)
3852 		{
3853 			// if the bracket was not attached?
3854 			if (formattedLine[0] == '{'
3855 			        && !isBracketType(bracketTypeStack->back(), SINGLE_LINE_TYPE))
3856 				isInLineBreak = true;
3857 		}
3858 		else if (bracketFormatMode == HORSTMANN_MODE)
3859 		{
3860 			// should a run-in statement be attached?
3861 			if (formattedLine[0] == '{')
3862 				formatRunIn();
3863 		}
3864 	}
3865 	else if (!doesLineStartComment)
3866 		noTrimCommentContinuation = true;
3867 
3868 	// appendSequence will write the previous line
3869 	appendSequence(AS_OPEN_COMMENT);
3870 	goForward(1);
3871 
3872 	// must be done AFTER appendSequence
3873 	if (shouldBreakBlocks)
3874 	{
3875 		// break before the comment if a header follows the comment
3876 		// for speed, do not check if previous line is empty,
3877 		//     if previous line is a line comment or if previous line is '{'
3878 		if (doesLineStartComment
3879 		        && !isImmediatelyPostEmptyLine
3880 		        && !isImmediatelyPostComment
3881 		        && !isImmediatelyPostLineComment
3882 		        && previousCommandChar != '{')
3883 		{
3884 			checkForFollowingHeader(currentLine.substr(charNum-1));
3885 		}
3886 	}
3887 
3888 	if (previousCommandChar == '}')
3889 		currentHeader = NULL;
3890 }
3891 
3892 /**
3893  * format a line comment body
3894  * the calling function should have a continue statement after calling this method
3895  */
formatLineCommentBody()3896 void ASFormatter::formatLineCommentBody()
3897 {
3898 	assert(isInLineComment);
3899 
3900 	appendCurrentChar();
3901 	// append the comment up to the next tab
3902 	// tabs must be checked for convert-tabs before appending
3903 	while (charNum + 1 < (int) currentLine.length()
3904 	        && currentLine[charNum+1] != '\t')
3905 	{
3906 		currentChar = currentLine[++charNum];
3907 		appendCurrentChar();
3908 	}
3909 
3910 	// explicitely break a line when a line comment's end is found.
3911 	if (charNum + 1 == (int) currentLine.length())
3912 	{
3913 		isInLineBreak = true;
3914 		isInLineComment = false;
3915 		isImmediatelyPostLineComment = true;
3916 		currentChar = 0;  //make sure it is a neutral char.
3917 	}
3918 }
3919 
3920 /**
3921  * format a line comment opener
3922  * the line comment opener will be appended to the current formattedLine or a new formattedLine as necessary
3923  * the calling function should have a continue statement after calling this method
3924  */
formatLineCommentOpener()3925 void ASFormatter::formatLineCommentOpener()
3926 {
3927 	assert(isSequenceReached("//"));
3928 
3929 	if (currentLine[charNum+2] == '\xf2')       // check for windows line marker
3930 		isAppendPostBlockEmptyLineRequested = false;
3931 
3932 	isInLineComment = true;
3933 	isCharImmediatelyPostComment = false;
3934 
3935 	// do not indent if in column 1 or 2
3936 	if (!shouldIndentCol1Comments && !lineCommentNoIndent)
3937 	{
3938 		if (charNum == 0)
3939 			lineCommentNoIndent = true;
3940 		else if (charNum == 1 && currentLine[0] == ' ')
3941 			lineCommentNoIndent = true;
3942 	}
3943 	// move comment if spaces were added or deleted
3944 	if (lineCommentNoIndent == false && spacePadNum != 0)
3945 		adjustComments();
3946 	formattedLineCommentNum = formattedLine.length();
3947 
3948 	// must be done BEFORE appendSequence
3949 	// check for run-in statement
3950 	if (previousCommandChar == '{'
3951 	        && !isImmediatelyPostComment
3952 	        && !isImmediatelyPostLineComment)
3953 	{
3954 		if (bracketFormatMode == NONE_MODE)
3955 		{
3956 			if (currentLineBeginsWithBracket)
3957 				formatRunIn();
3958 		}
3959 		else if (bracketFormatMode == HORSTMANN_MODE)
3960 		{
3961 			if (!lineCommentNoIndent)
3962 				formatRunIn();
3963 			else
3964 				isInLineBreak = true;
3965 		}
3966 		else if (bracketFormatMode == BREAK_MODE)
3967 		{
3968 			if (formattedLine[0] == '{')
3969 				isInLineBreak = true;
3970 		}
3971 		else
3972 		{
3973 			if (currentLineBeginsWithBracket)
3974 				isInLineBreak = true;
3975 		}
3976 	}
3977 
3978 	// appendSequence will write the previous line
3979 	appendSequence(AS_OPEN_LINE_COMMENT);
3980 	goForward(1);
3981 
3982 	if (formattedLine.compare(0, 2, "//") == 0)
3983 		lineIsLineCommentOnly = true;
3984 
3985 	// must be done AFTER appendSequence
3986 	if (shouldBreakBlocks)
3987 	{
3988 		// break before the comment if a header follows the line comment
3989 		// for speed, do not check if previous line is empty,
3990 		//     if previous line is a comment or if previous line is '{'
3991 		if (lineIsLineCommentOnly
3992 		        && previousCommandChar != '{'
3993 		        && !isImmediatelyPostEmptyLine
3994 		        && !isImmediatelyPostComment
3995 		        && !isImmediatelyPostLineComment)
3996 		{
3997 			checkForFollowingHeader(currentLine.substr(charNum-1));
3998 		}
3999 	}
4000 
4001 	if (previousCommandChar == '}')
4002 		currentHeader = NULL;
4003 
4004 	// if tabbed input don't convert the immediately following tabs to spaces
4005 	if (getIndentString() == "\t" && lineCommentNoIndent)
4006 	{
4007 		while (charNum + 1 < (int) currentLine.length()
4008 		        && currentLine[charNum+1] == '\t')
4009 		{
4010 			currentChar = currentLine[++charNum];
4011 			appendCurrentChar();
4012 		}
4013 	}
4014 
4015 	// explicitely break a line when a line comment's end is found.
4016 	if (charNum + 1 == (int) currentLine.length())
4017 	{
4018 		isInLineBreak = true;
4019 		isInLineComment = false;
4020 		isImmediatelyPostLineComment = true;
4021 		currentChar = 0;  //make sure it is a neutral char.
4022 	}
4023 }
4024 
4025 /**
4026  * format quote body
4027  * the calling function should have a continue statement after calling this method
4028  */
formatQuoteBody()4029 void ASFormatter::formatQuoteBody()
4030 {
4031 	assert(isInQuote);
4032 
4033 	if (isSpecialChar)
4034 	{
4035 		isSpecialChar = false;
4036 	}
4037 	else if (currentChar == '\\' && !isInVerbatimQuote)
4038 	{
4039 		if (peekNextChar() == ' ')              // is this '\' at end of line
4040 			haveLineContinuationChar = true;
4041 		else
4042 			isSpecialChar = true;
4043 	}
4044 	else if (isInVerbatimQuote && currentChar == '"')
4045 	{
4046 		if (peekNextChar() == '"')              // check consecutive quotes
4047 		{
4048 			appendSequence("\"\"");
4049 			goForward(1);
4050 			return;
4051 		}
4052 		else
4053 		{
4054 			isInQuote = false;
4055 			isInVerbatimQuote = false;
4056 		}
4057 	}
4058 	else if (quoteChar == currentChar)
4059 	{
4060 		isInQuote = false;
4061 	}
4062 
4063 	appendCurrentChar();
4064 
4065 	// append the text to the ending quoteChar or an escape sequence
4066 	// tabs in quotes are NOT changed by convert-tabs
4067 	if (isInQuote && currentChar != '\\')
4068 	{
4069 		while (charNum + 1 < (int) currentLine.length()
4070 		        && currentLine[charNum+1] != quoteChar
4071 		        && currentLine[charNum+1] != '\\')
4072 		{
4073 			currentChar = currentLine[++charNum];
4074 			appendCurrentChar();
4075 		}
4076 	}
4077 }
4078 
4079 /**
4080  * format a quote opener
4081  * the quote opener will be appended to the current formattedLine or a new formattedLine as necessary
4082  * the calling function should have a continue statement after calling this method
4083  */
formatQuoteOpener()4084 void ASFormatter::formatQuoteOpener()
4085 {
4086 	assert(currentChar == '"' || currentChar == '\'');
4087 
4088 	isInQuote = true;
4089 	quoteChar = currentChar;
4090 	if (isSharpStyle() && previousChar == '@')
4091 		isInVerbatimQuote = true;
4092 
4093 	// a quote following a bracket is an array
4094 	if (previousCommandChar == '{'
4095 	        && !isImmediatelyPostComment
4096 	        && !isImmediatelyPostLineComment
4097 	        && isNonInStatementArray
4098 	        && !isBracketType(bracketTypeStack->back(), SINGLE_LINE_TYPE)
4099 	        && !isWhiteSpace(peekNextChar()))
4100 	{
4101 		if (bracketFormatMode == NONE_MODE)
4102 		{
4103 			if (currentLineBeginsWithBracket)
4104 				formatRunIn();
4105 		}
4106 		else if (bracketFormatMode == HORSTMANN_MODE)
4107 		{
4108 			if (!lineCommentNoIndent)
4109 				formatRunIn();
4110 			else
4111 				isInLineBreak = true;
4112 		}
4113 		else if (bracketFormatMode == BREAK_MODE)
4114 		{
4115 			if (formattedLine[0] == '{')
4116 				isInLineBreak = true;
4117 		}
4118 		else
4119 		{
4120 			if (currentLineBeginsWithBracket)
4121 				isInLineBreak = true;
4122 		}
4123 	}
4124 	previousCommandChar = ' ';
4125 	appendCurrentChar();
4126 }
4127 
4128 /**
4129  * get the next line comment adjustment that results from breaking a closing bracket.
4130  * the bracket must be on the same line as the closing header.
4131  * i.e "} else" changed to "} \n else".
4132  */
getNextLineCommentAdjustment()4133 int ASFormatter::getNextLineCommentAdjustment()
4134 {
4135 	assert(foundClosingHeader && previousNonWSChar == '}');
4136 	if (charNum < 1)
4137 		return 0;
4138 	size_t lastBracket = currentLine.rfind('}', charNum - 1);
4139 	if (lastBracket != string::npos)
4140 		return (lastBracket - charNum);	// return a negative number
4141 	return 0;
4142 }
4143 
getLineEndFormat() const4144 LineEndFormat ASFormatter::getLineEndFormat() const
4145 {
4146 	return lineEnd;
4147 }
4148 
4149 /**
4150  * get the current line comment adjustment that results from attaching
4151  * a closing header to a closing bracket.
4152  * the bracket must be on the line previous to the closing header.
4153  * the adjustment is 2 chars, one for the bracket and one for the space.
4154  * i.e "} \n else" changed to "} else".
4155  */
getCurrentLineCommentAdjustment()4156 int ASFormatter::getCurrentLineCommentAdjustment()
4157 {
4158 	assert(foundClosingHeader && previousNonWSChar == '}');
4159 	if (charNum < 1)
4160 		return 2;
4161 	size_t lastBracket = currentLine.rfind('}', charNum - 1);
4162 	if (lastBracket == string::npos)
4163 		return 2;
4164 	return 0;
4165 }
4166 
4167 /**
4168  * get the previous word
4169  * the argument 'end' must point to the search start.
4170  *
4171  * @return is the previous word.
4172  */
getPreviousWord(const string & line,int currPos) const4173 string ASFormatter::getPreviousWord(const string& line, int currPos) const
4174 {
4175 	// get the last legal word (may be a number)
4176 	if (currPos == 0)
4177 		return string();
4178 
4179 	size_t end = line.find_last_not_of(" \t", currPos-1);
4180 	if (end == string::npos || !isLegalNameChar(line[end]))
4181 		return string();
4182 
4183 	int start;          // start of the previous word
4184 	for (start = end; start > -1; start--)
4185 	{
4186 		if (!isLegalNameChar(line[start]) || line[start] == '.')
4187 			break;
4188 	}
4189 	start++;
4190 
4191 	return (line.substr(start, end-start+1));
4192 }
4193 
4194 /**
4195  * check if a line break is needed when a closing bracket
4196  * is followed by a closing header.
4197  * the break depends on the bracketFormatMode and other factors.
4198  */
isLineBreakBeforeClosingHeader()4199 void ASFormatter::isLineBreakBeforeClosingHeader()
4200 {
4201 	assert(foundClosingHeader && previousNonWSChar == '}');
4202 	if (bracketFormatMode == BREAK_MODE || bracketFormatMode == HORSTMANN_MODE)
4203 	{
4204 		isInLineBreak = true;
4205 	}
4206 	else if (bracketFormatMode == NONE_MODE)
4207 	{
4208 		if (shouldBreakClosingHeaderBrackets
4209 		        || getBracketIndent() || getBlockIndent())
4210 		{
4211 			isInLineBreak = true;
4212 		}
4213 		else
4214 		{
4215 			appendSpacePad();
4216 			// is closing bracket broken?
4217 			size_t i = currentLine.find_first_not_of(" \t");
4218 			if (i != string::npos && currentLine[i] == '}')
4219 				isInLineBreak = false;
4220 
4221 			if (shouldBreakBlocks)
4222 				isAppendPostBlockEmptyLineRequested = false;
4223 		}
4224 	}
4225 	// bracketFormatMode == ATTACH_MODE, LINUX_MODE, STROUSTRUP_MODE
4226 	else
4227 	{
4228 		if (shouldBreakClosingHeaderBrackets
4229 		        || getBracketIndent() || getBlockIndent())
4230 		{
4231 			isInLineBreak = true;
4232 		}
4233 		else
4234 		{
4235 			// if a blank line does not preceed this
4236 			// or last line is not a one line block, attach header
4237 			bool previousLineIsEmpty = isEmptyLine(formattedLine);
4238 			bool previousLineIsOneLineBlock = false;
4239 			size_t firstBracket = findNextChar(formattedLine, '{');
4240 			if (firstBracket != string::npos)
4241 				previousLineIsOneLineBlock = isOneLineBlockReached(formattedLine, firstBracket);
4242 			if (!previousLineIsEmpty
4243 			        && !previousLineIsOneLineBlock)
4244 			{
4245 				isInLineBreak = false;
4246 				appendSpacePad();
4247 				spacePadNum = 0;	// don't count as comment padding
4248 			}
4249 
4250 			if (shouldBreakBlocks)
4251 				isAppendPostBlockEmptyLineRequested = false;
4252 		}
4253 	}
4254 }
4255 
4256 /**
4257  * Add brackets to a single line statement following a header.
4258  * Brackets are not added if the proper conditions are not met.
4259  * Brackets are added to the currentLine.
4260  */
addBracketsToStatement()4261 bool ASFormatter::addBracketsToStatement()
4262 {
4263 	assert(isImmediatelyPostHeader);
4264 
4265 	if (currentHeader != &AS_IF
4266 	        && currentHeader != &AS_ELSE
4267 	        && currentHeader != &AS_FOR
4268 	        && currentHeader != &AS_WHILE
4269 	        && currentHeader != &AS_DO
4270 	        && currentHeader != &AS_FOREACH)
4271 		return false;
4272 
4273 	// do not add if a header follows (i.e. else if)
4274 	if (isCharPotentialHeader(currentLine, charNum))
4275 		if (findHeader(headers) != NULL)
4276 			return false;
4277 
4278 	// find the next semi-colon
4279 	size_t nextSemiColon = findNextChar(currentLine, ';', charNum+1);
4280 	if (nextSemiColon == string::npos)
4281 		return false;
4282 
4283 	// add closing bracket before changing the line length
4284 	if (nextSemiColon == currentLine.length() - 1)
4285 		currentLine.append(" }");
4286 	else
4287 		currentLine.insert(nextSemiColon + 1, " }");
4288 	// add opening bracket
4289 	currentLine.insert(charNum, "{ ");
4290 	currentChar = '{';
4291 	// remove extra spaces
4292 	if (!shouldAddOneLineBrackets)
4293 	{
4294 		size_t lastText = formattedLine.find_last_not_of(" \t");
4295 		if ((formattedLine.length() - 1) - lastText > 1)
4296 			formattedLine.erase(lastText + 1);
4297 	}
4298 	return true;
4299 }
4300 
4301 /**
4302  * Find the next character that is not in quotes or a comment.
4303  *
4304  * @param line         the line to be searched.
4305  * @param searchChar   the char to find.
4306  * @param searchStart  the char to find.
4307  * @return the position on the line or string::npos if not found.
4308  */
findNextChar(string & line,char searchChar,int searchStart)4309 size_t ASFormatter::findNextChar(string& line, char searchChar, int searchStart /*0*/)
4310 {
4311 	// find the next searchChar
4312 	size_t i;
4313 	for (i = searchStart; i < line.length(); i++)
4314 	{
4315 		if (line.compare(i, 2, "//") == 0)
4316 			return string::npos;
4317 		if (line.compare(i, 2, "/*") == 0)
4318 		{
4319 			size_t endComment = line.find("*/", i+2);
4320 			if (endComment == string::npos)
4321 				return string::npos;
4322 			i = endComment + 2;
4323 		}
4324 		if (line[i] == '\'' || line[i] == '\"')
4325 		{
4326 			char quote = line[i];
4327 			while (i < line.length())
4328 			{
4329 				size_t endQuote = line.find(quote, i+1);
4330 				if (endQuote == string::npos)
4331 					return string::npos;
4332 				i = endQuote;
4333 				if (line[endQuote-1] != '\\')	// check for '\"'
4334 					break;
4335 				if (line[endQuote-2] == '\\')	// check for '\\'
4336 					break;
4337 			}
4338 		}
4339 
4340 		if (line[i] == searchChar)
4341 			break;
4342 
4343 		// for now don't process C# 'delegate' brackets
4344 		// do this last in case the search char is a '{'
4345 		if (line[i] == '{')
4346 			return string::npos;
4347 	}
4348 	if (i >= line.length())	// didn't find searchChar
4349 		return string::npos;
4350 
4351 	return i;
4352 }
4353 
4354 /**
4355  * Look ahead in the file to see if a struct has access modifiers.
4356  *
4357  * @param line          a reference to the line to indent.
4358  * @param index         the current line index.
4359  * @return              true if the struct has access modifiers.
4360  */
isStructAccessModified(string & firstLine,size_t index) const4361 bool ASFormatter::isStructAccessModified(string  &firstLine, size_t index) const
4362 {
4363 	assert(firstLine[index] == '{');
4364 	assert(isCStyle());
4365 
4366 	bool isFirstLine = true;
4367 	bool needReset = false;
4368 	size_t bracketCount = 1;
4369 	string nextLine = firstLine.substr(index + 1);
4370 
4371 	// find the first non-blank text, bypassing all comments.
4372 	bool isInComment = false;
4373 	while (sourceIterator->hasMoreLines())
4374 	{
4375 		if (isFirstLine)
4376 			isFirstLine = false;
4377 		else
4378 		{
4379 			nextLine = sourceIterator->peekNextLine();
4380 			needReset = true;
4381 		}
4382 		// parse the line
4383 		for (size_t i = 0; i < nextLine.length(); i++)
4384 		{
4385 			if (isWhiteSpace(nextLine[i]))
4386 				continue;
4387 			if (nextLine.compare(i, 2, "/*") == 0)
4388 				isInComment = true;
4389 			if (isInComment)
4390 			{
4391 				i = nextLine.find("*/", i);
4392 				if (i == string::npos)
4393 				{
4394 					i = nextLine.length();
4395 					continue;
4396 				}
4397 				i++;
4398 				isInComment = false;
4399 				continue;
4400 			}
4401 			if (nextLine.compare(i, 2, "//") == 0)
4402 			{
4403 				i = nextLine.length();
4404 				continue;
4405 			}
4406 			// handle brackets
4407 			if (nextLine[i] == '{')
4408 				bracketCount++;
4409 			if (nextLine[i] == '}')
4410 				bracketCount--;
4411 			if (bracketCount == 0)
4412 			{
4413 				if (needReset)
4414 					sourceIterator->peekReset();
4415 				return false;
4416 			}
4417 			// check for access modifiers
4418 			if (isCharPotentialHeader(nextLine, i))
4419 			{
4420 				if (findKeyword(nextLine, i, AS_PUBLIC)
4421 				        || findKeyword(nextLine, i, AS_PRIVATE)
4422 				        || findKeyword(nextLine, i, AS_PROTECTED))
4423 				{
4424 					if (needReset)
4425 						sourceIterator->peekReset();
4426 					return true;
4427 				}
4428 				string name = getCurrentWord(nextLine, i);
4429 				i += name.length() - 1;
4430 			}
4431 		}	// end of for loop
4432 	}	// end of while loop
4433 
4434 	if (needReset)
4435 		sourceIterator->peekReset();
4436 	return false;
4437 }
4438 
4439 /**
4440  * Check to see if this is an EXEC SQL statement.
4441  *
4442  * @param line          a reference to the line to indent.
4443  * @param index         the current line index.
4444  * @return              true if the statement is EXEC SQL.
4445  */
isExecSQL(string & line,size_t index) const4446 bool ASFormatter::isExecSQL(string  &line, size_t index) const
4447 {
4448 	if (line[index] != 'e' && line[index] != 'E')	// quick check to reject most
4449 		return false;
4450 	string word;
4451 	if (isCharPotentialHeader(line, index))
4452 		word = getCurrentWord(line, index);
4453 	for (size_t i = 0; i < word.length(); i++)
4454 		word[i] = (char) toupper(word[i]);
4455 	if (word != "EXEC")
4456 		return false;
4457 	size_t index2 = index + word.length();
4458 	index2 = line.find_first_not_of(" \t", index2);
4459 	if (index2 == string::npos)
4460 		return false;
4461 	word.erase();
4462 	if (isCharPotentialHeader(line, index2))
4463 		word = getCurrentWord(line, index2);
4464 	for (size_t i = 0; i < word.length(); i++)
4465 		word[i] = (char) toupper(word[i]);
4466 	if (word != "SQL")
4467 		return false;
4468 	return true;
4469 }
4470 
4471 /**
4472  * The continuation lines must be adjusted so the leading spaces
4473  *     is equivalent to the text on the opening line.
4474  *
4475  * Updates currentLine and charNum.
4476  */
trimContinuationLine()4477 void ASFormatter::trimContinuationLine()
4478 {
4479 	size_t len = currentLine.length();
4480 	size_t indent = getIndentLength();
4481 	charNum = 0;
4482 
4483 	if (leadingSpaces > 0 && len > 0)
4484 	{
4485 		size_t i;
4486 		size_t continuationIncrementIn = 0;
4487 		for (i = 0; (i < len) && (i + continuationIncrementIn < leadingSpaces); i++)
4488 		{
4489 			if (!isWhiteSpace(currentLine[i]))		// don't delete any text
4490 			{
4491 				i = 0;
4492 				continuationIncrementIn = tabIncrementIn;
4493 				break;
4494 			}
4495 			if (currentLine[i] == '\t')
4496 				continuationIncrementIn += indent - 1 - ((continuationIncrementIn + i) % indent);
4497 		}
4498 
4499 		if ((int) continuationIncrementIn == tabIncrementIn)
4500 			charNum = i;
4501 		else
4502 		{
4503 			// build a new line with the equivalent leading chars
4504 			string newLine;
4505 			int leadingChars = 0;
4506 			if ((int) leadingSpaces > tabIncrementIn)
4507 				leadingChars = leadingSpaces - tabIncrementIn;
4508 			newLine.append(leadingChars, ' ');
4509 			newLine.append(currentLine, i, len-i);
4510 			currentLine = newLine;
4511 			charNum = leadingChars;
4512 		}
4513 		if (i >= len)
4514 			charNum = 0;
4515 	}
4516 	return;
4517 }
4518 
4519 
4520 }   // end namespace astyle
4521