openjp2/j2k: Report error if all wanted components are not decoded.
[openjpeg.git] / thirdparty / astyle / ASFormatter.cpp
1 // ASFormatter.cpp
2 // Copyright (c) 2017 by Jim Pattee <jimp03@email.com>.
3 // This code is licensed under the MIT License.
4 // License.md describes the conditions under which this software may be distributed.
5
6 //-----------------------------------------------------------------------------
7 // headers
8 //-----------------------------------------------------------------------------
9
10 #include "astyle.h"
11
12 #include <algorithm>
13 #include <fstream>
14
15 //-----------------------------------------------------------------------------
16 // astyle namespace
17 //-----------------------------------------------------------------------------
18
19 namespace astyle {
20 //
21 //-----------------------------------------------------------------------------
22 // ASFormatter class
23 //-----------------------------------------------------------------------------
24
25 /**
26  * Constructor of ASFormatter
27  */
28 ASFormatter::ASFormatter()
29 {
30         sourceIterator = nullptr;
31         enhancer = new ASEnhancer;
32         preBraceHeaderStack = nullptr;
33         braceTypeStack = nullptr;
34         parenStack = nullptr;
35         structStack = nullptr;
36         questionMarkStack = nullptr;
37         lineCommentNoIndent = false;
38         formattingStyle = STYLE_NONE;
39         braceFormatMode = NONE_MODE;
40         pointerAlignment = PTR_ALIGN_NONE;
41         referenceAlignment = REF_SAME_AS_PTR;
42         objCColonPadMode = COLON_PAD_NO_CHANGE;
43         lineEnd = LINEEND_DEFAULT;
44         maxCodeLength = string::npos;
45         shouldPadCommas = false;
46         shouldPadOperators = false;
47         shouldPadParensOutside = false;
48         shouldPadFirstParen = false;
49         shouldPadParensInside = false;
50         shouldPadHeader = false;
51         shouldStripCommentPrefix = false;
52         shouldUnPadParens = false;
53         attachClosingBraceMode = false;
54         shouldBreakOneLineBlocks = true;
55         shouldBreakOneLineHeaders = false;
56         shouldBreakOneLineStatements = true;
57         shouldConvertTabs = false;
58         shouldIndentCol1Comments = false;
59         shouldIndentPreprocBlock = false;
60         shouldCloseTemplates = false;
61         shouldAttachExternC = false;
62         shouldAttachNamespace = false;
63         shouldAttachClass = false;
64         shouldAttachClosingWhile = false;
65         shouldAttachInline = false;
66         shouldBreakBlocks = false;
67         shouldBreakClosingHeaderBlocks = false;
68         shouldBreakClosingHeaderBraces = false;
69         shouldDeleteEmptyLines = false;
70         shouldBreakElseIfs = false;
71         shouldBreakLineAfterLogical = false;
72         shouldAddBraces = false;
73         shouldAddOneLineBraces = false;
74         shouldRemoveBraces = false;
75         shouldPadMethodColon = false;
76         shouldPadMethodPrefix = false;
77         shouldUnPadMethodPrefix = false;
78         shouldPadReturnType = false;
79         shouldUnPadReturnType = false;
80         shouldPadParamType = false;
81         shouldUnPadParamType = false;
82
83         // initialize ASFormatter member vectors
84         formatterFileType = 9;          // reset to an invalid type
85         headers = new vector<const string*>;
86         nonParenHeaders = new vector<const string*>;
87         preDefinitionHeaders = new vector<const string*>;
88         preCommandHeaders = new vector<const string*>;
89         operators = new vector<const string*>;
90         assignmentOperators = new vector<const string*>;
91         castOperators = new vector<const string*>;
92
93         // initialize ASEnhancer member vectors
94         indentableMacros = new vector<const pair<const string, const string>* >;
95 }
96
97 /**
98  * Destructor of ASFormatter
99  */
100 ASFormatter::~ASFormatter()
101 {
102         // delete ASFormatter stack vectors
103         deleteContainer(preBraceHeaderStack);
104         deleteContainer(braceTypeStack);
105         deleteContainer(parenStack);
106         deleteContainer(structStack);
107         deleteContainer(questionMarkStack);
108
109         // delete ASFormatter member vectors
110         formatterFileType = 9;          // reset to an invalid type
111         delete headers;
112         delete nonParenHeaders;
113         delete preDefinitionHeaders;
114         delete preCommandHeaders;
115         delete operators;
116         delete assignmentOperators;
117         delete castOperators;
118
119         // delete ASEnhancer member vectors
120         delete indentableMacros;
121
122         // must be done when the ASFormatter object is deleted (not ASBeautifier)
123         // delete ASBeautifier member vectors
124         ASBeautifier::deleteBeautifierVectors();
125
126         delete enhancer;
127 }
128
129 /**
130  * initialize the ASFormatter.
131  *
132  * init() should be called every time a ASFormatter object is to start
133  * formatting a NEW source file.
134  * init() receives a pointer to a ASSourceIterator object that will be
135  * used to iterate through the source code.
136  *
137  * @param si        a pointer to the ASSourceIterator or ASStreamIterator object.
138  */
139 void ASFormatter::init(ASSourceIterator* si)
140 {
141         buildLanguageVectors();
142         fixOptionVariableConflicts();
143         ASBeautifier::init(si);
144         sourceIterator = si;
145
146         enhancer->init(getFileType(),
147                        getIndentLength(),
148                        getTabLength(),
149                        getIndentString() == "\t",
150                        getForceTabIndentation(),
151                        getNamespaceIndent(),
152                        getCaseIndent(),
153                        shouldIndentPreprocBlock,
154                        getPreprocDefineIndent(),
155                        getEmptyLineFill(),
156                        indentableMacros);
157
158         initContainer(preBraceHeaderStack, new vector<const string*>);
159         initContainer(parenStack, new vector<int>);
160         initContainer(structStack, new vector<bool>);
161         initContainer(questionMarkStack, new vector<bool>);
162         parenStack->emplace_back(0);               // parenStack must contain this default entry
163         initContainer(braceTypeStack, new vector<BraceType>);
164         braceTypeStack->emplace_back(NULL_TYPE);   // braceTypeStack must contain this default entry
165         clearFormattedLineSplitPoints();
166
167         currentHeader = nullptr;
168         currentLine = "";
169         readyFormattedLine = "";
170         formattedLine = "";
171         verbatimDelimiter = "";
172         currentChar = ' ';
173         previousChar = ' ';
174         previousCommandChar = ' ';
175         previousNonWSChar = ' ';
176         quoteChar = '"';
177         preprocBlockEnd = 0;
178         charNum = 0;
179         checksumIn = 0;
180         checksumOut = 0;
181         currentLineFirstBraceNum = string::npos;
182         formattedLineCommentNum = 0;
183         leadingSpaces = 0;
184         previousReadyFormattedLineLength = string::npos;
185         preprocBraceTypeStackSize = 0;
186         spacePadNum = 0;
187         nextLineSpacePadNum = 0;
188         objCColonAlign = 0;
189         templateDepth = 0;
190         squareBracketCount = 0;
191         runInIndentChars = 0;
192         tabIncrementIn = 0;
193         previousBraceType = NULL_TYPE;
194
195         isVirgin = true;
196         isInVirginLine = true;
197         isInLineComment = false;
198         isInComment = false;
199         isInCommentStartLine = false;
200         noTrimCommentContinuation = false;
201         isInPreprocessor = false;
202         isInPreprocessorBeautify = false;
203         doesLineStartComment = false;
204         lineEndsInCommentOnly = false;
205         lineIsCommentOnly = false;
206         lineIsLineCommentOnly = false;
207         lineIsEmpty = false;
208         isImmediatelyPostCommentOnly = false;
209         isImmediatelyPostEmptyLine = false;
210         isInClassInitializer = false;
211         isInQuote = false;
212         isInVerbatimQuote = false;
213         haveLineContinuationChar = false;
214         isInQuoteContinuation = false;
215         isHeaderInMultiStatementLine = false;
216         isSpecialChar = false;
217         isNonParenHeader = false;
218         foundNamespaceHeader = false;
219         foundClassHeader = false;
220         foundStructHeader = false;
221         foundInterfaceHeader = false;
222         foundPreDefinitionHeader = false;
223         foundPreCommandHeader = false;
224         foundPreCommandMacro = false;
225         foundTrailingReturnType = false;
226         foundCastOperator = false;
227         foundQuestionMark = false;
228         isInLineBreak = false;
229         endOfAsmReached = false;
230         endOfCodeReached = false;
231         isFormattingModeOff = false;
232         isInEnum = false;
233         isInExecSQL = false;
234         isInAsm = false;
235         isInAsmOneLine = false;
236         isInAsmBlock = false;
237         isLineReady = false;
238         elseHeaderFollowsComments = false;
239         caseHeaderFollowsComments = false;
240         isPreviousBraceBlockRelated = false;
241         isInPotentialCalculation = false;
242         needHeaderOpeningBrace = false;
243         shouldBreakLineAtNextChar = false;
244         shouldKeepLineUnbroken = false;
245         shouldReparseCurrentChar = false;
246         passedSemicolon = false;
247         passedColon = false;
248         isImmediatelyPostNonInStmt = false;
249         isCharImmediatelyPostNonInStmt = false;
250         isInTemplate = false;
251         isImmediatelyPostComment = false;
252         isImmediatelyPostLineComment = false;
253         isImmediatelyPostEmptyBlock = false;
254         isImmediatelyPostObjCMethodPrefix = false;
255         isImmediatelyPostPreprocessor = false;
256         isImmediatelyPostReturn = false;
257         isImmediatelyPostThrow = false;
258         isImmediatelyPostNewDelete = false;
259         isImmediatelyPostOperator = false;
260         isImmediatelyPostTemplate = false;
261         isImmediatelyPostPointerOrReference = false;
262         isCharImmediatelyPostReturn = false;
263         isCharImmediatelyPostThrow = false;
264         isCharImmediatelyPostNewDelete = false;
265         isCharImmediatelyPostOperator = false;
266         isCharImmediatelyPostComment = false;
267         isPreviousCharPostComment = false;
268         isCharImmediatelyPostLineComment = false;
269         isCharImmediatelyPostOpenBlock = false;
270         isCharImmediatelyPostCloseBlock = false;
271         isCharImmediatelyPostTemplate = false;
272         isCharImmediatelyPostPointerOrReference = false;
273         isInObjCInterface = false;
274         isInObjCMethodDefinition = false;
275         isInObjCReturnType = false;
276         isInObjCSelector = false;
277         breakCurrentOneLineBlock = false;
278         shouldRemoveNextClosingBrace = false;
279         isInBraceRunIn = false;
280         currentLineBeginsWithBrace = false;
281         isPrependPostBlockEmptyLineRequested = false;
282         isAppendPostBlockEmptyLineRequested = false;
283         isIndentableProprocessor = false;
284         isIndentableProprocessorBlock = false;
285         prependEmptyLine = false;
286         appendOpeningBrace = false;
287         foundClosingHeader = false;
288         isImmediatelyPostHeader = false;
289         isInHeader = false;
290         isInCase = false;
291         isFirstPreprocConditional = false;
292         processedFirstConditional = false;
293         isJavaStaticConstructor = false;
294 }
295
296 /**
297  * build vectors for each programing language
298  * depending on the file extension.
299  */
300 void ASFormatter::buildLanguageVectors()
301 {
302         if (getFileType() == formatterFileType)  // don't build unless necessary
303                 return;
304
305         formatterFileType = getFileType();
306
307         headers->clear();
308         nonParenHeaders->clear();
309         preDefinitionHeaders->clear();
310         preCommandHeaders->clear();
311         operators->clear();
312         assignmentOperators->clear();
313         castOperators->clear();
314         indentableMacros->clear();      // ASEnhancer
315
316         ASResource::buildHeaders(headers, getFileType());
317         ASResource::buildNonParenHeaders(nonParenHeaders, getFileType());
318         ASResource::buildPreDefinitionHeaders(preDefinitionHeaders, getFileType());
319         ASResource::buildPreCommandHeaders(preCommandHeaders, getFileType());
320         ASResource::buildOperators(operators, getFileType());
321         ASResource::buildAssignmentOperators(assignmentOperators);
322         ASResource::buildCastOperators(castOperators);
323         ASResource::buildIndentableMacros(indentableMacros);    //ASEnhancer
324 }
325
326 /**
327  * set the variables for each predefined style.
328  * this will override any previous settings.
329  */
330 void ASFormatter::fixOptionVariableConflicts()
331 {
332         if (formattingStyle == STYLE_ALLMAN)
333         {
334                 setBraceFormatMode(BREAK_MODE);
335         }
336         else if (formattingStyle == STYLE_JAVA)
337         {
338                 setBraceFormatMode(ATTACH_MODE);
339         }
340         else if (formattingStyle == STYLE_KR)
341         {
342                 setBraceFormatMode(LINUX_MODE);
343         }
344         else if (formattingStyle == STYLE_STROUSTRUP)
345         {
346                 setBraceFormatMode(LINUX_MODE);
347                 setBreakClosingHeaderBracesMode(true);
348         }
349         else if (formattingStyle == STYLE_WHITESMITH)
350         {
351                 setBraceFormatMode(BREAK_MODE);
352                 setBraceIndent(true);
353                 setClassIndent(true);                   // avoid hanging indent with access modifiers
354                 setSwitchIndent(true);                  // avoid hanging indent with case statements
355         }
356         else if (formattingStyle == STYLE_VTK)
357         {
358                 // the unindented class brace does NOT cause a hanging indent like Whitesmith
359                 setBraceFormatMode(BREAK_MODE);
360                 setBraceIndentVtk(true);                // sets both braceIndent and braceIndentVtk
361                 setSwitchIndent(true);                  // avoid hanging indent with case statements
362         }
363         else if (formattingStyle == STYLE_BANNER)
364         {
365                 // attached braces can have hanging indents with the closing brace
366                 setBraceFormatMode(ATTACH_MODE);
367                 setBraceIndent(true);
368                 setClassIndent(true);                   // avoid hanging indent with access modifiers
369                 setSwitchIndent(true);                  // avoid hanging indent with case statements
370         }
371         else if (formattingStyle == STYLE_GNU)
372         {
373                 setBraceFormatMode(BREAK_MODE);
374                 setBlockIndent(true);
375         }
376         else if (formattingStyle == STYLE_LINUX)
377         {
378                 setBraceFormatMode(LINUX_MODE);
379                 // always for Linux style
380                 setMinConditionalIndentOption(MINCOND_ONEHALF);
381         }
382         else if (formattingStyle == STYLE_HORSTMANN)
383         {
384                 setBraceFormatMode(RUN_IN_MODE);
385                 setSwitchIndent(true);
386         }
387         else if (formattingStyle == STYLE_1TBS)
388         {
389                 setBraceFormatMode(LINUX_MODE);
390                 setAddBracesMode(true);
391                 setRemoveBracesMode(false);
392         }
393         else if (formattingStyle == STYLE_GOOGLE)
394         {
395                 setBraceFormatMode(ATTACH_MODE);
396                 setModifierIndent(true);
397                 setClassIndent(false);
398         }
399         else if (formattingStyle == STYLE_MOZILLA)
400         {
401                 setBraceFormatMode(LINUX_MODE);
402         }
403         else if (formattingStyle == STYLE_PICO)
404         {
405                 setBraceFormatMode(RUN_IN_MODE);
406                 setAttachClosingBraceMode(true);
407                 setSwitchIndent(true);
408                 setBreakOneLineBlocksMode(false);
409                 setBreakOneLineStatementsMode(false);
410                 // add-braces won't work for pico, but it could be fixed if necessary
411                 // both options should be set to true
412                 if (shouldAddBraces)
413                         shouldAddOneLineBraces = true;
414         }
415         else if (formattingStyle == STYLE_LISP)
416         {
417                 setBraceFormatMode(ATTACH_MODE);
418                 setAttachClosingBraceMode(true);
419                 setBreakOneLineStatementsMode(false);
420                 // add-one-line-braces won't work for lisp
421                 // only shouldAddBraces should be set to true
422                 if (shouldAddOneLineBraces)
423                 {
424                         shouldAddBraces = true;
425                         shouldAddOneLineBraces = false;
426                 }
427         }
428         setMinConditionalIndentLength();
429         // if not set by indent=force-tab-x set equal to indentLength
430         if (getTabLength() == 0)
431                 setDefaultTabLength();
432         // add-one-line-braces implies keep-one-line-blocks
433         if (shouldAddOneLineBraces)
434                 setBreakOneLineBlocksMode(false);
435         // don't allow add-braces and remove-braces
436         if (shouldAddBraces || shouldAddOneLineBraces)
437                 setRemoveBracesMode(false);
438         // don't allow indent-classes and indent-modifiers
439         if (getClassIndent())
440                 setModifierIndent(false);
441 }
442
443 /**
444  * get the next formatted line.
445  *
446  * @return    formatted line.
447  */
448 string ASFormatter::nextLine()
449 {
450         const string* newHeader = nullptr;
451         isInVirginLine = isVirgin;
452         isCharImmediatelyPostComment = false;
453         isPreviousCharPostComment = false;
454         isCharImmediatelyPostLineComment = false;
455         isCharImmediatelyPostOpenBlock = false;
456         isCharImmediatelyPostCloseBlock = false;
457         isCharImmediatelyPostTemplate = false;
458
459         while (!isLineReady)
460         {
461                 if (shouldReparseCurrentChar)
462                         shouldReparseCurrentChar = false;
463                 else if (!getNextChar())
464                 {
465                         breakLine();
466                         continue;
467                 }
468                 else // stuff to do when reading a new character...
469                 {
470                         // make sure that a virgin '{' at the beginning of the file will be treated as a block...
471                         if (isInVirginLine && currentChar == '{'
472                                 && currentLineBeginsWithBrace
473                                 && previousCommandChar == ' ')
474                                 previousCommandChar = '{';
475                         if (isInClassInitializer
476                                 && isBraceType(braceTypeStack->back(), COMMAND_TYPE))
477                                 isInClassInitializer = false;
478                         if (isInBraceRunIn)
479                                 isInLineBreak = false;
480                         if (!isWhiteSpace(currentChar))
481                                 isInBraceRunIn = false;
482                         isPreviousCharPostComment = isCharImmediatelyPostComment;
483                         isCharImmediatelyPostComment = false;
484                         isCharImmediatelyPostTemplate = false;
485                         isCharImmediatelyPostReturn = false;
486                         isCharImmediatelyPostThrow = false;
487                         isCharImmediatelyPostNewDelete = false;
488                         isCharImmediatelyPostOperator = false;
489                         isCharImmediatelyPostPointerOrReference = false;
490                         isCharImmediatelyPostOpenBlock = false;
491                         isCharImmediatelyPostCloseBlock = false;
492                 }
493
494                 if ((lineIsLineCommentOnly || lineIsCommentOnly)
495                         && currentLine.find("*INDENT-ON*", charNum) != string::npos
496                         && isFormattingModeOff)
497                 {
498                         isFormattingModeOff = false;
499                         breakLine();
500                         formattedLine = currentLine;
501                         charNum = (int) currentLine.length() - 1;
502                         continue;
503                 }
504                 if (isFormattingModeOff)
505                 {
506                         breakLine();
507                         formattedLine = currentLine;
508                         charNum = (int) currentLine.length() - 1;
509                         continue;
510                 }
511                 if ((lineIsLineCommentOnly || lineIsCommentOnly)
512                         && currentLine.find("*INDENT-OFF*", charNum) != string::npos)
513                 {
514                         isFormattingModeOff = true;
515                         if (isInLineBreak)                      // is true if not the first line
516                                 breakLine();
517                         formattedLine = currentLine;
518                         charNum = (int)currentLine.length() - 1;
519                         continue;
520                 }
521
522                 if (shouldBreakLineAtNextChar)
523                 {
524                         if (isWhiteSpace(currentChar) && !lineIsEmpty)
525                                 continue;
526                         isInLineBreak = true;
527                         shouldBreakLineAtNextChar = false;
528                 }
529
530                 if (isInExecSQL && !passedSemicolon)
531                 {
532                         if (currentChar == ';')
533                                 passedSemicolon = true;
534                         appendCurrentChar();
535                         continue;
536                 }
537
538                 if (isInLineComment)
539                 {
540                         formatLineCommentBody();
541                         continue;
542                 }
543                 else if (isInComment)
544                 {
545                         formatCommentBody();
546                         continue;
547                 }
548
549                 else if (isInQuote)
550                 {
551                         formatQuoteBody();
552                         continue;
553                 }
554
555                 // not in quote or comment or line comment
556
557                 if (isSequenceReached("//"))
558                 {
559                         formatLineCommentOpener();
560                         testForTimeToSplitFormattedLine();
561                         continue;
562                 }
563                 else if (isSequenceReached("/*"))
564                 {
565                         formatCommentOpener();
566                         testForTimeToSplitFormattedLine();
567                         continue;
568                 }
569                 else if (currentChar == '"'
570                          || (currentChar == '\'' && !isDigitSeparator(currentLine, charNum)))
571                 {
572                         formatQuoteOpener();
573                         testForTimeToSplitFormattedLine();
574                         continue;
575                 }
576                 // treat these preprocessor statements as a line comment
577                 else if (currentChar == '#'
578                          && currentLine.find_first_not_of(" \t") == (size_t) charNum)
579                 {
580                         string preproc = trim(currentLine.c_str() + charNum + 1);
581                         if (preproc.length() > 0
582                                 && isCharPotentialHeader(preproc, 0)
583                                 && (findKeyword(preproc, 0, "region")
584                                     || findKeyword(preproc, 0, "endregion")
585                                     || findKeyword(preproc, 0, "error")
586                                     || findKeyword(preproc, 0, "warning")
587                                     || findKeyword(preproc, 0, "line")))
588                         {
589                                 currentLine = rtrim(currentLine);       // trim the end only
590                                 // check for run-in
591                                 if (formattedLine.length() > 0 && formattedLine[0] == '{')
592                                 {
593                                         isInLineBreak = true;
594                                         isInBraceRunIn = false;
595                                 }
596                                 if (previousCommandChar == '}')
597                                         currentHeader = nullptr;
598                                 isInLineComment = true;
599                                 appendCurrentChar();
600                                 continue;
601                         }
602                 }
603
604                 if (isInPreprocessor)
605                 {
606                         appendCurrentChar();
607                         continue;
608                 }
609
610                 if (isInTemplate && shouldCloseTemplates)
611                 {
612                         if (previousNonWSChar == '>' && isWhiteSpace(currentChar) && peekNextChar() == '>')
613                                 continue;
614                 }
615
616                 if (shouldRemoveNextClosingBrace && currentChar == '}')
617                 {
618                         currentLine[charNum] = currentChar = ' ';
619                         shouldRemoveNextClosingBrace = false;
620                         assert(adjustChecksumIn(-'}'));
621                         if (isEmptyLine(currentLine))
622                                 continue;
623                 }
624
625                 // handle white space - needed to simplify the rest.
626                 if (isWhiteSpace(currentChar))
627                 {
628                         appendCurrentChar();
629                         continue;
630                 }
631
632                 /* not in MIDDLE of quote or comment or SQL or white-space of any type ... */
633
634                 // check if in preprocessor
635                 // ** isInPreprocessor will be automatically reset at the beginning
636                 //    of a new line in getnextChar()
637                 if (currentChar == '#')
638                 {
639                         isInPreprocessor = true;
640                         // check for run-in
641                         if (formattedLine.length() > 0 && formattedLine[0] == '{')
642                         {
643                                 isInLineBreak = true;
644                                 isInBraceRunIn = false;
645                         }
646                         processPreprocessor();
647                         // if top level it is potentially indentable
648                         if (shouldIndentPreprocBlock
649                                 && (isBraceType(braceTypeStack->back(), NULL_TYPE)
650                                     || isBraceType(braceTypeStack->back(), NAMESPACE_TYPE))
651                                 && !foundClassHeader
652                                 && !isInClassInitializer
653                                 && sourceIterator->tellg() > preprocBlockEnd)
654                         {
655                                 // indent the #if preprocessor blocks
656                                 string preproc = ASBeautifier::extractPreprocessorStatement(currentLine);
657                                 if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef
658                                 {
659                                         if (isImmediatelyPostPreprocessor)
660                                                 breakLine();
661                                         isIndentableProprocessorBlock = isIndentablePreprocessorBlock(currentLine, charNum);
662                                         isIndentableProprocessor = isIndentableProprocessorBlock;
663                                 }
664                         }
665                         if (isIndentableProprocessorBlock
666                                 && charNum < (int) currentLine.length() - 1
667                                 && isWhiteSpace(currentLine[charNum + 1]))
668                         {
669                                 size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
670                                 if (nextText != string::npos)
671                                         currentLine.erase(charNum + 1, nextText - charNum - 1);
672                         }
673                         if (isIndentableProprocessorBlock
674                                 && sourceIterator->tellg() >= preprocBlockEnd)
675                                 isIndentableProprocessorBlock = false;
676                         //  need to fall thru here to reset the variables
677                 }
678
679                 /* not in preprocessor ... */
680
681                 if (isImmediatelyPostComment)
682                 {
683                         caseHeaderFollowsComments = false;
684                         isImmediatelyPostComment = false;
685                         isCharImmediatelyPostComment = true;
686                 }
687
688                 if (isImmediatelyPostLineComment)
689                 {
690                         caseHeaderFollowsComments = false;
691                         isImmediatelyPostLineComment = false;
692                         isCharImmediatelyPostLineComment = true;
693                 }
694
695                 if (isImmediatelyPostReturn)
696                 {
697                         isImmediatelyPostReturn = false;
698                         isCharImmediatelyPostReturn = true;
699                 }
700
701                 if (isImmediatelyPostThrow)
702                 {
703                         isImmediatelyPostThrow = false;
704                         isCharImmediatelyPostThrow = true;
705                 }
706
707                 if (isImmediatelyPostNewDelete)
708                 {
709                         isImmediatelyPostNewDelete = false;
710                         isCharImmediatelyPostNewDelete = true;
711                 }
712
713                 if (isImmediatelyPostOperator)
714                 {
715                         isImmediatelyPostOperator = false;
716                         isCharImmediatelyPostOperator = true;
717                 }
718                 if (isImmediatelyPostTemplate)
719                 {
720                         isImmediatelyPostTemplate = false;
721                         isCharImmediatelyPostTemplate = true;
722                 }
723                 if (isImmediatelyPostPointerOrReference)
724                 {
725                         isImmediatelyPostPointerOrReference = false;
726                         isCharImmediatelyPostPointerOrReference = true;
727                 }
728
729                 // reset isImmediatelyPostHeader information
730                 if (isImmediatelyPostHeader)
731                 {
732                         // should braces be added
733                         if (currentChar != '{'
734                                 && shouldAddBraces
735                                 && (shouldBreakOneLineStatements || !isHeaderInMultiStatementLine)
736                                 && isOkToBreakBlock(braceTypeStack->back()))
737                         {
738                                 bool bracesAdded = addBracesToStatement();
739                                 if (bracesAdded && !shouldAddOneLineBraces)
740                                 {
741                                         size_t firstText = currentLine.find_first_not_of(" \t");
742                                         assert(firstText != string::npos);
743                                         if ((int) firstText == charNum || shouldBreakOneLineHeaders)
744                                                 breakCurrentOneLineBlock = true;
745                                 }
746                         }
747                         // should braces be removed
748                         else if (currentChar == '{' && shouldRemoveBraces)
749                         {
750                                 bool bracesRemoved = removeBracesFromStatement();
751                                 if (bracesRemoved)
752                                 {
753                                         shouldRemoveNextClosingBrace = true;
754                                         if (isBeforeAnyLineEndComment(charNum))
755                                                 spacePadNum--;
756                                         else if (shouldBreakOneLineBlocks
757                                                  || (currentLineBeginsWithBrace
758                                                      && currentLine.find_first_not_of(" \t") != string::npos))
759                                                 shouldBreakLineAtNextChar = true;
760                                         continue;
761                                 }
762                         }
763
764                         // break 'else-if' if shouldBreakElseIfs is requested
765                         if (shouldBreakElseIfs
766                                 && currentHeader == &AS_ELSE
767                                 && isOkToBreakBlock(braceTypeStack->back())
768                                 && !isBeforeAnyComment()
769                                 && (shouldBreakOneLineStatements || !isHeaderInMultiStatementLine))
770                         {
771                                 string nextText = peekNextText(currentLine.substr(charNum));
772                                 if (nextText.length() > 0
773                                         && isCharPotentialHeader(nextText, 0)
774                                         && ASBase::findHeader(nextText, 0, headers) == &AS_IF)
775                                 {
776                                         isInLineBreak = true;
777                                 }
778                         }
779
780                         // break a header (e.g. if, while, else) from the following statement
781                         if (shouldBreakOneLineHeaders
782                                 && peekNextChar() != ' '
783                                 && (shouldBreakOneLineStatements
784                                     || (!isHeaderInMultiStatementLine
785                                         && !isMultiStatementLine()))
786                                 && isOkToBreakBlock(braceTypeStack->back())
787                                 && !isBeforeAnyComment())
788                         {
789                                 if (currentChar == '{')
790                                 {
791                                         if (!currentLineBeginsWithBrace)
792                                         {
793                                                 if (isOneLineBlockReached(currentLine, charNum) == 3)
794                                                         isInLineBreak = false;
795                                                 else
796                                                         breakCurrentOneLineBlock = true;
797                                         }
798                                 }
799                                 else if (currentHeader == &AS_ELSE)
800                                 {
801                                         string nextText = peekNextText(currentLine.substr(charNum), true);
802                                         if (nextText.length() > 0
803                                                 && ((isCharPotentialHeader(nextText, 0)
804                                                      && ASBase::findHeader(nextText, 0, headers) != &AS_IF)
805                                                     || nextText[0] == '{'))
806                                                 isInLineBreak = true;
807                                 }
808                                 else
809                                 {
810                                         isInLineBreak = true;
811                                 }
812                         }
813
814                         isImmediatelyPostHeader = false;
815                 }
816
817                 if (passedSemicolon)    // need to break the formattedLine
818                 {
819                         passedSemicolon = false;
820                         if (parenStack->back() == 0 && !isCharImmediatelyPostComment && currentChar != ';') // allow ;;
821                         {
822                                 // does a one-line block have ending comments?
823                                 if (isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE))
824                                 {
825                                         size_t blockEnd = currentLine.rfind(AS_CLOSE_BRACE);
826                                         assert(blockEnd != string::npos);
827                                         // move ending comments to this formattedLine
828                                         if (isBeforeAnyLineEndComment(blockEnd))
829                                         {
830                                                 size_t commentStart = currentLine.find_first_not_of(" \t", blockEnd + 1);
831                                                 assert(commentStart != string::npos);
832                                                 assert((currentLine.compare(commentStart, 2, "//") == 0)
833                                                        || (currentLine.compare(commentStart, 2, "/*") == 0));
834                                                 formattedLine.append(getIndentLength() - 1, ' ');
835                                                 // append comment
836                                                 int charNumSave = charNum;
837                                                 charNum = commentStart;
838                                                 while (charNum < (int) currentLine.length())
839                                                 {
840                                                         currentChar = currentLine[charNum];
841                                                         if (currentChar == '\t' && shouldConvertTabs)
842                                                                 convertTabToSpaces();
843                                                         formattedLine.append(1, currentChar);
844                                                         ++charNum;
845                                                 }
846                                                 size_t commentLength = currentLine.length() - commentStart;
847                                                 currentLine.erase(commentStart, commentLength);
848                                                 charNum = charNumSave;
849                                                 currentChar = currentLine[charNum];
850                                                 testForTimeToSplitFormattedLine();
851                                         }
852                                 }
853                                 isInExecSQL = false;
854                                 shouldReparseCurrentChar = true;
855                                 if (formattedLine.find_first_not_of(" \t") != string::npos)
856                                         isInLineBreak = true;
857                                 if (needHeaderOpeningBrace)
858                                 {
859                                         isCharImmediatelyPostCloseBlock = true;
860                                         needHeaderOpeningBrace = false;
861                                 }
862                                 continue;
863                         }
864                 }
865
866                 if (passedColon)
867                 {
868                         passedColon = false;
869                         if (parenStack->back() == 0
870                                 && !isBeforeAnyComment()
871                                 && (formattedLine.find_first_not_of(" \t") != string::npos))
872                         {
873                                 shouldReparseCurrentChar = true;
874                                 isInLineBreak = true;
875                                 continue;
876                         }
877                 }
878
879                 // Check if in template declaration, e.g. foo<bar> or foo<bar,fig>
880                 if (!isInTemplate && currentChar == '<')
881                 {
882                         checkIfTemplateOpener();
883                 }
884
885                 // handle parens
886                 if (currentChar == '(' || currentChar == '[' || (isInTemplate && currentChar == '<'))
887                 {
888                         questionMarkStack->push_back(foundQuestionMark);
889                         foundQuestionMark = false;
890                         parenStack->back()++;
891                         if (currentChar == '[')
892                         {
893                                 ++squareBracketCount;
894                                 if (getAlignMethodColon() && squareBracketCount == 1 && isCStyle())
895                                         objCColonAlign = findObjCColonAlignment();
896                         }
897                 }
898                 else if (currentChar == ')' || currentChar == ']' || (isInTemplate && currentChar == '>'))
899                 {
900                         foundPreCommandHeader = false;
901                         parenStack->back()--;
902                         // this can happen in preprocessor directives
903                         if (parenStack->back() < 0)
904                                 parenStack->back() = 0;
905                         if (!questionMarkStack->empty())
906                         {
907                                 foundQuestionMark = questionMarkStack->back();
908                                 questionMarkStack->pop_back();
909                         }
910                         if (isInTemplate && currentChar == '>')
911                         {
912                                 templateDepth--;
913                                 if (templateDepth == 0)
914                                 {
915                                         isInTemplate = false;
916                                         isImmediatelyPostTemplate = true;
917                                 }
918                         }
919
920                         // check if this parenthesis closes a header, e.g. if (...), while (...)
921                         if (isInHeader && parenStack->back() == 0)
922                         {
923                                 isInHeader = false;
924                                 isImmediatelyPostHeader = true;
925                                 foundQuestionMark = false;
926                         }
927                         if (currentChar == ']')
928                         {
929                                 --squareBracketCount;
930                                 if (squareBracketCount <= 0)
931                                 {
932                                         squareBracketCount = 0;
933                                         objCColonAlign = 0;
934                                 }
935                         }
936                         if (currentChar == ')')
937                         {
938                                 foundCastOperator = false;
939                                 if (parenStack->back() == 0)
940                                         endOfAsmReached = true;
941                         }
942                 }
943
944                 // handle braces
945                 if (currentChar == '{' || currentChar == '}')
946                 {
947                         // if appendOpeningBrace this was already done for the original brace
948                         if (currentChar == '{' && !appendOpeningBrace)
949                         {
950                                 BraceType newBraceType = getBraceType();
951                                 breakCurrentOneLineBlock = false;
952                                 foundNamespaceHeader = false;
953                                 foundClassHeader = false;
954                                 foundStructHeader = false;
955                                 foundInterfaceHeader = false;
956                                 foundPreDefinitionHeader = false;
957                                 foundPreCommandHeader = false;
958                                 foundPreCommandMacro = false;
959                                 foundTrailingReturnType = false;
960                                 isInPotentialCalculation = false;
961                                 isInObjCMethodDefinition = false;
962                                 isInObjCInterface = false;
963                                 isInEnum = false;
964                                 isJavaStaticConstructor = false;
965                                 isCharImmediatelyPostNonInStmt = false;
966                                 needHeaderOpeningBrace = false;
967                                 shouldKeepLineUnbroken = false;
968                                 objCColonAlign = 0;
969
970                                 isPreviousBraceBlockRelated = !isBraceType(newBraceType, ARRAY_TYPE);
971                                 braceTypeStack->emplace_back(newBraceType);
972                                 preBraceHeaderStack->emplace_back(currentHeader);
973                                 currentHeader = nullptr;
974                                 structStack->push_back(isInIndentableStruct);
975                                 if (isBraceType(newBraceType, STRUCT_TYPE) && isCStyle())
976                                         isInIndentableStruct = isStructAccessModified(currentLine, charNum);
977                                 else
978                                         isInIndentableStruct = false;
979                         }
980
981                         // this must be done before the braceTypeStack is popped
982                         BraceType braceType = braceTypeStack->back();
983                         bool isOpeningArrayBrace = (isBraceType(braceType, ARRAY_TYPE)
984                                                     && braceTypeStack->size() >= 2
985                                                     && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2], ARRAY_TYPE)
986                                                    );
987
988                         if (currentChar == '}')
989                         {
990                                 // if a request has been made to append a post block empty line,
991                                 // but the block exists immediately before a closing brace,
992                                 // then there is no need for the post block empty line.
993                                 isAppendPostBlockEmptyLineRequested = false;
994                                 if (isInAsm)
995                                         endOfAsmReached = true;
996                                 isInAsmOneLine = isInQuote = false;
997                                 shouldKeepLineUnbroken = false;
998                                 squareBracketCount = 0;
999
1000                                 if (braceTypeStack->size() > 1)
1001                                 {
1002                                         previousBraceType = braceTypeStack->back();
1003                                         braceTypeStack->pop_back();
1004                                         isPreviousBraceBlockRelated = !isBraceType(braceType, ARRAY_TYPE);
1005                                 }
1006                                 else
1007                                 {
1008                                         previousBraceType = NULL_TYPE;
1009                                         isPreviousBraceBlockRelated = false;
1010                                 }
1011
1012                                 if (!preBraceHeaderStack->empty())
1013                                 {
1014                                         currentHeader = preBraceHeaderStack->back();
1015                                         preBraceHeaderStack->pop_back();
1016                                 }
1017                                 else
1018                                         currentHeader = nullptr;
1019
1020                                 if (!structStack->empty())
1021                                 {
1022                                         isInIndentableStruct = structStack->back();
1023                                         structStack->pop_back();
1024                                 }
1025                                 else
1026                                         isInIndentableStruct = false;
1027
1028                                 if (isNonInStatementArray
1029                                         && (!isBraceType(braceTypeStack->back(), ARRAY_TYPE)    // check previous brace
1030                                             || peekNextChar() == ';'))                                                  // check for "};" added V2.01
1031                                         isImmediatelyPostNonInStmt = true;
1032
1033                                 if (!shouldBreakOneLineStatements
1034                                         && ASBeautifier::getNextWord(currentLine, charNum) == AS_ELSE)
1035                                 {
1036                                         // handle special case of "else" at the end of line
1037                                         size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
1038                                         if (ASBeautifier::peekNextChar(currentLine, nextText + 3) == ' ')
1039                                                 shouldBreakLineAtNextChar = true;
1040                                 }
1041                         }
1042
1043                         // format braces
1044                         appendOpeningBrace = false;
1045                         if (isBraceType(braceType, ARRAY_TYPE))
1046                         {
1047                                 formatArrayBraces(braceType, isOpeningArrayBrace);
1048                         }
1049                         else
1050                         {
1051                                 if (currentChar == '{')
1052                                         formatOpeningBrace(braceType);
1053                                 else
1054                                         formatClosingBrace(braceType);
1055                         }
1056                         continue;
1057                 }
1058
1059                 if ((((previousCommandChar == '{' && isPreviousBraceBlockRelated)
1060                         || ((previousCommandChar == '}'
1061                              && !isImmediatelyPostEmptyBlock
1062                              && isPreviousBraceBlockRelated
1063                              && !isPreviousCharPostComment       // Fixes wrongly appended newlines after '}' immediately after comments
1064                              && peekNextChar() != ' '
1065                              && !isBraceType(previousBraceType, DEFINITION_TYPE))
1066                             && !isBraceType(braceTypeStack->back(), DEFINITION_TYPE)))
1067                         && isOkToBreakBlock(braceTypeStack->back()))
1068                         // check for array
1069                         || (previousCommandChar == '{'                  // added 9/30/2010
1070                             && isBraceType(braceTypeStack->back(), ARRAY_TYPE)
1071                             && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
1072                             && isNonInStatementArray)
1073                         // check for pico one line braces
1074                         || (formattingStyle == STYLE_PICO
1075                             && (previousCommandChar == '{' && isPreviousBraceBlockRelated)
1076                             && isBraceType(braceTypeStack->back(), COMMAND_TYPE)
1077                             && isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
1078                             && braceFormatMode == RUN_IN_MODE)
1079                    )
1080                 {
1081                         isCharImmediatelyPostOpenBlock = (previousCommandChar == '{');
1082                         isCharImmediatelyPostCloseBlock = (previousCommandChar == '}');
1083
1084                         if (isCharImmediatelyPostOpenBlock
1085                                 && !isCharImmediatelyPostComment
1086                                 && !isCharImmediatelyPostLineComment)
1087                         {
1088                                 previousCommandChar = ' ';
1089
1090                                 if (braceFormatMode == NONE_MODE)
1091                                 {
1092                                         if (isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
1093                                                 && (isBraceType(braceTypeStack->back(), BREAK_BLOCK_TYPE)
1094                                                     || shouldBreakOneLineBlocks))
1095                                                 isInLineBreak = true;
1096                                         else if (currentLineBeginsWithBrace)
1097                                                 formatRunIn();
1098                                         else
1099                                                 breakLine();
1100                                 }
1101                                 else if (braceFormatMode == RUN_IN_MODE
1102                                          && currentChar != '#')
1103                                         formatRunIn();
1104                                 else
1105                                         isInLineBreak = true;
1106                         }
1107                         else if (isCharImmediatelyPostCloseBlock
1108                                  && shouldBreakOneLineStatements
1109                                  && !isCharImmediatelyPostComment
1110                                  && ((isLegalNameChar(currentChar) && currentChar != '.')
1111                                      || currentChar == '+'
1112                                      || currentChar == '-'
1113                                      || currentChar == '*'
1114                                      || currentChar == '&'
1115                                      || currentChar == '('))
1116                         {
1117                                 previousCommandChar = ' ';
1118                                 isInLineBreak = true;
1119                         }
1120                 }
1121
1122                 // reset block handling flags
1123                 isImmediatelyPostEmptyBlock = false;
1124
1125                 // look for headers
1126                 bool isPotentialHeader = isCharPotentialHeader(currentLine, charNum);
1127
1128                 if (isPotentialHeader && !isInTemplate && squareBracketCount == 0)
1129                 {
1130                         isNonParenHeader = false;
1131                         foundClosingHeader = false;
1132
1133                         newHeader = findHeader(headers);
1134
1135                         // Qt headers may be variables in C++
1136                         if (isCStyle()
1137                                 && (newHeader == &AS_FOREVER || newHeader == &AS_FOREACH))
1138                         {
1139                                 if (currentLine.find_first_of("=;", charNum) != string::npos)
1140                                         newHeader = nullptr;
1141                         }
1142                         if (isJavaStyle()
1143                                 && (newHeader == &AS_SYNCHRONIZED))
1144                         {
1145                                 // want synchronized statements not synchronized methods
1146                                 if (!isBraceType(braceTypeStack->back(), COMMAND_TYPE))
1147                                         newHeader = nullptr;
1148                         }
1149                         else if (newHeader == &AS_USING
1150                                  && ASBeautifier::peekNextChar(
1151                                      currentLine, charNum + (*newHeader).length() - 1) != '(')
1152                                 newHeader = nullptr;
1153
1154                         if (newHeader != nullptr)
1155                         {
1156                                 foundClosingHeader = isClosingHeader(newHeader);
1157
1158                                 if (!foundClosingHeader)
1159                                 {
1160                                         // these are closing headers
1161                                         if ((newHeader == &AS_WHILE && currentHeader == &AS_DO)
1162                                                 || (newHeader == &_AS_FINALLY && currentHeader == &_AS_TRY)
1163                                                 || (newHeader == &_AS_EXCEPT && currentHeader == &_AS_TRY))
1164                                                 foundClosingHeader = true;
1165                                         // don't append empty block for these related headers
1166                                         else if (isSharpStyle()
1167                                                  && previousNonWSChar == '}'
1168                                                  && ((newHeader == &AS_SET && currentHeader == &AS_GET)
1169                                                      || (newHeader == &AS_REMOVE && currentHeader == &AS_ADD))
1170                                                  && isOkToBreakBlock(braceTypeStack->back()))
1171                                                 isAppendPostBlockEmptyLineRequested = false;
1172                                 }
1173
1174                                 // TODO: this can be removed in a future release
1175                                 // version 3.0 - break erroneous attached header from previous versions
1176                                 if (isSharpStyle()
1177                                         && ((newHeader == &AS_SET && currentHeader == &AS_GET)
1178                                             || (newHeader == &AS_REMOVE && currentHeader == &AS_ADD))
1179                                         && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
1180                                         && currentLine[currentLine.find_first_not_of(" \t")] == '}')
1181                                         isInLineBreak = true;
1182                                 // END TODO
1183
1184                                 const string* previousHeader = currentHeader;
1185                                 currentHeader = newHeader;
1186                                 needHeaderOpeningBrace = true;
1187
1188                                 // is the previous statement on the same line?
1189                                 if ((previousNonWSChar == ';' || previousNonWSChar == ':')
1190                                         && !isInLineBreak
1191                                         && isOkToBreakBlock(braceTypeStack->back()))
1192                                 {
1193                                         // if breaking lines, break the line at the header
1194                                         // except for multiple 'case' statements on a line
1195                                         if (maxCodeLength != string::npos
1196                                                 && previousHeader != &AS_CASE)
1197                                                 isInLineBreak = true;
1198                                         else
1199                                                 isHeaderInMultiStatementLine = true;
1200                                 }
1201
1202                                 if (foundClosingHeader && previousNonWSChar == '}')
1203                                 {
1204                                         if (isOkToBreakBlock(braceTypeStack->back()))
1205                                                 isLineBreakBeforeClosingHeader();
1206
1207                                         // get the adjustment for a comment following the closing header
1208                                         if (isInLineBreak)
1209                                                 nextLineSpacePadNum = getNextLineCommentAdjustment();
1210                                         else
1211                                                 spacePadNum = getCurrentLineCommentAdjustment();
1212                                 }
1213
1214                                 // check if the found header is non-paren header
1215                                 isNonParenHeader = findHeader(nonParenHeaders) != nullptr;
1216
1217                                 if (isNonParenHeader
1218                                         && (currentHeader == &AS_CATCH
1219                                             || currentHeader == &AS_CASE))
1220                                 {
1221                                         int startChar = charNum + currentHeader->length() - 1;
1222                                         if (ASBeautifier::peekNextChar(currentLine, startChar) == '(')
1223                                                 isNonParenHeader = false;
1224                                 }
1225
1226                                 // join 'else if' statements
1227                                 if (currentHeader == &AS_IF
1228                                         && previousHeader == &AS_ELSE
1229                                         && isInLineBreak
1230                                         && !shouldBreakElseIfs
1231                                         && !isCharImmediatelyPostLineComment
1232                                         && !isImmediatelyPostPreprocessor)
1233                                 {
1234                                         // 'else' must be last thing on the line
1235                                         size_t start = formattedLine.length() >= 6 ? formattedLine.length() - 6 : 0;
1236                                         if (formattedLine.find(AS_ELSE, start) != string::npos)
1237                                         {
1238                                                 appendSpacePad();
1239                                                 isInLineBreak = false;
1240                                         }
1241                                 }
1242
1243                                 appendSequence(*currentHeader);
1244                                 goForward(currentHeader->length() - 1);
1245                                 // if a paren-header is found add a space after it, if needed
1246                                 // this checks currentLine, appendSpacePad() checks formattedLine
1247                                 // in 'case' and C# 'catch' can be either a paren or non-paren header
1248                                 if (shouldPadHeader
1249                                         && !isNonParenHeader
1250                                         && charNum < (int) currentLine.length() - 1 && !isWhiteSpace(currentLine[charNum + 1]))
1251                                         appendSpacePad();
1252
1253                                 // Signal that a header has been reached
1254                                 // *** But treat a closing while() (as in do...while)
1255                                 //     as if it were NOT a header since a closing while()
1256                                 //     should never have a block after it!
1257                                 if (currentHeader != &AS_CASE && currentHeader != &AS_DEFAULT
1258                                         && !(foundClosingHeader && currentHeader == &AS_WHILE))
1259                                 {
1260                                         isInHeader = true;
1261
1262                                         // in C# 'catch' and 'delegate' can be a paren or non-paren header
1263                                         if (isNonParenHeader && !isSharpStyleWithParen(currentHeader))
1264                                         {
1265                                                 isImmediatelyPostHeader = true;
1266                                                 isInHeader = false;
1267                                         }
1268                                 }
1269
1270                                 if (shouldBreakBlocks
1271                                         && isOkToBreakBlock(braceTypeStack->back())
1272                                         && !isHeaderInMultiStatementLine)
1273                                 {
1274                                         if (previousHeader == nullptr
1275                                                 && !foundClosingHeader
1276                                                 && !isCharImmediatelyPostOpenBlock
1277                                                 && !isImmediatelyPostCommentOnly)
1278                                         {
1279                                                 isPrependPostBlockEmptyLineRequested = true;
1280                                         }
1281
1282                                         if (isClosingHeader(currentHeader)
1283                                                 || foundClosingHeader)
1284                                         {
1285                                                 isPrependPostBlockEmptyLineRequested = false;
1286                                         }
1287
1288                                         if (shouldBreakClosingHeaderBlocks
1289                                                 && isCharImmediatelyPostCloseBlock
1290                                                 && !isImmediatelyPostCommentOnly
1291                                                 && !(currentHeader == &AS_WHILE                 // do-while
1292                                                      && foundClosingHeader))
1293                                         {
1294                                                 isPrependPostBlockEmptyLineRequested = true;
1295                                         }
1296                                 }
1297
1298                                 if (currentHeader == &AS_CASE
1299                                         || currentHeader == &AS_DEFAULT)
1300                                         isInCase = true;
1301
1302                                 continue;
1303                         }
1304                         else if ((newHeader = findHeader(preDefinitionHeaders)) != nullptr
1305                                  && parenStack->back() == 0
1306                                  && !isInEnum)          // not C++11 enum class
1307                         {
1308                                 if (newHeader == &AS_NAMESPACE || newHeader == &AS_MODULE)
1309                                         foundNamespaceHeader = true;
1310                                 if (newHeader == &AS_CLASS)
1311                                         foundClassHeader = true;
1312                                 if (newHeader == &AS_STRUCT)
1313                                         foundStructHeader = true;
1314                                 if (newHeader == &AS_INTERFACE)
1315                                         foundInterfaceHeader = true;
1316                                 foundPreDefinitionHeader = true;
1317                                 appendSequence(*newHeader);
1318                                 goForward(newHeader->length() - 1);
1319
1320                                 continue;
1321                         }
1322                         else if ((newHeader = findHeader(preCommandHeaders)) != nullptr)
1323                         {
1324                                 // a 'const' variable is not a preCommandHeader
1325                                 if (previousNonWSChar == ')')
1326                                         foundPreCommandHeader = true;
1327                         }
1328                         else if ((newHeader = findHeader(castOperators)) != nullptr)
1329                         {
1330                                 foundCastOperator = true;
1331                                 appendSequence(*newHeader);
1332                                 goForward(newHeader->length() - 1);
1333                                 continue;
1334                         }
1335                 }   // (isPotentialHeader && !isInTemplate)
1336
1337                 if (isInLineBreak)          // OK to break line here
1338                 {
1339                         breakLine();
1340                         if (isInVirginLine)             // adjust for the first line
1341                         {
1342                                 lineCommentNoBeautify = lineCommentNoIndent;
1343                                 lineCommentNoIndent = false;
1344                                 if (isImmediatelyPostPreprocessor)
1345                                 {
1346                                         isInIndentablePreproc = isIndentableProprocessor;
1347                                         isIndentableProprocessor = false;
1348                                 }
1349                         }
1350                 }
1351
1352                 if (previousNonWSChar == '}' || currentChar == ';')
1353                 {
1354                         if (currentChar == ';')
1355                         {
1356                                 squareBracketCount = 0;
1357
1358                                 if (((shouldBreakOneLineStatements
1359                                         || isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE))
1360                                         && isOkToBreakBlock(braceTypeStack->back()))
1361                                         && !(attachClosingBraceMode && peekNextChar() == '}'))
1362                                 {
1363                                         passedSemicolon = true;
1364                                 }
1365                                 else if (!shouldBreakOneLineStatements
1366                                          && ASBeautifier::getNextWord(currentLine, charNum) == AS_ELSE)
1367                                 {
1368                                         // handle special case of "else" at the end of line
1369                                         size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
1370                                         if (ASBeautifier::peekNextChar(currentLine, nextText + 3) == ' ')
1371                                                 passedSemicolon = true;
1372                                 }
1373
1374                                 if (shouldBreakBlocks
1375                                         && currentHeader != nullptr
1376                                         && currentHeader != &AS_CASE
1377                                         && currentHeader != &AS_DEFAULT
1378                                         && !isHeaderInMultiStatementLine
1379                                         && parenStack->back() == 0)
1380                                 {
1381                                         isAppendPostBlockEmptyLineRequested = true;
1382                                 }
1383                         }
1384                         if (currentChar != ';'
1385                                 || (needHeaderOpeningBrace && parenStack->back() == 0))
1386                                 currentHeader = nullptr;
1387                         resetEndOfStatement();
1388                 }
1389
1390                 if (currentChar == ':'
1391                         && previousChar != ':'         // not part of '::'
1392                         && peekNextChar() != ':')      // not part of '::'
1393                 {
1394                         if (isInCase)
1395                         {
1396                                 isInCase = false;
1397                                 if (shouldBreakOneLineStatements)
1398                                         passedColon = true;
1399                         }
1400                         else if (isCStyle()                     // for C/C++ only
1401                                  && isOkToBreakBlock(braceTypeStack->back())
1402                                  && shouldBreakOneLineStatements
1403                                  && !foundQuestionMark          // not in a ?: sequence
1404                                  && !foundPreDefinitionHeader   // not in a definition block
1405                                  && previousCommandChar != ')'  // not after closing paren of a method header
1406                                  && !foundPreCommandHeader      // not after a 'noexcept'
1407                                  && squareBracketCount == 0        // not in objC method call
1408                                  && !isInObjCMethodDefinition   // not objC '-' or '+' method
1409                                  && !isInObjCInterface          // not objC @interface
1410                                  && !isInObjCSelector           // not objC @selector
1411                                  && !isDigit(peekNextChar())    // not a bit field
1412                                  && !isInEnum                   // not an enum with a base type
1413                                  && !isInAsm                    // not in extended assembler
1414                                  && !isInAsmOneLine             // not in extended assembler
1415                                  && !isInAsmBlock)              // not in extended assembler
1416                         {
1417                                 passedColon = true;
1418                         }
1419
1420                         if (isCStyle()
1421                                 && shouldPadMethodColon
1422                                 && (squareBracketCount > 0 || isInObjCMethodDefinition || isInObjCSelector)
1423                                 && !foundQuestionMark)                  // not in a ?: sequence
1424                                 padObjCMethodColon();
1425
1426                         if (isInObjCInterface)
1427                         {
1428                                 appendSpacePad();
1429                                 if ((int) currentLine.length() > charNum + 1
1430                                         && !isWhiteSpace(currentLine[charNum + 1]))
1431                                         currentLine.insert(charNum + 1, " ");
1432                         }
1433
1434                         if (isClassInitializer())
1435                                 isInClassInitializer = true;
1436                 }
1437
1438                 if (currentChar == '?')
1439                         foundQuestionMark = true;
1440
1441                 if (isPotentialHeader && !isInTemplate)
1442                 {
1443                         if (findKeyword(currentLine, charNum, AS_NEW)
1444                                 || findKeyword(currentLine, charNum, AS_DELETE))
1445                         {
1446                                 isInPotentialCalculation = false;
1447                                 isImmediatelyPostNewDelete = true;
1448                         }
1449
1450                         if (findKeyword(currentLine, charNum, AS_RETURN))
1451                         {
1452                                 isInPotentialCalculation = true;        // return is the same as an = sign
1453                                 isImmediatelyPostReturn = true;
1454                         }
1455
1456                         if (findKeyword(currentLine, charNum, AS_OPERATOR))
1457                                 isImmediatelyPostOperator = true;
1458
1459                         if (findKeyword(currentLine, charNum, AS_ENUM))
1460                         {
1461                                 size_t firstNum = currentLine.find_first_of("(){},/");
1462                                 if (firstNum == string::npos
1463                                         || currentLine[firstNum] == '{'
1464                                         || currentLine[firstNum] == '/')
1465                                         isInEnum = true;
1466                         }
1467
1468                         if (isCStyle()
1469                                 && findKeyword(currentLine, charNum, AS_THROW)
1470                                 && previousCommandChar != ')'
1471                                 && !foundPreCommandHeader)      // 'const' throw()
1472                                 isImmediatelyPostThrow = true;
1473
1474                         if (isCStyle() && findKeyword(currentLine, charNum, AS_EXTERN) && isExternC())
1475                                 isInExternC = true;
1476
1477                         if (isCStyle() && findKeyword(currentLine, charNum, AS_AUTO)
1478                                 && (isBraceType(braceTypeStack->back(), NULL_TYPE)
1479                                     || isBraceType(braceTypeStack->back(), NAMESPACE_TYPE)
1480                                     || isBraceType(braceTypeStack->back(), CLASS_TYPE)))
1481                                 foundTrailingReturnType = true;
1482
1483                         // Objective-C NSException macros are preCommandHeaders
1484                         if (isCStyle() && findKeyword(currentLine, charNum, AS_NS_DURING))
1485                                 foundPreCommandMacro = true;
1486                         if (isCStyle() && findKeyword(currentLine, charNum, AS_NS_HANDLER))
1487                                 foundPreCommandMacro = true;
1488
1489                         if (isCStyle() && isExecSQL(currentLine, charNum))
1490                                 isInExecSQL = true;
1491
1492                         if (isCStyle())
1493                         {
1494                                 if (findKeyword(currentLine, charNum, AS_ASM)
1495                                         || findKeyword(currentLine, charNum, AS__ASM__))
1496                                 {
1497                                         isInAsm = true;
1498                                 }
1499                                 else if (findKeyword(currentLine, charNum, AS_MS_ASM)           // microsoft specific
1500                                          || findKeyword(currentLine, charNum, AS_MS__ASM))
1501                                 {
1502                                         int index = 4;
1503                                         if (peekNextChar() == '_')      // check for __asm
1504                                                 index = 5;
1505
1506                                         char peekedChar = ASBase::peekNextChar(currentLine, charNum + index);
1507                                         if (peekedChar == '{' || peekedChar == ' ')
1508                                                 isInAsmBlock = true;
1509                                         else
1510                                                 isInAsmOneLine = true;
1511                                 }
1512                         }
1513
1514                         if (isJavaStyle()
1515                                 && (findKeyword(currentLine, charNum, AS_STATIC)
1516                                     && isNextCharOpeningBrace(charNum + 6)))
1517                                 isJavaStaticConstructor = true;
1518
1519                         if (isSharpStyle()
1520                                 && (findKeyword(currentLine, charNum, AS_DELEGATE)
1521                                     || findKeyword(currentLine, charNum, AS_UNCHECKED)))
1522                                 isSharpDelegate = true;
1523
1524                         // append the entire name
1525                         string name = getCurrentWord(currentLine, charNum);
1526                         // must pad the 'and' and 'or' operators if required
1527                         if (name == "and" || name == "or")
1528                         {
1529                                 if (shouldPadOperators && previousNonWSChar != ':')
1530                                 {
1531                                         appendSpacePad();
1532                                         appendOperator(name);
1533                                         goForward(name.length() - 1);
1534                                         if (!isBeforeAnyComment()
1535                                                 && !(currentLine.compare(charNum + 1, 1, AS_SEMICOLON) == 0)
1536                                                 && !(currentLine.compare(charNum + 1, 2, AS_SCOPE_RESOLUTION) == 0))
1537                                                 appendSpaceAfter();
1538                                 }
1539                                 else
1540                                 {
1541                                         appendOperator(name);
1542                                         goForward(name.length() - 1);
1543                                 }
1544                         }
1545                         else
1546                         {
1547                                 appendSequence(name);
1548                                 goForward(name.length() - 1);
1549                         }
1550
1551                         continue;
1552
1553                 }   // (isPotentialHeader &&  !isInTemplate)
1554
1555                 // determine if this is an Objective-C statement
1556
1557                 if (currentChar == '@'
1558                         && isCharPotentialHeader(currentLine, charNum + 1)
1559                         && findKeyword(currentLine, charNum + 1, AS_INTERFACE)
1560                         && isBraceType(braceTypeStack->back(), NULL_TYPE))
1561                 {
1562                         isInObjCInterface = true;
1563                         string name = '@' + AS_INTERFACE;
1564                         appendSequence(name);
1565                         goForward(name.length() - 1);
1566                         continue;
1567                 }
1568                 else if (currentChar == '@'
1569                          && isCharPotentialHeader(currentLine, charNum + 1)
1570                          && findKeyword(currentLine, charNum + 1, AS_SELECTOR))
1571                 {
1572                         isInObjCSelector = true;
1573                         string name = '@' + AS_SELECTOR;
1574                         appendSequence(name);
1575                         goForward(name.length() - 1);
1576                         continue;
1577                 }
1578                 else if ((currentChar == '-' || currentChar == '+')
1579                          && (int) currentLine.find_first_not_of(" \t") == charNum
1580                          && peekNextChar() == '('
1581                          && isBraceType(braceTypeStack->back(), NULL_TYPE)
1582                          && !isInPotentialCalculation)
1583                 {
1584                         isInObjCMethodDefinition = true;
1585                         isImmediatelyPostObjCMethodPrefix = true;
1586                         isInObjCInterface = false;
1587                         if (getAlignMethodColon())
1588                                 objCColonAlign = findObjCColonAlignment();
1589                         appendCurrentChar();
1590                         continue;
1591                 }
1592
1593                 // determine if this is a potential calculation
1594
1595                 bool isPotentialOperator = isCharPotentialOperator(currentChar);
1596                 newHeader = nullptr;
1597
1598                 if (isPotentialOperator)
1599                 {
1600                         newHeader = findOperator(operators);
1601
1602                         // check for Java ? wildcard
1603                         if (newHeader != nullptr
1604                                 && newHeader == &AS_GCC_MIN_ASSIGN
1605                                 && isJavaStyle()
1606                                 && isInTemplate)
1607                                 newHeader = nullptr;
1608
1609                         if (newHeader != nullptr)
1610                         {
1611                                 if (newHeader == &AS_LAMBDA)
1612                                         foundPreCommandHeader = true;
1613
1614                                 // correct mistake of two >> closing a template
1615                                 if (isInTemplate && (newHeader == &AS_GR_GR || newHeader == &AS_GR_GR_GR))
1616                                         newHeader = &AS_GR;
1617
1618                                 if (!isInPotentialCalculation)
1619                                 {
1620                                         // must determine if newHeader is an assignment operator
1621                                         // do NOT use findOperator - the length must be exact!!!
1622                                         if (find(begin(*assignmentOperators), end(*assignmentOperators), newHeader)
1623                                                 != end(*assignmentOperators))
1624                                         {
1625                                                 foundPreCommandHeader = false;
1626                                                 char peekedChar = peekNextChar();
1627                                                 isInPotentialCalculation = !(newHeader == &AS_EQUAL && peekedChar == '*')
1628                                                                            && !(newHeader == &AS_EQUAL && peekedChar == '&')
1629                                                                            && !isCharImmediatelyPostOperator;
1630                                         }
1631                                 }
1632                         }
1633                 }
1634
1635                 // process pointers and references
1636                 // check newHeader to eliminate things like '&&' sequence
1637                 if (newHeader != nullptr && !isJavaStyle()
1638                         && (newHeader == &AS_MULT
1639                             || newHeader == &AS_BIT_AND
1640                             || newHeader == &AS_BIT_XOR
1641                             || newHeader == &AS_AND)
1642                         && isPointerOrReference())
1643                 {
1644                         if (!isDereferenceOrAddressOf() && !isOperatorPaddingDisabled())
1645                                 formatPointerOrReference();
1646                         else
1647                         {
1648                                 appendOperator(*newHeader);
1649                                 goForward(newHeader->length() - 1);
1650                         }
1651                         isImmediatelyPostPointerOrReference = true;
1652                         continue;
1653                 }
1654
1655                 if (shouldPadOperators && newHeader != nullptr && !isOperatorPaddingDisabled())
1656                 {
1657                         padOperators(newHeader);
1658                         continue;
1659                 }
1660
1661                 // remove spaces before commas
1662                 if (currentChar == ',')
1663                 {
1664                         const size_t len = formattedLine.length();
1665                         size_t lastText = formattedLine.find_last_not_of(' ');
1666                         if (lastText != string::npos && lastText < len - 1)
1667                         {
1668                                 formattedLine.resize(lastText + 1);
1669                                 int size_diff = len - (lastText + 1);
1670                                 spacePadNum -= size_diff;
1671                         }
1672                 }
1673
1674                 // pad commas and semi-colons
1675                 if (currentChar == ';'
1676                         || (currentChar == ',' && (shouldPadOperators || shouldPadCommas)))
1677                 {
1678                         char nextChar = ' ';
1679                         if (charNum + 1 < (int) currentLine.length())
1680                                 nextChar = currentLine[charNum + 1];
1681                         if (!isWhiteSpace(nextChar)
1682                                 && nextChar != '}'
1683                                 && nextChar != ')'
1684                                 && nextChar != ']'
1685                                 && nextChar != '>'
1686                                 && nextChar != ';'
1687                                 && !isBeforeAnyComment()
1688                                 /* && !(isBraceType(braceTypeStack->back(), ARRAY_TYPE)) */
1689                            )
1690                         {
1691                                 appendCurrentChar();
1692                                 appendSpaceAfter();
1693                                 continue;
1694                         }
1695                 }
1696
1697                 // pad parens
1698                 if (currentChar == '(' || currentChar == ')')
1699                 {
1700                         if (currentChar == '(')
1701                         {
1702                                 if (shouldPadHeader
1703                                         && (isCharImmediatelyPostReturn
1704                                             || isCharImmediatelyPostThrow
1705                                             || isCharImmediatelyPostNewDelete))
1706                                         appendSpacePad();
1707                         }
1708
1709                         if (shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens || shouldPadFirstParen)
1710                                 padParens();
1711                         else
1712                                 appendCurrentChar();
1713
1714                         if (isInObjCMethodDefinition)
1715                         {
1716                                 if (currentChar == '(' && isImmediatelyPostObjCMethodPrefix)
1717                                 {
1718                                         if (shouldPadMethodPrefix || shouldUnPadMethodPrefix)
1719                                                 padObjCMethodPrefix();
1720                                         isImmediatelyPostObjCMethodPrefix = false;
1721                                         isInObjCReturnType = true;
1722                                 }
1723                                 else if (currentChar == ')' && isInObjCReturnType)
1724                                 {
1725                                         if (shouldPadReturnType || shouldUnPadReturnType)
1726                                                 padObjCReturnType();
1727                                         isInObjCReturnType = false;
1728                                 }
1729                                 else if (shouldPadParamType || shouldUnPadParamType)
1730                                         padObjCParamType();
1731                         }
1732                         continue;
1733                 }
1734
1735                 // bypass the entire operator
1736                 if (newHeader != nullptr)
1737                 {
1738                         appendOperator(*newHeader);
1739                         goForward(newHeader->length() - 1);
1740                         continue;
1741                 }
1742
1743                 appendCurrentChar();
1744
1745         }   // end of while loop  *  end of while loop  *  end of while loop  *  end of while loop
1746
1747         // return a beautified (i.e. correctly indented) line.
1748
1749         string beautifiedLine;
1750         size_t readyFormattedLineLength = trim(readyFormattedLine).length();
1751         bool isInNamespace = isBraceType(braceTypeStack->back(), NAMESPACE_TYPE);
1752
1753         if (prependEmptyLine            // prepend a blank line before this formatted line
1754                 && readyFormattedLineLength > 0
1755                 && previousReadyFormattedLineLength > 0)
1756         {
1757                 isLineReady = true;             // signal a waiting readyFormattedLine
1758                 beautifiedLine = beautify("");
1759                 previousReadyFormattedLineLength = 0;
1760                 // call the enhancer for new empty lines
1761                 enhancer->enhance(beautifiedLine, isInNamespace, isInPreprocessorBeautify, isInBeautifySQL);
1762         }
1763         else            // format the current formatted line
1764         {
1765                 isLineReady = false;
1766                 runInIndentContinuation = runInIndentChars;
1767                 beautifiedLine = beautify(readyFormattedLine);
1768                 previousReadyFormattedLineLength = readyFormattedLineLength;
1769                 // the enhancer is not called for no-indent line comments
1770                 if (!lineCommentNoBeautify && !isFormattingModeOff)
1771                         enhancer->enhance(beautifiedLine, isInNamespace, isInPreprocessorBeautify, isInBeautifySQL);
1772                 runInIndentChars = 0;
1773                 lineCommentNoBeautify = lineCommentNoIndent;
1774                 lineCommentNoIndent = false;
1775                 isInIndentablePreproc = isIndentableProprocessor;
1776                 isIndentableProprocessor = false;
1777                 isElseHeaderIndent = elseHeaderFollowsComments;
1778                 isCaseHeaderCommentIndent = caseHeaderFollowsComments;
1779                 objCColonAlignSubsequent = objCColonAlign;
1780                 if (isCharImmediatelyPostNonInStmt)
1781                 {
1782                         isNonInStatementArray = false;
1783                         isCharImmediatelyPostNonInStmt = false;
1784                 }
1785                 isInPreprocessorBeautify = isInPreprocessor;    // used by ASEnhancer
1786                 isInBeautifySQL = isInExecSQL;                                  // used by ASEnhancer
1787         }
1788
1789         prependEmptyLine = false;
1790         assert(computeChecksumOut(beautifiedLine));
1791         return beautifiedLine;
1792 }
1793
1794 /**
1795  * check if there are any indented lines ready to be read by nextLine()
1796  *
1797  * @return    are there any indented lines ready?
1798  */
1799 bool ASFormatter::hasMoreLines() const
1800 {
1801         return !endOfCodeReached;
1802 }
1803
1804 /**
1805  * comparison function for BraceType enum
1806  */
1807 bool ASFormatter::isBraceType(BraceType a, BraceType b) const
1808 {
1809         if (a == NULL_TYPE || b == NULL_TYPE)
1810                 return (a == b);
1811         return ((a & b) == b);
1812 }
1813
1814 /**
1815  * set the formatting style.
1816  *
1817  * @param style         the formatting style.
1818  */
1819 void ASFormatter::setFormattingStyle(FormatStyle style)
1820 {
1821         formattingStyle = style;
1822 }
1823
1824 /**
1825  * set the add braces mode.
1826  * options:
1827  *    true     braces added to headers for single line statements.
1828  *    false    braces NOT added to headers for single line statements.
1829  *
1830  * @param state         the add braces state.
1831  */
1832 void ASFormatter::setAddBracesMode(bool state)
1833 {
1834         shouldAddBraces = state;
1835 }
1836
1837 /**
1838  * set the add one line braces mode.
1839  * options:
1840  *    true     one line braces added to headers for single line statements.
1841  *    false    one line braces NOT added to headers for single line statements.
1842  *
1843  * @param state         the add one line braces state.
1844  */
1845 void ASFormatter::setAddOneLineBracesMode(bool state)
1846 {
1847         shouldAddBraces = state;
1848         shouldAddOneLineBraces = state;
1849 }
1850
1851 /**
1852  * set the remove braces mode.
1853  * options:
1854  *    true     braces removed from headers for single line statements.
1855  *    false    braces NOT removed from headers for single line statements.
1856  *
1857  * @param state         the remove braces state.
1858  */
1859 void ASFormatter::setRemoveBracesMode(bool state)
1860 {
1861         shouldRemoveBraces = state;
1862 }
1863
1864 // retained for compatability with release 2.06
1865 // "Brackets" have been changed to "Braces" in 3.0
1866 // it is referenced only by the old "bracket" options
1867 void ASFormatter::setAddBracketsMode(bool state)
1868 {
1869         setAddBracesMode(state);
1870 }
1871
1872 // retained for compatability with release 2.06
1873 // "Brackets" have been changed to "Braces" in 3.0
1874 // it is referenced only by the old "bracket" options
1875 void ASFormatter::setAddOneLineBracketsMode(bool state)
1876 {
1877         setAddOneLineBracesMode(state);
1878 }
1879
1880 // retained for compatability with release 2.06
1881 // "Brackets" have been changed to "Braces" in 3.0
1882 // it is referenced only by the old "bracket" options
1883 void ASFormatter::setRemoveBracketsMode(bool state)
1884 {
1885         setRemoveBracesMode(state);
1886 }
1887
1888 // retained for compatability with release 2.06
1889 // "Brackets" have been changed to "Braces" in 3.0
1890 // it is referenced only by the old "bracket" options
1891 void ASFormatter::setBreakClosingHeaderBracketsMode(bool state)
1892 {
1893         setBreakClosingHeaderBracesMode(state);
1894 }
1895
1896
1897 /**
1898  * set the brace formatting mode.
1899  * options:
1900  *
1901  * @param mode         the brace formatting mode.
1902  */
1903 void ASFormatter::setBraceFormatMode(BraceMode mode)
1904 {
1905         braceFormatMode = mode;
1906 }
1907
1908 /**
1909  * set 'break after' mode for maximum code length
1910  *
1911  * @param state         the 'break after' mode.
1912  */
1913 void ASFormatter::setBreakAfterMode(bool state)
1914 {
1915         shouldBreakLineAfterLogical = state;
1916 }
1917
1918 /**
1919  * set closing header brace breaking mode
1920  * options:
1921  *    true     braces just before closing headers (e.g. 'else', 'catch')
1922  *             will be broken, even if standard braces are attached.
1923  *    false    closing header braces will be treated as standard braces.
1924  *
1925  * @param state         the closing header brace breaking mode.
1926  */
1927 void ASFormatter::setBreakClosingHeaderBracesMode(bool state)
1928 {
1929         shouldBreakClosingHeaderBraces = state;
1930 }
1931
1932 /**
1933  * set 'else if()' breaking mode
1934  * options:
1935  *    true     'else' headers will be broken from their succeeding 'if' headers.
1936  *    false    'else' headers will be attached to their succeeding 'if' headers.
1937  *
1938  * @param state         the 'else if()' breaking mode.
1939  */
1940 void ASFormatter::setBreakElseIfsMode(bool state)
1941 {
1942         shouldBreakElseIfs = state;
1943 }
1944
1945 /**
1946 * set comma padding mode.
1947 * options:
1948 *    true     statement commas and semicolons will be padded with spaces around them.
1949 *    false    statement commas and semicolons will not be padded.
1950 *
1951 * @param state         the padding mode.
1952 */
1953 void ASFormatter::setCommaPaddingMode(bool state)
1954 {
1955         shouldPadCommas = state;
1956 }
1957
1958 /**
1959  * set maximum code length
1960  *
1961  * @param max         the maximum code length.
1962  */
1963 void ASFormatter::setMaxCodeLength(int max)
1964 {
1965         maxCodeLength = max;
1966 }
1967
1968 /**
1969  * set operator padding mode.
1970  * options:
1971  *    true     statement operators will be padded with spaces around them.
1972  *    false    statement operators will not be padded.
1973  *
1974  * @param state         the padding mode.
1975  */
1976 void ASFormatter::setOperatorPaddingMode(bool state)
1977 {
1978         shouldPadOperators = state;
1979 }
1980
1981 /**
1982  * set parenthesis outside padding mode.
1983  * options:
1984  *    true     statement parentheses will be padded with spaces around them.
1985  *    false    statement parentheses will not be padded.
1986  *
1987  * @param state         the padding mode.
1988  */
1989 void ASFormatter::setParensOutsidePaddingMode(bool state)
1990 {
1991         shouldPadParensOutside = state;
1992 }
1993
1994 /**
1995  * set parenthesis inside padding mode.
1996  * options:
1997  *    true     statement parenthesis will be padded with spaces around them.
1998  *    false    statement parenthesis will not be padded.
1999  *
2000  * @param state         the padding mode.
2001  */
2002 void ASFormatter::setParensInsidePaddingMode(bool state)
2003 {
2004         shouldPadParensInside = state;
2005 }
2006
2007 /**
2008  * set padding mode before one or more open parentheses.
2009  * options:
2010  *    true     first open parenthesis will be padded with a space before.
2011  *    false    first open parenthesis will not be padded.
2012  *
2013  * @param state         the padding mode.
2014  */
2015 void ASFormatter::setParensFirstPaddingMode(bool state)
2016 {
2017         shouldPadFirstParen = state;
2018 }
2019
2020 /**
2021  * set header padding mode.
2022  * options:
2023  *    true     headers will be padded with spaces around them.
2024  *    false    headers will not be padded.
2025  *
2026  * @param state         the padding mode.
2027  */
2028 void ASFormatter::setParensHeaderPaddingMode(bool state)
2029 {
2030         shouldPadHeader = state;
2031 }
2032
2033 /**
2034  * set parenthesis unpadding mode.
2035  * options:
2036  *    true     statement parenthesis will be unpadded with spaces removed around them.
2037  *    false    statement parenthesis will not be unpadded.
2038  *
2039  * @param state         the padding mode.
2040  */
2041 void ASFormatter::setParensUnPaddingMode(bool state)
2042 {
2043         shouldUnPadParens = state;
2044 }
2045
2046 /**
2047 * set the state of the preprocessor indentation option.
2048 * If true, #ifdef blocks at level 0 will be indented.
2049 *
2050 * @param   state             state of option.
2051 */
2052 void ASFormatter::setPreprocBlockIndent(bool state)
2053 {
2054         shouldIndentPreprocBlock = state;
2055 }
2056
2057 /**
2058  * Set strip comment prefix mode.
2059  * options:
2060  *    true     strip leading '*' in a comment.
2061  *    false    leading '*' in a comment will be left unchanged.
2062  *
2063  * @param state         the strip comment prefix mode.
2064  */
2065 void ASFormatter::setStripCommentPrefix(bool state)
2066 {
2067         shouldStripCommentPrefix = state;
2068 }
2069
2070 /**
2071  * set objective-c '-' or '+' class prefix padding mode.
2072  * options:
2073  *    true     class prefix will be padded a spaces after them.
2074  *    false    class prefix will be left unchanged.
2075  *
2076  * @param state         the padding mode.
2077  */
2078 void ASFormatter::setMethodPrefixPaddingMode(bool state)
2079 {
2080         shouldPadMethodPrefix = state;
2081 }
2082
2083 /**
2084  * set objective-c '-' or '+' class prefix unpadding mode.
2085  * options:
2086  *    true     class prefix will be unpadded with spaces after them removed.
2087  *    false    class prefix will left unchanged.
2088  *
2089  * @param state         the unpadding mode.
2090  */
2091 void ASFormatter::setMethodPrefixUnPaddingMode(bool state)
2092 {
2093         shouldUnPadMethodPrefix = state;
2094 }
2095
2096 // set objective-c '-' or '+' return type padding mode.
2097 void ASFormatter::setReturnTypePaddingMode(bool state)
2098 {
2099         shouldPadReturnType = state;
2100 }
2101
2102 // set objective-c '-' or '+' return type unpadding mode.
2103 void ASFormatter::setReturnTypeUnPaddingMode(bool state)
2104 {
2105         shouldUnPadReturnType = state;
2106 }
2107
2108 // set objective-c method parameter type padding mode.
2109 void ASFormatter::setParamTypePaddingMode(bool state)
2110 {
2111         shouldPadParamType = state;
2112 }
2113
2114 // set objective-c method parameter type unpadding mode.
2115 void ASFormatter::setParamTypeUnPaddingMode(bool state)
2116 {
2117         shouldUnPadParamType = state;
2118 }
2119
2120 /**
2121  * set objective-c method colon padding mode.
2122  *
2123  * @param mode         objective-c colon padding mode.
2124  */
2125 void ASFormatter::setObjCColonPaddingMode(ObjCColonPad mode)
2126 {
2127         shouldPadMethodColon = true;
2128         objCColonPadMode = mode;
2129 }
2130
2131 /**
2132  * set option to attach closing braces
2133  *
2134  * @param state        true = attach, false = don't attach.
2135  */
2136 void ASFormatter::setAttachClosingBraceMode(bool state)
2137 {
2138         attachClosingBraceMode = state;
2139 }
2140
2141 /**
2142  * set option to attach class braces
2143  *
2144  * @param state        true = attach, false = use style default.
2145  */
2146 void ASFormatter::setAttachClass(bool state)
2147 {
2148         shouldAttachClass = state;
2149 }
2150
2151 /**
2152  * set option to attach extern "C" braces
2153  *
2154  * @param state        true = attach, false = use style default.
2155  */
2156 void ASFormatter::setAttachExternC(bool state)
2157 {
2158         shouldAttachExternC = state;
2159 }
2160
2161 /**
2162  * set option to attach namespace braces
2163  *
2164  * @param state        true = attach, false = use style default.
2165  */
2166 void ASFormatter::setAttachNamespace(bool state)
2167 {
2168         shouldAttachNamespace = state;
2169 }
2170
2171 /**
2172  * set option to attach inline braces
2173  *
2174  * @param state        true = attach, false = use style default.
2175  */
2176 void ASFormatter::setAttachInline(bool state)
2177 {
2178         shouldAttachInline = state;
2179 }
2180
2181 void ASFormatter::setAttachClosingWhile(bool state)
2182 {
2183         shouldAttachClosingWhile = state;
2184 }
2185
2186 /**
2187  * set option to break/not break one-line blocks
2188  *
2189  * @param state        true = break, false = don't break.
2190  */
2191 void ASFormatter::setBreakOneLineBlocksMode(bool state)
2192 {
2193         shouldBreakOneLineBlocks = state;
2194 }
2195
2196 /**
2197 * set one line headers breaking mode
2198 */
2199 void ASFormatter::setBreakOneLineHeadersMode(bool state)
2200 {
2201         shouldBreakOneLineHeaders = state;
2202 }
2203
2204 /**
2205 * set option to break/not break lines consisting of multiple statements.
2206 *
2207 * @param state        true = break, false = don't break.
2208 */
2209 void ASFormatter::setBreakOneLineStatementsMode(bool state)
2210 {
2211         shouldBreakOneLineStatements = state;
2212 }
2213
2214 void ASFormatter::setCloseTemplatesMode(bool state)
2215 {
2216         shouldCloseTemplates = state;
2217 }
2218
2219 /**
2220  * set option to convert tabs to spaces.
2221  *
2222  * @param state        true = convert, false = don't convert.
2223  */
2224 void ASFormatter::setTabSpaceConversionMode(bool state)
2225 {
2226         shouldConvertTabs = state;
2227 }
2228
2229 /**
2230  * set option to indent comments in column 1.
2231  *
2232  * @param state        true = indent, false = don't indent.
2233  */
2234 void ASFormatter::setIndentCol1CommentsMode(bool state)
2235 {
2236         shouldIndentCol1Comments = state;
2237 }
2238
2239 /**
2240  * set option to force all line ends to a particular style.
2241  *
2242  * @param fmt           format enum value
2243  */
2244 void ASFormatter::setLineEndFormat(LineEndFormat fmt)
2245 {
2246         lineEnd = fmt;
2247 }
2248
2249 /**
2250  * set option to break unrelated blocks of code with empty lines.
2251  *
2252  * @param state        true = convert, false = don't convert.
2253  */
2254 void ASFormatter::setBreakBlocksMode(bool state)
2255 {
2256         shouldBreakBlocks = state;
2257 }
2258
2259 /**
2260  * set option to break closing header blocks of code (such as 'else', 'catch', ...) with empty lines.
2261  *
2262  * @param state        true = convert, false = don't convert.
2263  */
2264 void ASFormatter::setBreakClosingHeaderBlocksMode(bool state)
2265 {
2266         shouldBreakClosingHeaderBlocks = state;
2267 }
2268
2269 /**
2270  * set option to delete empty lines.
2271  *
2272  * @param state        true = delete, false = don't delete.
2273  */
2274 void ASFormatter::setDeleteEmptyLinesMode(bool state)
2275 {
2276         shouldDeleteEmptyLines = state;
2277 }
2278
2279 /**
2280  * set the pointer alignment.
2281  *
2282  * @param alignment    the pointer alignment.
2283  */
2284 void ASFormatter::setPointerAlignment(PointerAlign alignment)
2285 {
2286         pointerAlignment = alignment;
2287 }
2288
2289 void ASFormatter::setReferenceAlignment(ReferenceAlign alignment)
2290 {
2291         referenceAlignment = alignment;
2292 }
2293
2294 /**
2295  * jump over several characters.
2296  *
2297  * @param i       the number of characters to jump over.
2298  */
2299 void ASFormatter::goForward(int i)
2300 {
2301         while (--i >= 0)
2302                 getNextChar();
2303 }
2304
2305 /**
2306  * peek at the next unread character.
2307  *
2308  * @return     the next unread character.
2309  */
2310 char ASFormatter::peekNextChar() const
2311 {
2312         char ch = ' ';
2313         size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
2314
2315         if (peekNum == string::npos)
2316                 return ch;
2317
2318         ch = currentLine[peekNum];
2319
2320         return ch;
2321 }
2322
2323 /**
2324  * check if current placement is before a comment
2325  *
2326  * @return     is before a comment.
2327  */
2328 bool ASFormatter::isBeforeComment() const
2329 {
2330         bool foundComment = false;
2331         size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
2332
2333         if (peekNum == string::npos)
2334                 return foundComment;
2335
2336         foundComment = (currentLine.compare(peekNum, 2, "/*") == 0);
2337
2338         return foundComment;
2339 }
2340
2341 /**
2342  * check if current placement is before a comment or line-comment
2343  *
2344  * @return     is before a comment or line-comment.
2345  */
2346 bool ASFormatter::isBeforeAnyComment() const
2347 {
2348         bool foundComment = false;
2349         size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
2350
2351         if (peekNum == string::npos)
2352                 return foundComment;
2353
2354         foundComment = (currentLine.compare(peekNum, 2, "/*") == 0
2355                         || currentLine.compare(peekNum, 2, "//") == 0);
2356
2357         return foundComment;
2358 }
2359
2360 /**
2361  * check if current placement is before a comment or line-comment
2362  * if a block comment it must be at the end of the line
2363  *
2364  * @return     is before a comment or line-comment.
2365  */
2366 bool ASFormatter::isBeforeAnyLineEndComment(int startPos) const
2367 {
2368         bool foundLineEndComment = false;
2369         size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1);
2370
2371         if (peekNum != string::npos)
2372         {
2373                 if (currentLine.compare(peekNum, 2, "//") == 0)
2374                         foundLineEndComment = true;
2375                 else if (currentLine.compare(peekNum, 2, "/*") == 0)
2376                 {
2377                         // comment must be closed on this line with nothing after it
2378                         size_t endNum = currentLine.find("*/", peekNum + 2);
2379                         if (endNum != string::npos)
2380                         {
2381                                 size_t nextChar = currentLine.find_first_not_of(" \t", endNum + 2);
2382                                 if (nextChar == string::npos)
2383                                         foundLineEndComment = true;
2384                         }
2385                 }
2386         }
2387         return foundLineEndComment;
2388 }
2389
2390 /**
2391  * check if current placement is before a comment followed by a line-comment
2392  *
2393  * @return     is before a multiple line-end comment.
2394  */
2395 bool ASFormatter::isBeforeMultipleLineEndComments(int startPos) const
2396 {
2397         bool foundMultipleLineEndComment = false;
2398         size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1);
2399
2400         if (peekNum != string::npos)
2401         {
2402                 if (currentLine.compare(peekNum, 2, "/*") == 0)
2403                 {
2404                         // comment must be closed on this line with nothing after it
2405                         size_t endNum = currentLine.find("*/", peekNum + 2);
2406                         if (endNum != string::npos)
2407                         {
2408                                 size_t nextChar = currentLine.find_first_not_of(" \t", endNum + 2);
2409                                 if (nextChar != string::npos
2410                                         && currentLine.compare(nextChar, 2, "//") == 0)
2411                                         foundMultipleLineEndComment = true;
2412                         }
2413                 }
2414         }
2415         return foundMultipleLineEndComment;
2416 }
2417
2418 /**
2419  * get the next character, increasing the current placement in the process.
2420  * the new character is inserted into the variable currentChar.
2421  *
2422  * @return   whether succeeded to receive the new character.
2423  */
2424 bool ASFormatter::getNextChar()
2425 {
2426         isInLineBreak = false;
2427         previousChar = currentChar;
2428
2429         if (!isWhiteSpace(currentChar))
2430         {
2431                 previousNonWSChar = currentChar;
2432                 if (!isInComment && !isInLineComment && !isInQuote
2433                         && !isImmediatelyPostComment
2434                         && !isImmediatelyPostLineComment
2435                         && !isInPreprocessor
2436                         && !isSequenceReached("/*")
2437                         && !isSequenceReached("//"))
2438                         previousCommandChar = currentChar;
2439         }
2440
2441         if (charNum + 1 < (int) currentLine.length()
2442                 && (!isWhiteSpace(peekNextChar()) || isInComment || isInLineComment))
2443         {
2444                 currentChar = currentLine[++charNum];
2445
2446                 if (currentChar == '\t' && shouldConvertTabs)
2447                         convertTabToSpaces();
2448
2449                 return true;
2450         }
2451
2452         // end of line has been reached
2453         return getNextLine();
2454 }
2455
2456 /**
2457  * get the next line of input, increasing the current placement in the process.
2458  *
2459  * @param emptyLineWasDeleted         an empty line was deleted.
2460  * @return   whether succeeded in reading the next line.
2461  */
2462 bool ASFormatter::getNextLine(bool emptyLineWasDeleted /*false*/)
2463 {
2464         if (!sourceIterator->hasMoreLines())
2465         {
2466                 endOfCodeReached = true;
2467                 return false;
2468         }
2469         if (appendOpeningBrace)
2470                 currentLine = "{";              // append brace that was removed from the previous line
2471         else
2472         {
2473                 currentLine = sourceIterator->nextLine(emptyLineWasDeleted);
2474                 assert(computeChecksumIn(currentLine));
2475         }
2476         // reset variables for new line
2477         inLineNumber++;
2478         if (endOfAsmReached)
2479                 endOfAsmReached = isInAsmBlock = isInAsm = false;
2480         shouldKeepLineUnbroken = false;
2481         isInCommentStartLine = false;
2482         isInCase = false;
2483         isInAsmOneLine = false;
2484         isHeaderInMultiStatementLine = false;
2485         isInQuoteContinuation = isInVerbatimQuote || haveLineContinuationChar;
2486         haveLineContinuationChar = false;
2487         isImmediatelyPostEmptyLine = lineIsEmpty;
2488         previousChar = ' ';
2489
2490         if (currentLine.length() == 0)
2491                 currentLine = string(" ");        // a null is inserted if this is not done
2492
2493         // unless reading in the first line of the file, break a new line.
2494         if (!isVirgin)
2495                 isInLineBreak = true;
2496         else
2497                 isVirgin = false;
2498
2499         if (isImmediatelyPostNonInStmt)
2500         {
2501                 isCharImmediatelyPostNonInStmt = true;
2502                 isImmediatelyPostNonInStmt = false;
2503         }
2504
2505         // check if is in preprocessor before line trimming
2506         // a blank line after a \ will remove the flag
2507         isImmediatelyPostPreprocessor = isInPreprocessor;
2508         if (!isInComment
2509                 && (previousNonWSChar != '\\'
2510                     || isEmptyLine(currentLine)))
2511                 isInPreprocessor = false;
2512
2513         if (passedSemicolon)
2514                 isInExecSQL = false;
2515         initNewLine();
2516
2517         currentChar = currentLine[charNum];
2518         if (isInBraceRunIn && previousNonWSChar == '{' && !isInComment)
2519                 isInLineBreak = false;
2520         isInBraceRunIn = false;
2521
2522         if (currentChar == '\t' && shouldConvertTabs)
2523                 convertTabToSpaces();
2524
2525         // check for an empty line inside a command brace.
2526         // if yes then read the next line (calls getNextLine recursively).
2527         // must be after initNewLine.
2528         if (shouldDeleteEmptyLines
2529                 && lineIsEmpty
2530                 && isBraceType((*braceTypeStack)[braceTypeStack->size() - 1], COMMAND_TYPE))
2531         {
2532                 if (!shouldBreakBlocks || previousNonWSChar == '{' || !commentAndHeaderFollows())
2533                 {
2534                         isInPreprocessor = isImmediatelyPostPreprocessor;               // restore
2535                         lineIsEmpty = false;
2536                         return getNextLine(true);
2537                 }
2538         }
2539         return true;
2540 }
2541
2542 /**
2543  * jump over the leading white space in the current line,
2544  * IF the line does not begin a comment or is in a preprocessor definition.
2545  */
2546 void ASFormatter::initNewLine()
2547 {
2548         size_t len = currentLine.length();
2549         size_t tabSize = getTabLength();
2550         charNum = 0;
2551
2552         // don't trim these
2553         if (isInQuoteContinuation
2554                 || (isInPreprocessor && !getPreprocDefineIndent()))
2555                 return;
2556
2557         // SQL continuation lines must be adjusted so the leading spaces
2558         // is equivalent to the opening EXEC SQL
2559         if (isInExecSQL)
2560         {
2561                 // replace leading tabs with spaces
2562                 // so that continuation indent will be spaces
2563                 size_t tabCount_ = 0;
2564                 size_t i;
2565                 for (i = 0; i < currentLine.length(); i++)
2566                 {
2567                         if (!isWhiteSpace(currentLine[i]))              // stop at first text
2568                                 break;
2569                         if (currentLine[i] == '\t')
2570                         {
2571                                 size_t numSpaces = tabSize - ((tabCount_ + i) % tabSize);
2572                                 currentLine.replace(i, 1, numSpaces, ' ');
2573                                 tabCount_++;
2574                                 i += tabSize - 1;
2575                         }
2576                 }
2577                 // this will correct the format if EXEC SQL is not a hanging indent
2578                 trimContinuationLine();
2579                 return;
2580         }
2581
2582         // comment continuation lines must be adjusted so the leading spaces
2583         // is equivalent to the opening comment
2584         if (isInComment)
2585         {
2586                 if (noTrimCommentContinuation)
2587                         leadingSpaces = tabIncrementIn = 0;
2588                 trimContinuationLine();
2589                 return;
2590         }
2591
2592         // compute leading spaces
2593         isImmediatelyPostCommentOnly = lineIsLineCommentOnly || lineEndsInCommentOnly;
2594         lineIsCommentOnly = false;
2595         lineIsLineCommentOnly = false;
2596         lineEndsInCommentOnly = false;
2597         doesLineStartComment = false;
2598         currentLineBeginsWithBrace = false;
2599         lineIsEmpty = false;
2600         currentLineFirstBraceNum = string::npos;
2601         tabIncrementIn = 0;
2602
2603         // bypass whitespace at the start of a line
2604         // preprocessor tabs are replaced later in the program
2605         for (charNum = 0; isWhiteSpace(currentLine[charNum]) && charNum + 1 < (int) len; charNum++)
2606         {
2607                 if (currentLine[charNum] == '\t' && !isInPreprocessor)
2608                         tabIncrementIn += tabSize - 1 - ((tabIncrementIn + charNum) % tabSize);
2609         }
2610         leadingSpaces = charNum + tabIncrementIn;
2611
2612         if (isSequenceReached("/*"))
2613         {
2614                 doesLineStartComment = true;
2615                 if ((int) currentLine.length() > charNum + 2
2616                         && currentLine.find("*/", charNum + 2) != string::npos)
2617                         lineIsCommentOnly = true;
2618         }
2619         else if (isSequenceReached("//"))
2620         {
2621                 lineIsLineCommentOnly = true;
2622         }
2623         else if (isSequenceReached("{"))
2624         {
2625                 currentLineBeginsWithBrace = true;
2626                 currentLineFirstBraceNum = charNum;
2627                 size_t firstText = currentLine.find_first_not_of(" \t", charNum + 1);
2628                 if (firstText != string::npos)
2629                 {
2630                         if (currentLine.compare(firstText, 2, "//") == 0)
2631                                 lineIsLineCommentOnly = true;
2632                         else if (currentLine.compare(firstText, 2, "/*") == 0
2633                                  || isExecSQL(currentLine, firstText))
2634                         {
2635                                 // get the extra adjustment
2636                                 size_t j;
2637                                 for (j = charNum + 1; j < firstText && isWhiteSpace(currentLine[j]); j++)
2638                                 {
2639                                         if (currentLine[j] == '\t')
2640                                                 tabIncrementIn += tabSize - 1 - ((tabIncrementIn + j) % tabSize);
2641                                 }
2642                                 leadingSpaces = j + tabIncrementIn;
2643                                 if (currentLine.compare(firstText, 2, "/*") == 0)
2644                                         doesLineStartComment = true;
2645                         }
2646                 }
2647         }
2648         else if (isWhiteSpace(currentLine[charNum]) && !(charNum + 1 < (int) currentLine.length()))
2649         {
2650                 lineIsEmpty = true;
2651         }
2652
2653         // do not trim indented preprocessor define (except for comment continuation lines)
2654         if (isInPreprocessor)
2655         {
2656                 if (!doesLineStartComment)
2657                         leadingSpaces = 0;
2658                 charNum = 0;
2659         }
2660 }
2661
2662 /**
2663  * Append a character to the current formatted line.
2664  * The formattedLine split points are updated.
2665  *
2666  * @param ch               the character to append.
2667  * @param canBreakLine     if true, a registered line-break
2668  */
2669 void ASFormatter::appendChar(char ch, bool canBreakLine)
2670 {
2671         if (canBreakLine && isInLineBreak)
2672                 breakLine();
2673
2674         formattedLine.append(1, ch);
2675         isImmediatelyPostCommentOnly = false;
2676         if (maxCodeLength != string::npos)
2677         {
2678                 // These compares reduce the frequency of function calls.
2679                 if (isOkToSplitFormattedLine())
2680                         updateFormattedLineSplitPoints(ch);
2681                 if (formattedLine.length() > maxCodeLength)
2682                         testForTimeToSplitFormattedLine();
2683         }
2684 }
2685
2686 /**
2687  * Append a string sequence to the current formatted line.
2688  * The formattedLine split points are NOT updated.
2689  * But the formattedLine is checked for time to split.
2690  *
2691  * @param sequence         the sequence to append.
2692  * @param canBreakLine     if true, a registered line-break
2693  */
2694 void ASFormatter::appendSequence(const string& sequence, bool canBreakLine)
2695 {
2696         if (canBreakLine && isInLineBreak)
2697                 breakLine();
2698         formattedLine.append(sequence);
2699         if (formattedLine.length() > maxCodeLength)
2700                 testForTimeToSplitFormattedLine();
2701 }
2702
2703 /**
2704  * Append an operator sequence to the current formatted line.
2705  * The formattedLine split points are updated.
2706  *
2707  * @param sequence         the sequence to append.
2708  * @param canBreakLine     if true, a registered line-break
2709  */
2710 void ASFormatter::appendOperator(const string& sequence, bool canBreakLine)
2711 {
2712         if (canBreakLine && isInLineBreak)
2713                 breakLine();
2714         formattedLine.append(sequence);
2715         if (maxCodeLength != string::npos)
2716         {
2717                 // These compares reduce the frequency of function calls.
2718                 if (isOkToSplitFormattedLine())
2719                         updateFormattedLineSplitPointsOperator(sequence);
2720                 if (formattedLine.length() > maxCodeLength)
2721                         testForTimeToSplitFormattedLine();
2722         }
2723 }
2724
2725 /**
2726  * append a space to the current formattedline, UNLESS the
2727  * last character is already a white-space character.
2728  */
2729 void ASFormatter::appendSpacePad()
2730 {
2731         int len = formattedLine.length();
2732         if (len > 0 && !isWhiteSpace(formattedLine[len - 1]))
2733         {
2734                 formattedLine.append(1, ' ');
2735                 spacePadNum++;
2736                 if (maxCodeLength != string::npos)
2737                 {
2738                         // These compares reduce the frequency of function calls.
2739                         if (isOkToSplitFormattedLine())
2740                                 updateFormattedLineSplitPoints(' ');
2741                         if (formattedLine.length() > maxCodeLength)
2742                                 testForTimeToSplitFormattedLine();
2743                 }
2744         }
2745 }
2746
2747 /**
2748  * append a space to the current formattedline, UNLESS the
2749  * next character is already a white-space character.
2750  */
2751 void ASFormatter::appendSpaceAfter()
2752 {
2753         int len = currentLine.length();
2754         if (charNum + 1 < len && !isWhiteSpace(currentLine[charNum + 1]))
2755         {
2756                 formattedLine.append(1, ' ');
2757                 spacePadNum++;
2758                 if (maxCodeLength != string::npos)
2759                 {
2760                         // These compares reduce the frequency of function calls.
2761                         if (isOkToSplitFormattedLine())
2762                                 updateFormattedLineSplitPoints(' ');
2763                         if (formattedLine.length() > maxCodeLength)
2764                                 testForTimeToSplitFormattedLine();
2765                 }
2766         }
2767 }
2768
2769 /**
2770  * register a line break for the formatted line.
2771  */
2772 void ASFormatter::breakLine(bool isSplitLine /*false*/)
2773 {
2774         isLineReady = true;
2775         isInLineBreak = false;
2776         spacePadNum = nextLineSpacePadNum;
2777         nextLineSpacePadNum = 0;
2778         readyFormattedLine = formattedLine;
2779         formattedLine.erase();
2780         // queue an empty line prepend request if one exists
2781         prependEmptyLine = isPrependPostBlockEmptyLineRequested;
2782
2783         if (!isSplitLine)
2784         {
2785                 formattedLineCommentNum = string::npos;
2786                 clearFormattedLineSplitPoints();
2787
2788                 if (isAppendPostBlockEmptyLineRequested)
2789                 {
2790                         isAppendPostBlockEmptyLineRequested = false;
2791                         isPrependPostBlockEmptyLineRequested = true;
2792                 }
2793                 else
2794                         isPrependPostBlockEmptyLineRequested = false;
2795         }
2796 }
2797
2798 /**
2799  * check if the currently reached open-brace (i.e. '{')
2800  * opens a:
2801  * - a definition type block (such as a class or namespace),
2802  * - a command block (such as a method block)
2803  * - a static array
2804  * this method takes for granted that the current character
2805  * is an opening brace.
2806  *
2807  * @return    the type of the opened block.
2808  */
2809 BraceType ASFormatter::getBraceType()
2810 {
2811         assert(currentChar == '{');
2812
2813         BraceType returnVal = NULL_TYPE;
2814
2815         if ((previousNonWSChar == '='
2816                 || isBraceType(braceTypeStack->back(), ARRAY_TYPE))
2817                 && previousCommandChar != ')'
2818                 && !isNonParenHeader)
2819                 returnVal = ARRAY_TYPE;
2820         else if (foundPreDefinitionHeader && previousCommandChar != ')')
2821         {
2822                 returnVal = DEFINITION_TYPE;
2823                 if (foundNamespaceHeader)
2824                         returnVal = (BraceType)(returnVal | NAMESPACE_TYPE);
2825                 else if (foundClassHeader)
2826                         returnVal = (BraceType)(returnVal | CLASS_TYPE);
2827                 else if (foundStructHeader)
2828                         returnVal = (BraceType)(returnVal | STRUCT_TYPE);
2829                 else if (foundInterfaceHeader)
2830                         returnVal = (BraceType)(returnVal | INTERFACE_TYPE);
2831         }
2832         else if (isInEnum)
2833         {
2834                 returnVal = (BraceType)(ARRAY_TYPE | ENUM_TYPE);
2835         }
2836         else
2837         {
2838                 bool isCommandType = (foundPreCommandHeader
2839                                       || foundPreCommandMacro
2840                                       || (currentHeader != nullptr && isNonParenHeader)
2841                                       || (previousCommandChar == ')')
2842                                       || (previousCommandChar == ':' && !foundQuestionMark)
2843                                       || (previousCommandChar == ';')
2844                                       || ((previousCommandChar == '{' || previousCommandChar == '}')
2845                                           && isPreviousBraceBlockRelated)
2846                                       || (isInClassInitializer
2847                                           && (!isLegalNameChar(previousNonWSChar) || foundPreCommandHeader))
2848                                       || foundTrailingReturnType
2849                                       || isInObjCMethodDefinition
2850                                       || isInObjCInterface
2851                                       || isJavaStaticConstructor
2852                                       || isSharpDelegate);
2853
2854                 // C# methods containing 'get', 'set', 'add', and 'remove' do NOT end with parens
2855                 if (!isCommandType && isSharpStyle() && isNextWordSharpNonParenHeader(charNum + 1))
2856                 {
2857                         isCommandType = true;
2858                         isSharpAccessor = true;
2859                 }
2860
2861                 if (isInExternC)
2862                         returnVal = (isCommandType ? COMMAND_TYPE : EXTERN_TYPE);
2863                 else
2864                         returnVal = (isCommandType ? COMMAND_TYPE : ARRAY_TYPE);
2865         }
2866
2867         int foundOneLineBlock = isOneLineBlockReached(currentLine, charNum);
2868
2869         if (foundOneLineBlock == 2 && returnVal == COMMAND_TYPE)
2870                 returnVal = ARRAY_TYPE;
2871
2872         if (foundOneLineBlock > 0)
2873         {
2874                 returnVal = (BraceType) (returnVal | SINGLE_LINE_TYPE);
2875                 if (breakCurrentOneLineBlock)
2876                         returnVal = (BraceType) (returnVal | BREAK_BLOCK_TYPE);
2877                 if (foundOneLineBlock == 3)
2878                         returnVal = (BraceType)(returnVal | EMPTY_BLOCK_TYPE);
2879         }
2880
2881         if (isBraceType(returnVal, ARRAY_TYPE))
2882         {
2883                 if (isNonInStatementArrayBrace())
2884                 {
2885                         returnVal = (BraceType)(returnVal | ARRAY_NIS_TYPE);
2886                         isNonInStatementArray = true;
2887                         isImmediatelyPostNonInStmt = false;             // in case of "},{"
2888                         nonInStatementBrace = formattedLine.length() - 1;
2889                 }
2890                 if (isUniformInitializerBrace())
2891                         returnVal = (BraceType)(returnVal | INIT_TYPE);
2892         }
2893
2894         return returnVal;
2895 }
2896
2897 /**
2898 * check if a colon is a class initializer separator
2899 *
2900 * @return        whether it is a class initializer separator
2901 */
2902 bool ASFormatter::isClassInitializer() const
2903 {
2904         assert(currentChar == ':');
2905         assert(previousChar != ':' && peekNextChar() != ':');   // not part of '::'
2906
2907         // this should be similar to ASBeautifier::parseCurrentLine()
2908         bool foundClassInitializer = false;
2909
2910         if (foundQuestionMark)
2911         {
2912                 // do nothing special
2913         }
2914         else if (parenStack->back() > 0)
2915         {
2916                 // found a 'for' loop or an objective-C statement
2917                 // so do nothing special
2918         }
2919         else if (isInEnum)
2920         {
2921                 // found an enum with a base-type
2922         }
2923         else if (isCStyle()
2924                  && !isInCase
2925                  && (previousCommandChar == ')' || foundPreCommandHeader))
2926         {
2927                 // found a 'class' c'tor initializer
2928                 foundClassInitializer = true;
2929         }
2930         return foundClassInitializer;
2931 }
2932
2933 /**
2934  * check if a line is empty
2935  *
2936  * @return        whether line is empty
2937  */
2938 bool ASFormatter::isEmptyLine(const string& line) const
2939 {
2940         return line.find_first_not_of(" \t") == string::npos;
2941 }
2942
2943 /**
2944  * Check if the following text is "C" as in extern "C".
2945  *
2946  * @return        whether the statement is extern "C"
2947  */
2948 bool ASFormatter::isExternC() const
2949 {
2950         // charNum should be at 'extern'
2951         assert(!isWhiteSpace(currentLine[charNum]));
2952         size_t startQuote = currentLine.find_first_of(" \t\"", charNum);
2953         if (startQuote == string::npos)
2954                 return false;
2955         startQuote = currentLine.find_first_not_of(" \t", startQuote);
2956         if (startQuote == string::npos)
2957                 return false;
2958         if (currentLine.compare(startQuote, 3, "\"C\"") != 0)
2959                 return false;
2960         return true;
2961 }
2962
2963 /**
2964  * Check if the currently reached '*', '&' or '^' character is
2965  * a pointer-or-reference symbol, or another operator.
2966  * A pointer dereference (*) or an "address of" character (&)
2967  * counts as a pointer or reference because it is not an
2968  * arithmetic operator.
2969  *
2970  * @return        whether current character is a reference-or-pointer
2971  */
2972 bool ASFormatter::isPointerOrReference() const
2973 {
2974         assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
2975
2976         if (isJavaStyle())
2977                 return false;
2978
2979         if (isCharImmediatelyPostOperator)
2980                 return false;
2981
2982         // get the last legal word (may be a number)
2983         string lastWord = getPreviousWord(currentLine, charNum);
2984         if (lastWord.empty())
2985                 lastWord = " ";
2986
2987         // check for preceding or following numeric values
2988         string nextText = peekNextText(currentLine.substr(charNum + 1));
2989         if (nextText.length() == 0)
2990                 nextText = " ";
2991         char nextChar = nextText[0];
2992         if (isDigit(lastWord[0])
2993                 || isDigit(nextChar)
2994                 || nextChar == '!'
2995                 || nextChar == '~')
2996                 return false;
2997
2998         // check for multiply then a dereference (a * *b)
2999         if (currentChar == '*'
3000                 && charNum < (int) currentLine.length() - 1
3001                 && isWhiteSpace(currentLine[charNum + 1])
3002                 && nextChar == '*')
3003                 return false;
3004
3005         if ((foundCastOperator && nextChar == '>')
3006                 || isPointerOrReferenceVariable(lastWord))
3007                 return true;
3008
3009         if (isInClassInitializer
3010                 && previousNonWSChar != '('
3011                 && previousNonWSChar != '{'
3012                 && previousCommandChar != ','
3013                 && nextChar != ')'
3014                 && nextChar != '}')
3015                 return false;
3016
3017         //check for rvalue reference
3018         if (currentChar == '&' && nextChar == '&')
3019         {
3020                 if (previousNonWSChar == '>')
3021                         return true;
3022                 string followingText;
3023                 if ((int) currentLine.length() > charNum + 2)
3024                         followingText = peekNextText(currentLine.substr(charNum + 2));
3025                 if (followingText.length() > 0 && followingText[0] == ')')
3026                         return true;
3027                 if (currentHeader != nullptr || isInPotentialCalculation)
3028                         return false;
3029                 if (parenStack->back() > 0 && isBraceType(braceTypeStack->back(), COMMAND_TYPE))
3030                         return false;
3031                 return true;
3032         }
3033         if (nextChar == '*'
3034                 || previousNonWSChar == '='
3035                 || previousNonWSChar == '('
3036                 || previousNonWSChar == '['
3037                 || isCharImmediatelyPostReturn
3038                 || isInTemplate
3039                 || isCharImmediatelyPostTemplate
3040                 || currentHeader == &AS_CATCH
3041                 || currentHeader == &AS_FOREACH
3042                 || currentHeader == &AS_QFOREACH)
3043                 return true;
3044
3045         if (isBraceType(braceTypeStack->back(), ARRAY_TYPE)
3046                 && isLegalNameChar(lastWord[0])
3047                 && isLegalNameChar(nextChar)
3048                 && previousNonWSChar != ')')
3049         {
3050                 if (isArrayOperator())
3051                         return false;
3052         }
3053
3054         // checks on operators in parens
3055         if (parenStack->back() > 0
3056                 && isLegalNameChar(lastWord[0])
3057                 && isLegalNameChar(nextChar))
3058         {
3059                 // if followed by an assignment it is a pointer or reference
3060                 // if followed by semicolon it is a pointer or reference in range-based for
3061                 const string* followingOperator = getFollowingOperator();
3062                 if (followingOperator != nullptr
3063                         && followingOperator != &AS_MULT
3064                         && followingOperator != &AS_BIT_AND)
3065                 {
3066                         if (followingOperator == &AS_ASSIGN || followingOperator == &AS_COLON)
3067                                 return true;
3068                         return false;
3069                 }
3070
3071                 if (isBraceType(braceTypeStack->back(), COMMAND_TYPE)
3072                         || squareBracketCount > 0)
3073                         return false;
3074                 return true;
3075         }
3076
3077         // checks on operators in parens with following '('
3078         if (parenStack->back() > 0
3079                 && nextChar == '('
3080                 && previousNonWSChar != ','
3081                 && previousNonWSChar != '('
3082                 && previousNonWSChar != '!'
3083                 && previousNonWSChar != '&'
3084                 && previousNonWSChar != '*'
3085                 && previousNonWSChar != '|')
3086                 return false;
3087
3088         if (nextChar == '-'
3089                 || nextChar == '+')
3090         {
3091                 size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);
3092                 if (nextNum != string::npos)
3093                 {
3094                         if (currentLine.compare(nextNum, 2, "++") != 0
3095                                 && currentLine.compare(nextNum, 2, "--") != 0)
3096                                 return false;
3097                 }
3098         }
3099
3100         bool isPR = (!isInPotentialCalculation
3101                      || (!isLegalNameChar(previousNonWSChar)
3102                          && !(previousNonWSChar == ')' && nextChar == '(')
3103                          && !(previousNonWSChar == ')' && currentChar == '*' && !isImmediatelyPostCast())
3104                          && previousNonWSChar != ']')
3105                      || (!isWhiteSpace(nextChar)
3106                          && nextChar != '-'
3107                          && nextChar != '('
3108                          && nextChar != '['
3109                          && !isLegalNameChar(nextChar))
3110                     );
3111
3112         return isPR;
3113 }
3114
3115 /**
3116  * Check if the currently reached  '*' or '&' character is
3117  * a dereferenced pointer or "address of" symbol.
3118  * NOTE: this MUST be a pointer or reference as determined by
3119  * the function isPointerOrReference().
3120  *
3121  * @return        whether current character is a dereference or address of
3122  */
3123 bool ASFormatter::isDereferenceOrAddressOf() const
3124 {
3125         assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
3126
3127         if (isCharImmediatelyPostTemplate)
3128                 return false;
3129
3130         if (previousNonWSChar == '='
3131                 || previousNonWSChar == ','
3132                 || previousNonWSChar == '.'
3133                 || previousNonWSChar == '{'
3134                 || previousNonWSChar == '>'
3135                 || previousNonWSChar == '<'
3136                 || previousNonWSChar == '?'
3137                 || isCharImmediatelyPostLineComment
3138                 || isCharImmediatelyPostComment
3139                 || isCharImmediatelyPostReturn)
3140                 return true;
3141
3142         char nextChar = peekNextChar();
3143         if (currentChar == '*' && nextChar == '*')
3144         {
3145                 if (previousNonWSChar == '(')
3146                         return true;
3147                 if ((int) currentLine.length() < charNum + 2)
3148                         return true;
3149                 return false;
3150         }
3151         if (currentChar == '&' && nextChar == '&')
3152         {
3153                 if (previousNonWSChar == '(' || isInTemplate)
3154                         return true;
3155                 if ((int) currentLine.length() < charNum + 2)
3156                         return true;
3157                 return false;
3158         }
3159
3160         // check first char on the line
3161         if (charNum == (int) currentLine.find_first_not_of(" \t")
3162                 && (isBraceType(braceTypeStack->back(), COMMAND_TYPE)
3163                     || parenStack->back() != 0))
3164                 return true;
3165
3166         string nextText = peekNextText(currentLine.substr(charNum + 1));
3167         if (nextText.length() > 0)
3168         {
3169                 if (nextText[0] == ')' || nextText[0] == '>'
3170                         || nextText[0] == ',' || nextText[0] == '=')
3171                         return false;
3172                 if (nextText[0] == ';')
3173                         return true;
3174         }
3175
3176         // check for reference to a pointer *& (cannot have &*)
3177         if ((currentChar == '*' && nextChar == '&')
3178                 || (previousNonWSChar == '*' && currentChar == '&'))
3179                 return false;
3180
3181         if (!isBraceType(braceTypeStack->back(), COMMAND_TYPE)
3182                 && parenStack->back() == 0)
3183                 return false;
3184
3185         string lastWord = getPreviousWord(currentLine, charNum);
3186         if (lastWord == "else" || lastWord == "delete")
3187                 return true;
3188
3189         if (isPointerOrReferenceVariable(lastWord))
3190                 return false;
3191
3192         bool isDA = (!(isLegalNameChar(previousNonWSChar) || previousNonWSChar == '>')
3193                      || (nextText.length() > 0 && !isLegalNameChar(nextText[0]) && nextText[0] != '/')
3194                      || (ispunct((unsigned char)previousNonWSChar) && previousNonWSChar != '.')
3195                      || isCharImmediatelyPostReturn);
3196
3197         return isDA;
3198 }
3199
3200 /**
3201  * Check if the currently reached  '*' or '&' character is
3202  * centered with one space on each side.
3203  * Only spaces are checked, not tabs.
3204  * If true then a space will be deleted on the output.
3205  *
3206  * @return        whether current character is centered.
3207  */
3208 bool ASFormatter::isPointerOrReferenceCentered() const
3209 {
3210         assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
3211
3212         int prNum = charNum;
3213         int lineLength = (int) currentLine.length();
3214
3215         // check for end of line
3216         if (peekNextChar() == ' ')
3217                 return false;
3218
3219         // check space before
3220         if (prNum < 1
3221                 || currentLine[prNum - 1] != ' ')
3222                 return false;
3223
3224         // check no space before that
3225         if (prNum < 2
3226                 || currentLine[prNum - 2] == ' ')
3227                 return false;
3228
3229         // check for ** or &&
3230         if (prNum + 1 < lineLength
3231                 && (currentLine[prNum + 1] == '*' || currentLine[prNum + 1] == '&'))
3232                 prNum++;
3233
3234         // check space after
3235         if (prNum + 1 <= lineLength
3236                 && currentLine[prNum + 1] != ' ')
3237                 return false;
3238
3239         // check no space after that
3240         if (prNum + 2 < lineLength
3241                 && currentLine[prNum + 2] == ' ')
3242                 return false;
3243
3244         return true;
3245 }
3246
3247 /**
3248  * Check if a word is a pointer or reference variable type.
3249  *
3250  * @return        whether word is a pointer or reference variable.
3251  */
3252 bool ASFormatter::isPointerOrReferenceVariable(const string& word) const
3253 {
3254         return (word == "char"
3255                 || word == "int"
3256                 || word == "void"
3257                 || (word.length() >= 6     // check end of word for _t
3258                     && word.compare(word.length() - 2, 2, "_t") == 0)
3259                 || word == "INT"
3260                 || word == "VOID");
3261 }
3262
3263 /**
3264  * check if the currently reached '+' or '-' character is a unary operator
3265  * this method takes for granted that the current character
3266  * is a '+' or '-'.
3267  *
3268  * @return        whether the current '+' or '-' is a unary operator.
3269  */
3270 bool ASFormatter::isUnaryOperator() const
3271 {
3272         assert(currentChar == '+' || currentChar == '-');
3273
3274         return ((isCharImmediatelyPostReturn || !isLegalNameChar(previousCommandChar))
3275                 && previousCommandChar != '.'
3276                 && previousCommandChar != '\"'
3277                 && previousCommandChar != '\''
3278                 && previousCommandChar != ')'
3279                 && previousCommandChar != ']');
3280 }
3281
3282 /**
3283  * check if the currently reached comment is in a 'switch' statement
3284  *
3285  * @return        whether the current '+' or '-' is in an exponent.
3286  */
3287 bool ASFormatter::isInSwitchStatement() const
3288 {
3289         assert(isInLineComment || isInComment);
3290         if (!preBraceHeaderStack->empty())
3291                 for (size_t i = 1; i < preBraceHeaderStack->size(); i++)
3292                         if (preBraceHeaderStack->at(i) == &AS_SWITCH)
3293                                 return true;
3294         return false;
3295 }
3296
3297 /**
3298  * check if the currently reached '+' or '-' character is
3299  * part of an exponent, i.e. 0.2E-5.
3300  *
3301  * @return        whether the current '+' or '-' is in an exponent.
3302  */
3303 bool ASFormatter::isInExponent() const
3304 {
3305         assert(currentChar == '+' || currentChar == '-');
3306
3307         if (charNum >= 2)
3308         {
3309                 char prevPrevFormattedChar = currentLine[charNum - 2];
3310                 char prevFormattedChar = currentLine[charNum - 1];
3311                 return ((prevFormattedChar == 'e' || prevFormattedChar == 'E')
3312                         && (prevPrevFormattedChar == '.' || isDigit(prevPrevFormattedChar)));
3313         }
3314         return false;
3315 }
3316
3317 /**
3318  * check if an array brace should NOT have an in-statement indent
3319  *
3320  * @return        the array is non in-statement
3321  */
3322 bool ASFormatter::isNonInStatementArrayBrace() const
3323 {
3324         bool returnVal = false;
3325         char nextChar = peekNextChar();
3326         // if this opening brace begins the line there will be no inStatement indent
3327         if (currentLineBeginsWithBrace
3328                 && charNum == (int) currentLineFirstBraceNum
3329                 && nextChar != '}')
3330                 returnVal = true;
3331         // if an opening brace ends the line there will be no inStatement indent
3332         if (isWhiteSpace(nextChar)
3333                 || isBeforeAnyLineEndComment(charNum)
3334                 || nextChar == '{')
3335                 returnVal = true;
3336
3337         // Java "new Type [] {...}" IS an inStatement indent
3338         if (isJavaStyle() && previousNonWSChar == ']')
3339                 returnVal = false;
3340
3341         return returnVal;
3342 }
3343
3344 /**
3345  * check if a one-line block has been reached,
3346  * i.e. if the currently reached '{' character is closed
3347  * with a complimentary '}' elsewhere on the current line,
3348  *.
3349  * @return     0 = one-line block has not been reached.
3350  *             1 = one-line block has been reached.
3351  *             2 = one-line block has been reached and is followed by a comma.
3352  *             3 = one-line block has been reached and is an empty block.
3353  */
3354 int ASFormatter::isOneLineBlockReached(const string& line, int startChar) const
3355 {
3356         assert(line[startChar] == '{');
3357
3358         bool isInComment_ = false;
3359         bool isInQuote_ = false;
3360         bool hasText = false;
3361         int braceCount = 0;
3362         int lineLength = line.length();
3363         char quoteChar_ = ' ';
3364         char ch = ' ';
3365         char prevCh = ' ';
3366
3367         for (int i = startChar; i < lineLength; ++i)
3368         {
3369                 ch = line[i];
3370
3371                 if (isInComment_)
3372                 {
3373                         if (line.compare(i, 2, "*/") == 0)
3374                         {
3375                                 isInComment_ = false;
3376                                 ++i;
3377                         }
3378                         continue;
3379                 }
3380
3381                 if (ch == '\\')
3382                 {
3383                         ++i;
3384                         continue;
3385                 }
3386
3387                 if (isInQuote_)
3388                 {
3389                         if (ch == quoteChar_)
3390                                 isInQuote_ = false;
3391                         continue;
3392                 }
3393
3394                 if (ch == '"'
3395                         || (ch == '\'' && !isDigitSeparator(line, i)))
3396                 {
3397                         isInQuote_ = true;
3398                         quoteChar_ = ch;
3399                         continue;
3400                 }
3401
3402                 if (line.compare(i, 2, "//") == 0)
3403                         break;
3404
3405                 if (line.compare(i, 2, "/*") == 0)
3406                 {
3407                         isInComment_ = true;
3408                         ++i;
3409                         continue;
3410                 }
3411
3412                 if (ch == '{')
3413                 {
3414                         ++braceCount;
3415                         continue;
3416                 }
3417                 if (ch == '}')
3418                 {
3419                         --braceCount;
3420                         if (braceCount == 0)
3421                         {
3422                                 // is this an array?
3423                                 if (parenStack->back() == 0 && prevCh != '}')
3424                                 {
3425                                         size_t peekNum = line.find_first_not_of(" \t", i + 1);
3426                                         if (peekNum != string::npos && line[peekNum] == ',')
3427                                                 return 2;
3428                                 }
3429                                 if (!hasText)
3430                                         return 3;       // is an empty block
3431                                 return 1;
3432                         }
3433                 }
3434                 if (ch == ';')
3435                         continue;
3436                 if (!isWhiteSpace(ch))
3437                 {
3438                         hasText = true;
3439                         prevCh = ch;
3440                 }
3441         }
3442
3443         return 0;
3444 }
3445
3446 /**
3447  * peek at the next word to determine if it is a C# non-paren header.
3448  * will look ahead in the input file if necessary.
3449  *
3450  * @param  startChar      position on currentLine to start the search
3451  * @return                true if the next word is get or set.
3452  */
3453 bool ASFormatter::isNextWordSharpNonParenHeader(int startChar) const
3454 {
3455         // look ahead to find the next non-comment text
3456         string nextText = peekNextText(currentLine.substr(startChar));
3457         if (nextText.length() == 0)
3458                 return false;
3459         if (nextText[0] == '[')
3460                 return true;
3461         if (!isCharPotentialHeader(nextText, 0))
3462                 return false;
3463         if (findKeyword(nextText, 0, AS_GET) || findKeyword(nextText, 0, AS_SET)
3464                 || findKeyword(nextText, 0, AS_ADD) || findKeyword(nextText, 0, AS_REMOVE))
3465                 return true;
3466         return false;
3467 }
3468
3469 /**
3470  * peek at the next char to determine if it is an opening brace.
3471  * will look ahead in the input file if necessary.
3472  * this determines a java static constructor.
3473  *
3474  * @param startChar     position on currentLine to start the search
3475  * @return              true if the next word is an opening brace.
3476  */
3477 bool ASFormatter::isNextCharOpeningBrace(int startChar) const
3478 {
3479         bool retVal = false;
3480         string nextText = peekNextText(currentLine.substr(startChar));
3481         if (nextText.length() > 0
3482                 && nextText.compare(0, 1, "{") == 0)
3483                 retVal = true;
3484         return retVal;
3485 }
3486
3487 /**
3488 * Check if operator and, pointer, and reference padding is disabled.
3489 * Disabling is done thru a NOPAD tag in an ending comment.
3490 *
3491 * @return              true if the formatting on this line is disabled.
3492 */
3493 bool ASFormatter::isOperatorPaddingDisabled() const
3494 {
3495         size_t commentStart = currentLine.find("//", charNum);
3496         if (commentStart == string::npos)
3497         {
3498                 commentStart = currentLine.find("/*", charNum);
3499                 // comment must end on this line
3500                 if (commentStart != string::npos)
3501                 {
3502                         size_t commentEnd = currentLine.find("*/", commentStart + 2);
3503                         if (commentEnd == string::npos)
3504                                 commentStart = string::npos;
3505                 }
3506         }
3507         if (commentStart == string::npos)
3508                 return false;
3509         size_t noPadStart = currentLine.find("*NOPAD*", commentStart);
3510         if (noPadStart == string::npos)
3511                 return false;
3512         return true;
3513 }
3514
3515 /**
3516 * Determine if an opening array-type brace should have a leading space pad.
3517 * This is to identify C++11 uniform initializers.
3518 */
3519 bool ASFormatter::isUniformInitializerBrace() const
3520 {
3521         if (isCStyle() && !isInEnum && !isImmediatelyPostPreprocessor)
3522         {
3523                 if (isInClassInitializer
3524                         || isLegalNameChar(previousNonWSChar))
3525                         return true;
3526         }
3527         return false;
3528 }
3529
3530 /**
3531 * Determine if there is a following statement on the current line.
3532 */
3533 bool ASFormatter::isMultiStatementLine() const
3534 {
3535         assert((isImmediatelyPostHeader || foundClosingHeader));
3536         bool isInComment_ = false;
3537         bool isInQuote_ = false;
3538         int  semiCount_ = 0;
3539         int  parenCount_ = 0;
3540         int  braceCount_ = 0;
3541
3542         for (size_t i = 0; i < currentLine.length(); i++)
3543         {
3544                 if (isInComment_)
3545                 {
3546                         if (currentLine.compare(i, 2, "*/") == 0)
3547                         {
3548                                 isInComment_ = false;
3549                                 continue;
3550                         }
3551                 }
3552                 if (currentLine.compare(i, 2, "/*") == 0)
3553                 {
3554                         isInComment_ = true;
3555                         continue;
3556                 }
3557                 if (currentLine.compare(i, 2, "//") == 0)
3558                         return false;
3559                 if (isInQuote_)
3560                 {
3561                         if (currentLine[i] == '"' || currentLine[i] == '\'')
3562                                 isInQuote_ = false;
3563                         continue;
3564                 }
3565                 if (currentLine[i] == '"' || currentLine[i] == '\'')
3566                 {
3567                         isInQuote_ = true;
3568                         continue;
3569                 }
3570                 if (currentLine[i] == '(')
3571                 {
3572                         ++parenCount_;
3573                         continue;
3574                 }
3575                 if (currentLine[i] == ')')
3576                 {
3577                         --parenCount_;
3578                         continue;
3579                 }
3580                 if (parenCount_ > 0)
3581                         continue;
3582                 if (currentLine[i] == '{')
3583                 {
3584                         ++braceCount_;
3585                 }
3586                 if (currentLine[i] == '}')
3587                 {
3588                         --braceCount_;
3589                 }
3590                 if (braceCount_ > 0)
3591                         continue;
3592                 if (currentLine[i] == ';')
3593                 {
3594                         ++semiCount_;
3595                         if (semiCount_ > 1)
3596                                 return true;
3597                         continue;
3598                 }
3599         }
3600         return false;
3601 }
3602
3603 /**
3604  * get the next non-whitespace substring on following lines, bypassing all comments.
3605  *
3606  * @param   firstLine   the first line to check
3607  * @return  the next non-whitespace substring.
3608  */
3609 string ASFormatter::peekNextText(const string& firstLine,
3610                                  bool endOnEmptyLine /*false*/,
3611                                  shared_ptr<ASPeekStream> streamArg /*nullptr*/) const
3612 {
3613         bool isFirstLine = true;
3614         string nextLine_ = firstLine;
3615         size_t firstChar = string::npos;
3616         shared_ptr<ASPeekStream> stream = streamArg;
3617         if (stream == nullptr)                                                  // Borland may need == 0
3618                 stream = make_shared<ASPeekStream>(sourceIterator);
3619
3620         // find the first non-blank text, bypassing all comments.
3621         bool isInComment_ = false;
3622         while (stream->hasMoreLines() || isFirstLine)
3623         {
3624                 if (isFirstLine)
3625                         isFirstLine = false;
3626                 else
3627                         nextLine_ = stream->peekNextLine();
3628
3629                 firstChar = nextLine_.find_first_not_of(" \t");
3630                 if (firstChar == string::npos)
3631                 {
3632                         if (endOnEmptyLine && !isInComment_)
3633                                 break;
3634                         continue;
3635                 }
3636
3637                 if (nextLine_.compare(firstChar, 2, "/*") == 0)
3638                 {
3639                         firstChar += 2;
3640                         isInComment_ = true;
3641                 }
3642
3643                 if (isInComment_)
3644                 {
3645                         firstChar = nextLine_.find("*/", firstChar);
3646                         if (firstChar == string::npos)
3647                                 continue;
3648                         firstChar += 2;
3649                         isInComment_ = false;
3650                         firstChar = nextLine_.find_first_not_of(" \t", firstChar);
3651                         if (firstChar == string::npos)
3652                                 continue;
3653                 }
3654
3655                 if (nextLine_.compare(firstChar, 2, "//") == 0)
3656                         continue;
3657
3658                 // found the next text
3659                 break;
3660         }
3661
3662         if (firstChar == string::npos)
3663                 nextLine_ = "";
3664         else
3665                 nextLine_ = nextLine_.substr(firstChar);
3666         return nextLine_;
3667 }
3668
3669 /**
3670  * adjust comment position because of adding or deleting spaces
3671  * the spaces are added or deleted to formattedLine
3672  * spacePadNum contains the adjustment
3673  */
3674 void ASFormatter::adjustComments()
3675 {
3676         assert(spacePadNum != 0);
3677         assert(isSequenceReached("//") || isSequenceReached("/*"));
3678
3679         // block comment must be closed on this line with nothing after it
3680         if (isSequenceReached("/*"))
3681         {
3682                 size_t endNum = currentLine.find("*/", charNum + 2);
3683                 if (endNum == string::npos)
3684                         return;
3685                 if (currentLine.find_first_not_of(" \t", endNum + 2) != string::npos)
3686                         return;
3687         }
3688
3689         size_t len = formattedLine.length();
3690         // don't adjust a tab
3691         if (formattedLine[len - 1] == '\t')
3692                 return;
3693         // if spaces were removed, need to add spaces before the comment
3694         if (spacePadNum < 0)
3695         {
3696                 int adjust = -spacePadNum;          // make the number positive
3697                 formattedLine.append(adjust, ' ');
3698         }
3699         // if spaces were added, need to delete extra spaces before the comment
3700         // if cannot be done put the comment one space after the last text
3701         else if (spacePadNum > 0)
3702         {
3703                 int adjust = spacePadNum;
3704                 size_t lastText = formattedLine.find_last_not_of(' ');
3705                 if (lastText != string::npos
3706                         && lastText < len - adjust - 1)
3707                         formattedLine.resize(len - adjust);
3708                 else if (len > lastText + 2)
3709                         formattedLine.resize(lastText + 2);
3710                 else if (len < lastText + 2)
3711                         formattedLine.append(len - lastText, ' ');
3712         }
3713 }
3714
3715 /**
3716  * append the current brace inside the end of line comments
3717  * currentChar contains the brace, it will be appended to formattedLine
3718  * formattedLineCommentNum is the comment location on formattedLine
3719  */
3720 void ASFormatter::appendCharInsideComments()
3721 {
3722         if (formattedLineCommentNum == string::npos     // does the comment start on the previous line?
3723                 || formattedLineCommentNum == 0)
3724         {
3725                 appendCurrentChar();                        // don't attach
3726                 return;
3727         }
3728         assert(formattedLine.compare(formattedLineCommentNum, 2, "//") == 0
3729                || formattedLine.compare(formattedLineCommentNum, 2, "/*") == 0);
3730
3731         // find the previous non space char
3732         size_t end = formattedLineCommentNum;
3733         size_t beg = formattedLine.find_last_not_of(" \t", end - 1);
3734         if (beg == string::npos)
3735         {
3736                 appendCurrentChar();                // don't attach
3737                 return;
3738         }
3739         beg++;
3740
3741         // insert the brace
3742         if (end - beg < 3)                      // is there room to insert?
3743                 formattedLine.insert(beg, 3 - end + beg, ' ');
3744         if (formattedLine[beg] == '\t')         // don't pad with a tab
3745                 formattedLine.insert(beg, 1, ' ');
3746         formattedLine[beg + 1] = currentChar;
3747         testForTimeToSplitFormattedLine();
3748
3749         if (isBeforeComment())
3750                 breakLine();
3751         else if (isCharImmediatelyPostLineComment)
3752                 shouldBreakLineAtNextChar = true;
3753 }
3754
3755 /**
3756  * add or remove space padding to operators
3757  * the operators and necessary padding will be appended to formattedLine
3758  * the calling function should have a continue statement after calling this method
3759  *
3760  * @param newOperator     the operator to be padded
3761  */
3762 void ASFormatter::padOperators(const string* newOperator)
3763 {
3764         assert(shouldPadOperators);
3765         assert(newOperator != nullptr);
3766
3767         char nextNonWSChar = ASBase::peekNextChar(currentLine, charNum);
3768         bool shouldPad = (newOperator != &AS_SCOPE_RESOLUTION
3769                           && newOperator != &AS_PLUS_PLUS
3770                           && newOperator != &AS_MINUS_MINUS
3771                           && newOperator != &AS_NOT
3772                           && newOperator != &AS_BIT_NOT
3773                           && newOperator != &AS_ARROW
3774                           && !(newOperator == &AS_COLON && !foundQuestionMark                   // objC methods
3775                                && (isInObjCMethodDefinition || isInObjCInterface
3776                                    || isInObjCSelector || squareBracketCount != 0))
3777                           && !(newOperator == &AS_MINUS && isInExponent())
3778                           && !(newOperator == &AS_PLUS && isInExponent())
3779                           && !((newOperator == &AS_PLUS || newOperator == &AS_MINUS)    // check for unary plus or minus
3780                                && (previousNonWSChar == '('
3781                                    || previousNonWSChar == '['
3782                                    || previousNonWSChar == '='
3783                                    || previousNonWSChar == ','
3784                                    || previousNonWSChar == ':'
3785                                    || previousNonWSChar == '{'))
3786 //?                   // commented out in release 2.05.1 - doesn't seem to do anything???
3787 //x                   && !((newOperator == &AS_MULT || newOperator == &AS_BIT_AND || newOperator == &AS_AND)
3788 //x                        && isPointerOrReference())
3789                           && !(newOperator == &AS_MULT
3790                                && (previousNonWSChar == '.'
3791                                    || previousNonWSChar == '>'))    // check for ->
3792                           && !(newOperator == &AS_MULT && peekNextChar() == '>')
3793                           && !((isInTemplate || isImmediatelyPostTemplate)
3794                                && (newOperator == &AS_LS || newOperator == &AS_GR))
3795                           && !(newOperator == &AS_GCC_MIN_ASSIGN
3796                                && ASBase::peekNextChar(currentLine, charNum + 1) == '>')
3797                           && !(newOperator == &AS_GR && previousNonWSChar == '?')
3798                           && !(newOperator == &AS_QUESTION                      // check for Java wildcard
3799                                && isJavaStyle()
3800                                && (previousNonWSChar == '<'
3801                                    || nextNonWSChar == '>'
3802                                    || nextNonWSChar == '.'))
3803                           && !(newOperator == &AS_QUESTION                      // check for C# null conditional operator
3804                                && isSharpStyle()
3805                                && (nextNonWSChar == '.'
3806                                    || nextNonWSChar == '['))
3807                           && !isCharImmediatelyPostOperator
3808                           && !isInCase
3809                           && !isInAsm
3810                           && !isInAsmOneLine
3811                           && !isInAsmBlock
3812                          );
3813
3814         // pad before operator
3815         if (shouldPad
3816                 && !(newOperator == &AS_COLON
3817                      && (!foundQuestionMark && !isInEnum) && currentHeader != &AS_FOR)
3818                 && !(newOperator == &AS_QUESTION && isSharpStyle() // check for C# nullable type (e.g. int?)
3819                      && currentLine.find(':', charNum + 1) == string::npos)
3820            )
3821                 appendSpacePad();
3822         appendOperator(*newOperator);
3823         goForward(newOperator->length() - 1);
3824
3825         currentChar = (*newOperator)[newOperator->length() - 1];
3826         // pad after operator
3827         // but do not pad after a '-' that is a unary-minus.
3828         if (shouldPad
3829                 && !isBeforeAnyComment()
3830                 && !(newOperator == &AS_PLUS && isUnaryOperator())
3831                 && !(newOperator == &AS_MINUS && isUnaryOperator())
3832                 && !(currentLine.compare(charNum + 1, 1, AS_SEMICOLON) == 0)
3833                 && !(currentLine.compare(charNum + 1, 2, AS_SCOPE_RESOLUTION) == 0)
3834                 && !(peekNextChar() == ',')
3835                 && !(newOperator == &AS_QUESTION && isSharpStyle() // check for C# nullable type (e.g. int?)
3836                      && peekNextChar() == '[')
3837            )
3838                 appendSpaceAfter();
3839 }
3840
3841 /**
3842  * format pointer or reference
3843  * currentChar contains the pointer or reference
3844  * the symbol and necessary padding will be appended to formattedLine
3845  * the calling function should have a continue statement after calling this method
3846  *
3847  * NOTE: Do NOT use appendCurrentChar() in this method. The line should not be
3848  *       broken once the calculation starts.
3849  */
3850 void ASFormatter::formatPointerOrReference()
3851 {
3852         assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
3853         assert(!isJavaStyle());
3854
3855         int pa = pointerAlignment;
3856         int ra = referenceAlignment;
3857         int itemAlignment = (currentChar == '*' || currentChar == '^') ? pa : ((ra == REF_SAME_AS_PTR) ? pa : ra);
3858
3859         // check for ** and &&
3860         int ptrLength = 1;
3861         char peekedChar = peekNextChar();
3862         if ((currentChar == '*' && peekedChar == '*')
3863                 || (currentChar == '&' && peekedChar == '&'))
3864         {
3865                 ptrLength = 2;
3866                 size_t nextChar = currentLine.find_first_not_of(" \t", charNum + 2);
3867                 if (nextChar == string::npos)
3868                         peekedChar = ' ';
3869                 else
3870                         peekedChar = currentLine[nextChar];
3871         }
3872         // check for cast
3873         if (peekedChar == ')' || peekedChar == '>' || peekedChar == ',')
3874         {
3875                 formatPointerOrReferenceCast();
3876                 return;
3877         }
3878
3879         // check for a padded space and remove it
3880         if (charNum > 0
3881                 && !isWhiteSpace(currentLine[charNum - 1])
3882                 && formattedLine.length() > 0
3883                 && isWhiteSpace(formattedLine[formattedLine.length() - 1]))
3884         {
3885                 formattedLine.erase(formattedLine.length() - 1);
3886                 spacePadNum--;
3887         }
3888
3889         if (itemAlignment == PTR_ALIGN_TYPE)
3890         {
3891                 formatPointerOrReferenceToType();
3892         }
3893         else if (itemAlignment == PTR_ALIGN_MIDDLE)
3894         {
3895                 formatPointerOrReferenceToMiddle();
3896         }
3897         else if (itemAlignment == PTR_ALIGN_NAME)
3898         {
3899                 formatPointerOrReferenceToName();
3900         }
3901         else    // pointerAlignment == PTR_ALIGN_NONE
3902         {
3903                 formattedLine.append(ptrLength, currentChar);
3904                 if (ptrLength > 1)
3905                         goForward(ptrLength - 1);
3906         }
3907 }
3908
3909 /**
3910  * format pointer or reference with align to type
3911  */
3912 void ASFormatter::formatPointerOrReferenceToType()
3913 {
3914         assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
3915         assert(!isJavaStyle());
3916
3917         // do this before bumping charNum
3918         bool isOldPRCentered = isPointerOrReferenceCentered();
3919
3920         size_t prevCh = formattedLine.find_last_not_of(" \t");
3921         if (prevCh == string::npos)
3922                 prevCh = 0;
3923         if (formattedLine.length() == 0 || prevCh == formattedLine.length() - 1)
3924                 formattedLine.append(1, currentChar);
3925         else
3926         {
3927                 // exchange * or & with character following the type
3928                 // this may not work every time with a tab character
3929                 string charSave = formattedLine.substr(prevCh + 1, 1);
3930                 formattedLine[prevCh + 1] = currentChar;
3931                 formattedLine.append(charSave);
3932         }
3933         if (isSequenceReached("**") || isSequenceReached("&&"))
3934         {
3935                 if (formattedLine.length() == 1)
3936                         formattedLine.append(1, currentChar);
3937                 else
3938                         formattedLine.insert(prevCh + 2, 1, currentChar);
3939                 goForward(1);
3940         }
3941         // if no space after then add one
3942         if (charNum < (int) currentLine.length() - 1
3943                 && !isWhiteSpace(currentLine[charNum + 1])
3944                 && currentLine[charNum + 1] != ')')
3945                 appendSpacePad();
3946         // if old pointer or reference is centered, remove a space
3947         if (isOldPRCentered
3948                 && isWhiteSpace(formattedLine[formattedLine.length() - 1]))
3949         {
3950                 formattedLine.erase(formattedLine.length() - 1, 1);
3951                 spacePadNum--;
3952         }
3953         // update the formattedLine split point
3954         if (maxCodeLength != string::npos)
3955         {
3956                 size_t index = formattedLine.length() - 1;
3957                 if (isWhiteSpace(formattedLine[index]))
3958                 {
3959                         updateFormattedLineSplitPointsPointerOrReference(index);
3960                         testForTimeToSplitFormattedLine();
3961                 }
3962         }
3963 }
3964
3965 /**
3966  * format pointer or reference with align in the middle
3967  */
3968 void ASFormatter::formatPointerOrReferenceToMiddle()
3969 {
3970         assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
3971         assert(!isJavaStyle());
3972
3973         // compute current whitespace before
3974         size_t wsBefore = currentLine.find_last_not_of(" \t", charNum - 1);
3975         if (wsBefore == string::npos)
3976                 wsBefore = 0;
3977         else
3978                 wsBefore = charNum - wsBefore - 1;
3979         string sequenceToInsert(1, currentChar);
3980         if (isSequenceReached("**"))
3981         {
3982                 sequenceToInsert = "**";
3983                 goForward(1);
3984         }
3985         else if (isSequenceReached("&&"))
3986         {
3987                 sequenceToInsert = "&&";
3988                 goForward(1);
3989         }
3990         // if reference to a pointer check for conflicting alignment
3991         else if (currentChar == '*' && peekNextChar() == '&'
3992                  && (referenceAlignment == REF_ALIGN_TYPE
3993                      || referenceAlignment == REF_ALIGN_MIDDLE
3994                      || referenceAlignment == REF_SAME_AS_PTR))
3995         {
3996                 sequenceToInsert = "*&";
3997                 goForward(1);
3998                 for (size_t i = charNum; i < currentLine.length() - 1 && isWhiteSpace(currentLine[i]); i++)
3999                         goForward(1);
4000         }
4001         // if a comment follows don't align, just space pad
4002         if (isBeforeAnyComment())
4003         {
4004                 appendSpacePad();
4005                 formattedLine.append(sequenceToInsert);
4006                 appendSpaceAfter();
4007                 return;
4008         }
4009         // do this before goForward()
4010         bool isAfterScopeResolution = previousNonWSChar == ':';
4011         size_t charNumSave = charNum;
4012         // if this is the last thing on the line
4013         if (currentLine.find_first_not_of(" \t", charNum + 1) == string::npos)
4014         {
4015                 if (wsBefore == 0 && !isAfterScopeResolution)
4016                         formattedLine.append(1, ' ');
4017                 formattedLine.append(sequenceToInsert);
4018                 return;
4019         }
4020         // goForward() to convert tabs to spaces, if necessary,
4021         // and move following characters to preceding characters
4022         // this may not work every time with tab characters
4023         for (size_t i = charNum + 1; i < currentLine.length() && isWhiteSpace(currentLine[i]); i++)
4024         {
4025                 goForward(1);
4026                 if (formattedLine.length() > 0)
4027                         formattedLine.append(1, currentLine[i]);
4028                 else
4029                         spacePadNum--;
4030         }
4031         // find space padding after
4032         size_t wsAfter = currentLine.find_first_not_of(" \t", charNumSave + 1);
4033         if (wsAfter == string::npos || isBeforeAnyComment())
4034                 wsAfter = 0;
4035         else
4036                 wsAfter = wsAfter - charNumSave - 1;
4037         // don't pad before scope resolution operator, but pad after
4038         if (isAfterScopeResolution)
4039         {
4040                 size_t lastText = formattedLine.find_last_not_of(" \t");
4041                 formattedLine.insert(lastText + 1, sequenceToInsert);
4042                 appendSpacePad();
4043         }
4044         else if (formattedLine.length() > 0)
4045         {
4046                 // whitespace should be at least 2 chars to center
4047                 if (wsBefore + wsAfter < 2)
4048                 {
4049                         size_t charsToAppend = (2 - (wsBefore + wsAfter));
4050                         formattedLine.append(charsToAppend, ' ');
4051                         spacePadNum += charsToAppend;
4052                         if (wsBefore == 0)
4053                                 wsBefore++;
4054                         if (wsAfter == 0)
4055                                 wsAfter++;
4056                 }
4057                 // insert the pointer or reference char
4058                 size_t padAfter = (wsBefore + wsAfter) / 2;
4059                 size_t index = formattedLine.length() - padAfter;
4060                 formattedLine.insert(index, sequenceToInsert);
4061         }
4062         else    // formattedLine.length() == 0
4063         {
4064                 formattedLine.append(sequenceToInsert);
4065                 if (wsAfter == 0)
4066                         wsAfter++;
4067                 formattedLine.append(wsAfter, ' ');
4068                 spacePadNum += wsAfter;
4069         }
4070         // update the formattedLine split point after the pointer
4071         if (maxCodeLength != string::npos && formattedLine.length() > 0)
4072         {
4073                 size_t index = formattedLine.find_last_not_of(" \t");
4074                 if (index != string::npos && (index < formattedLine.length() - 1))
4075                 {
4076                         index++;
4077                         updateFormattedLineSplitPointsPointerOrReference(index);
4078                         testForTimeToSplitFormattedLine();
4079                 }
4080         }
4081 }
4082
4083 /**
4084  * format pointer or reference with align to name
4085  */
4086 void ASFormatter::formatPointerOrReferenceToName()
4087 {
4088         assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
4089         assert(!isJavaStyle());
4090
4091         // do this before bumping charNum
4092         bool isOldPRCentered = isPointerOrReferenceCentered();
4093
4094         size_t startNum = formattedLine.find_last_not_of(" \t");
4095         if (startNum == string::npos)
4096                 startNum = 0;
4097         string sequenceToInsert(1, currentChar);
4098         if (isSequenceReached("**"))
4099         {
4100                 sequenceToInsert = "**";
4101                 goForward(1);
4102         }
4103         else if (isSequenceReached("&&"))
4104         {
4105                 sequenceToInsert = "&&";
4106                 goForward(1);
4107         }
4108         // if reference to a pointer align both to name
4109         else if (currentChar == '*' && peekNextChar() == '&')
4110         {
4111                 sequenceToInsert = "*&";
4112                 goForward(1);
4113                 for (size_t i = charNum; i < currentLine.length() - 1 && isWhiteSpace(currentLine[i]); i++)
4114                         goForward(1);
4115         }
4116         char peekedChar = peekNextChar();
4117         bool isAfterScopeResolution = previousNonWSChar == ':';         // check for ::
4118         // if this is not the last thing on the line
4119         if (!isBeforeAnyComment()
4120                 && (int) currentLine.find_first_not_of(" \t", charNum + 1) > charNum)
4121         {
4122                 // goForward() to convert tabs to spaces, if necessary,
4123                 // and move following characters to preceding characters
4124                 // this may not work every time with tab characters
4125                 for (size_t i = charNum + 1; i < currentLine.length() && isWhiteSpace(currentLine[i]); i++)
4126                 {
4127                         // if a padded paren follows don't move
4128                         if (shouldPadParensOutside && peekedChar == '(' && !isOldPRCentered)
4129                         {
4130                                 // empty parens don't count
4131                                 size_t start = currentLine.find_first_not_of("( \t", charNum + 1);
4132                                 if (start != string::npos && currentLine[start] != ')')
4133                                         break;
4134                         }
4135                         goForward(1);
4136                         if (formattedLine.length() > 0)
4137                                 formattedLine.append(1, currentLine[i]);
4138                         else
4139                                 spacePadNum--;
4140                 }
4141         }
4142         // don't pad before scope resolution operator
4143         if (isAfterScopeResolution)
4144         {
4145                 size_t lastText = formattedLine.find_last_not_of(" \t");
4146                 if (lastText != string::npos && lastText + 1 < formattedLine.length())
4147                         formattedLine.erase(lastText + 1);
4148         }
4149         // if no space before * then add one
4150         else if (formattedLine.length() > 0
4151                  && (formattedLine.length() <= startNum + 1
4152                      || !isWhiteSpace(formattedLine[startNum + 1])))
4153         {
4154                 formattedLine.insert(startNum + 1, 1, ' ');
4155                 spacePadNum++;
4156         }
4157         appendSequence(sequenceToInsert, false);
4158         // if old pointer or reference is centered, remove a space
4159         if (isOldPRCentered
4160                 && formattedLine.length() > startNum + 1
4161                 && isWhiteSpace(formattedLine[startNum + 1])
4162                 && !isBeforeAnyComment())
4163         {
4164                 formattedLine.erase(startNum + 1, 1);
4165                 spacePadNum--;
4166         }
4167         // don't convert to *= or &=
4168         if (peekedChar == '=')
4169         {
4170                 appendSpaceAfter();
4171                 // if more than one space before, delete one
4172                 if (formattedLine.length() > startNum
4173                         && isWhiteSpace(formattedLine[startNum + 1])
4174                         && isWhiteSpace(formattedLine[startNum + 2]))
4175                 {
4176                         formattedLine.erase(startNum + 1, 1);
4177                         spacePadNum--;
4178                 }
4179         }
4180         // update the formattedLine split point
4181         if (maxCodeLength != string::npos)
4182         {
4183                 size_t index = formattedLine.find_last_of(" \t");
4184                 if (index != string::npos
4185                         && index < formattedLine.length() - 1
4186                         && (formattedLine[index + 1] == '*'
4187                             || formattedLine[index + 1] == '&'
4188                             || formattedLine[index + 1] == '^'))
4189                 {
4190                         updateFormattedLineSplitPointsPointerOrReference(index);
4191                         testForTimeToSplitFormattedLine();
4192                 }
4193         }
4194 }
4195
4196 /**
4197  * format pointer or reference cast
4198  * currentChar contains the pointer or reference
4199  * NOTE: the pointers and references in function definitions
4200  *       are processed as a cast (e.g. void foo(void*, void*))
4201  *       is processed here.
4202  */
4203 void ASFormatter::formatPointerOrReferenceCast()
4204 {
4205         assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
4206         assert(!isJavaStyle());
4207
4208         int pa = pointerAlignment;
4209         int ra = referenceAlignment;
4210         int itemAlignment = (currentChar == '*' || currentChar == '^') ? pa : ((ra == REF_SAME_AS_PTR) ? pa : ra);
4211
4212         string sequenceToInsert(1, currentChar);
4213         if (isSequenceReached("**") || isSequenceReached("&&"))
4214         {
4215                 goForward(1);
4216                 sequenceToInsert.append(1, currentLine[charNum]);
4217         }
4218         if (itemAlignment == PTR_ALIGN_NONE)
4219         {
4220                 appendSequence(sequenceToInsert, false);
4221                 return;
4222         }
4223         // remove preceding whitespace
4224         char prevCh = ' ';
4225         size_t prevNum = formattedLine.find_last_not_of(" \t");
4226         if (prevNum != string::npos)
4227         {
4228                 prevCh = formattedLine[prevNum];
4229                 if (prevNum + 1 < formattedLine.length()
4230                         && isWhiteSpace(formattedLine[prevNum + 1])
4231                         && prevCh != '(')
4232                 {
4233                         spacePadNum -= (formattedLine.length() - 1 - prevNum);
4234                         formattedLine.erase(prevNum + 1);
4235                 }
4236         }
4237         bool isAfterScopeResolution = previousNonWSChar == ':';
4238         if ((itemAlignment == PTR_ALIGN_MIDDLE || itemAlignment == PTR_ALIGN_NAME)
4239                 && !isAfterScopeResolution && prevCh != '(')
4240         {
4241                 appendSpacePad();
4242                 // in this case appendSpacePad may or may not update the split point
4243                 if (maxCodeLength != string::npos && formattedLine.length() > 0)
4244                         updateFormattedLineSplitPointsPointerOrReference(formattedLine.length() - 1);
4245                 appendSequence(sequenceToInsert, false);
4246         }
4247         else
4248                 appendSequence(sequenceToInsert, false);
4249 }
4250
4251 /**
4252  * add or remove space padding to parens
4253  * currentChar contains the paren
4254  * the parens and necessary padding will be appended to formattedLine
4255  * the calling function should have a continue statement after calling this method
4256  */
4257 void ASFormatter::padParens()
4258 {
4259         assert(currentChar == '(' || currentChar == ')');
4260         assert(shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens || shouldPadFirstParen);
4261
4262         int spacesOutsideToDelete = 0;
4263         int spacesInsideToDelete = 0;
4264
4265         if (currentChar == '(')
4266         {
4267                 spacesOutsideToDelete = formattedLine.length() - 1;
4268                 spacesInsideToDelete = 0;
4269
4270                 // compute spaces outside the opening paren to delete
4271                 if (shouldUnPadParens)
4272                 {
4273                         char lastChar = ' ';
4274                         bool prevIsParenHeader = false;
4275                         size_t i = formattedLine.find_last_not_of(" \t");
4276                         if (i != string::npos)
4277                         {
4278                                 // if last char is a brace the previous whitespace is an indent
4279                                 if (formattedLine[i] == '{')
4280                                         spacesOutsideToDelete = 0;
4281                                 else if (isCharImmediatelyPostPointerOrReference)
4282                                         spacesOutsideToDelete = 0;
4283                                 else
4284                                 {
4285                                         spacesOutsideToDelete -= i;
4286                                         lastChar = formattedLine[i];
4287                                         // if previous word is a header, it will be a paren header
4288                                         string prevWord = getPreviousWord(formattedLine, formattedLine.length());
4289                                         const string* prevWordH = nullptr;
4290                                         if (shouldPadHeader
4291                                                 && prevWord.length() > 0
4292                                                 && isCharPotentialHeader(prevWord, 0))
4293                                                 prevWordH = ASBase::findHeader(prevWord, 0, headers);
4294                                         if (prevWordH != nullptr)
4295                                                 prevIsParenHeader = true;
4296                                         else if (prevWord == AS_RETURN)  // don't unpad
4297                                                 prevIsParenHeader = true;
4298                                         else if ((prevWord == AS_NEW || prevWord == AS_DELETE)
4299                                                  && shouldPadHeader)  // don't unpad
4300                                                 prevIsParenHeader = true;
4301                                         else if (isCStyle() && prevWord == AS_THROW && shouldPadHeader) // don't unpad
4302                                                 prevIsParenHeader = true;
4303                                         else if (prevWord == "and" || prevWord == "or" || prevWord == "in")  // don't unpad
4304                                                 prevIsParenHeader = true;
4305                                         // don't unpad variables
4306                                         else if (prevWord == "bool"
4307                                                  || prevWord == "int"
4308                                                  || prevWord == "void"
4309                                                  || prevWord == "void*"
4310                                                  || prevWord == "char"
4311                                                  || prevWord == "char*"
4312                                                  || prevWord == "long"
4313                                                  || prevWord == "double"
4314                                                  || prevWord == "float"
4315                                                  || (prevWord.length() >= 4     // check end of word for _t
4316                                                      && prevWord.compare(prevWord.length() - 2, 2, "_t") == 0)
4317                                                  || prevWord == "Int32"
4318                                                  || prevWord == "UInt32"
4319                                                  || prevWord == "Int64"
4320                                                  || prevWord == "UInt64"
4321                                                  || prevWord == "BOOL"
4322                                                  || prevWord == "DWORD"
4323                                                  || prevWord == "HWND"
4324                                                  || prevWord == "INT"
4325                                                  || prevWord == "LPSTR"
4326                                                  || prevWord == "VOID"
4327                                                  || prevWord == "LPVOID"
4328                                                 )
4329                                         {
4330                                                 prevIsParenHeader = true;
4331                                         }
4332                                 }
4333                         }
4334                         // do not unpad operators, but leave them if already padded
4335                         if (shouldPadParensOutside || prevIsParenHeader)
4336                                 spacesOutsideToDelete--;
4337                         else if (lastChar == '|'          // check for ||
4338                                  || lastChar == '&'       // check for &&
4339                                  || lastChar == ','
4340                                  || (lastChar == '(' && shouldPadParensInside)
4341                                  || (lastChar == '>' && !foundCastOperator)
4342                                  || lastChar == '<'
4343                                  || lastChar == '?'
4344                                  || lastChar == ':'
4345                                  || lastChar == ';'
4346                                  || lastChar == '='
4347                                  || lastChar == '+'
4348                                  || lastChar == '-'
4349                                  || lastChar == '*'
4350                                  || lastChar == '/'
4351                                  || lastChar == '%'
4352                                  || lastChar == '^'
4353                                 )
4354                                 spacesOutsideToDelete--;
4355
4356                         if (spacesOutsideToDelete > 0)
4357                         {
4358                                 formattedLine.erase(i + 1, spacesOutsideToDelete);
4359                                 spacePadNum -= spacesOutsideToDelete;
4360                         }
4361                 }
4362
4363                 // pad open paren outside
4364                 char peekedCharOutside = peekNextChar();
4365                 if (shouldPadFirstParen && previousChar != '(' && peekedCharOutside != ')')
4366                         appendSpacePad();
4367                 else if (shouldPadParensOutside)
4368                 {
4369                         if (!(currentChar == '(' && peekedCharOutside == ')'))
4370                                 appendSpacePad();
4371                 }
4372
4373                 appendCurrentChar();
4374
4375                 // unpad open paren inside
4376                 if (shouldUnPadParens)
4377                 {
4378                         size_t j = currentLine.find_first_not_of(" \t", charNum + 1);
4379                         if (j != string::npos)
4380                                 spacesInsideToDelete = j - charNum - 1;
4381                         if (shouldPadParensInside)
4382                                 spacesInsideToDelete--;
4383                         if (spacesInsideToDelete > 0)
4384                         {
4385                                 currentLine.erase(charNum + 1, spacesInsideToDelete);
4386                                 spacePadNum -= spacesInsideToDelete;
4387                         }
4388                         // convert tab to space if requested
4389                         if (shouldConvertTabs
4390                                 && (int) currentLine.length() > charNum + 1
4391                                 && currentLine[charNum + 1] == '\t')
4392                                 currentLine[charNum + 1] = ' ';
4393                 }
4394
4395                 // pad open paren inside
4396                 char peekedCharInside = peekNextChar();
4397                 if (shouldPadParensInside)
4398                         if (!(currentChar == '(' && peekedCharInside == ')'))
4399                                 appendSpaceAfter();
4400         }
4401         else if (currentChar == ')')
4402         {
4403                 // unpad close paren inside
4404                 if (shouldUnPadParens)
4405                 {
4406                         spacesInsideToDelete = formattedLine.length();
4407                         size_t i = formattedLine.find_last_not_of(" \t");
4408                         if (i != string::npos)
4409                                 spacesInsideToDelete = formattedLine.length() - 1 - i;
4410                         if (shouldPadParensInside)
4411                                 spacesInsideToDelete--;
4412                         if (spacesInsideToDelete > 0)
4413                         {
4414                                 formattedLine.erase(i + 1, spacesInsideToDelete);
4415                                 spacePadNum -= spacesInsideToDelete;
4416                         }
4417                 }
4418
4419                 // pad close paren inside
4420                 if (shouldPadParensInside)
4421                         if (!(previousChar == '(' && currentChar == ')'))
4422                                 appendSpacePad();
4423
4424                 appendCurrentChar();
4425
4426                 // unpad close paren outside
4427                 // close parens outside are left unchanged
4428                 if (shouldUnPadParens)
4429                 {
4430                         //spacesOutsideToDelete = 0;
4431                         //size_t j = currentLine.find_first_not_of(" \t", charNum + 1);
4432                         //if (j != string::npos)
4433                         //      spacesOutsideToDelete = j - charNum - 1;
4434                         //if (shouldPadParensOutside)
4435                         //      spacesOutsideToDelete--;
4436
4437                         //if (spacesOutsideToDelete > 0)
4438                         //{
4439                         //      currentLine.erase(charNum + 1, spacesOutsideToDelete);
4440                         //      spacePadNum -= spacesOutsideToDelete;
4441                         //}
4442                 }
4443
4444                 // pad close paren outside
4445                 char peekedCharOutside = peekNextChar();
4446                 if (shouldPadParensOutside)
4447                         if (peekedCharOutside != ';'
4448                                 && peekedCharOutside != ','
4449                                 && peekedCharOutside != '.'
4450                                 && peekedCharOutside != '+'    // check for ++
4451                                 && peekedCharOutside != '-'    // check for --
4452                                 && peekedCharOutside != ']')
4453                                 appendSpaceAfter();
4454         }
4455 }
4456
4457 /**
4458 * add or remove space padding to objective-c parens
4459 * these options have precedence over the padParens methods
4460 * the padParens method has already been called, this method adjusts
4461 */
4462 void ASFormatter::padObjCMethodPrefix()
4463 {
4464         assert(currentChar == '(' && isImmediatelyPostObjCMethodPrefix);
4465         assert(shouldPadMethodPrefix || shouldUnPadMethodPrefix);
4466
4467         size_t prefix = formattedLine.find_first_of("+-");
4468         if (prefix == string::npos)
4469                 return;
4470         size_t paren = formattedLine.find_first_of('(');
4471         if (paren == string::npos)
4472                 return;
4473         int spaces = paren - prefix - 1;
4474
4475         if (shouldPadMethodPrefix)
4476         {
4477                 if (spaces == 0)
4478                 {
4479                         formattedLine.insert(prefix + 1, 1, ' ');
4480                         spacePadNum += 1;
4481                 }
4482                 else if (spaces > 1)
4483                 {
4484                         formattedLine.erase(prefix + 1, spaces - 1);
4485                         spacePadNum -= spaces - 1;
4486                 }
4487         }
4488         // this option will be ignored if used with pad-method-prefix
4489         else if (shouldUnPadMethodPrefix)
4490         {
4491                 if (spaces > 0)
4492                 {
4493                         formattedLine.erase(prefix + 1, spaces);
4494                         spacePadNum -= spaces;
4495                 }
4496         }
4497 }
4498
4499 /**
4500 * add or remove space padding to objective-c parens
4501 * these options have precedence over the padParens methods
4502 * the padParens method has already been called, this method adjusts
4503 */
4504 void ASFormatter::padObjCReturnType()
4505 {
4506         assert(currentChar == ')' && isInObjCReturnType);
4507         assert(shouldPadReturnType || shouldUnPadReturnType);
4508
4509         size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
4510         if (nextText == string::npos)
4511                 return;
4512         int spaces = nextText - charNum - 1;
4513
4514         if (shouldPadReturnType)
4515         {
4516                 if (spaces == 0)
4517                 {
4518                         // this will already be padded if pad-paren is used
4519                         if (formattedLine[formattedLine.length() - 1] != ' ')
4520                         {
4521                                 formattedLine.append(" ");
4522                                 spacePadNum += 1;
4523                         }
4524                 }
4525                 else if (spaces > 1)
4526                 {
4527                         // do not use goForward here
4528                         currentLine.erase(charNum + 1, spaces - 1);
4529                         spacePadNum -= spaces - 1;
4530                 }
4531         }
4532         // this option will be ignored if used with pad-return-type
4533         else if (shouldUnPadReturnType)
4534         {
4535                 // this will already be padded if pad-paren is used
4536                 if (formattedLine[formattedLine.length() - 1] == ' ')
4537                 {
4538                         spacePadNum -= formattedLine.length() - 1 - nextText;
4539                         int lastText = formattedLine.find_last_not_of(" \t");
4540                         formattedLine.resize(lastText + 1);
4541                 }
4542                 if (spaces > 0)
4543                 {
4544                         // do not use goForward here
4545                         currentLine.erase(charNum + 1, spaces);
4546                         spacePadNum -= spaces;
4547                 }
4548         }
4549 }
4550
4551 /**
4552 * add or remove space padding to objective-c parens
4553 * these options have precedence over the padParens methods
4554 * the padParens method has already been called, this method adjusts
4555 */
4556 void ASFormatter::padObjCParamType()
4557 {
4558         assert((currentChar == '(' || currentChar == ')') && isInObjCMethodDefinition);
4559         assert(!isImmediatelyPostObjCMethodPrefix && !isInObjCReturnType);
4560         assert(shouldPadParamType || shouldUnPadParamType);
4561
4562         if (currentChar == '(')
4563         {
4564                 // open paren has already been attached to formattedLine by padParen
4565                 size_t paramOpen = formattedLine.rfind('(');
4566                 assert(paramOpen != string::npos);
4567                 size_t prevText = formattedLine.find_last_not_of(" \t", paramOpen - 1);
4568                 if (prevText == string::npos)
4569                         return;
4570                 int spaces = paramOpen - prevText - 1;
4571
4572                 if (shouldPadParamType
4573                         || objCColonPadMode == COLON_PAD_ALL
4574                         || objCColonPadMode == COLON_PAD_AFTER)
4575                 {
4576                         if (spaces == 0)
4577                         {
4578                                 formattedLine.insert(paramOpen, 1, ' ');
4579                                 spacePadNum += 1;
4580                         }
4581                         if (spaces > 1)
4582                         {
4583                                 formattedLine.erase(prevText + 1, spaces - 1);
4584                                 spacePadNum -= spaces - 1;
4585                         }
4586                 }
4587                 // this option will be ignored if used with pad-param-type
4588                 else if (shouldUnPadParamType
4589                          || objCColonPadMode == COLON_PAD_NONE
4590                          || objCColonPadMode == COLON_PAD_BEFORE)
4591                 {
4592                         if (spaces > 0)
4593                         {
4594                                 formattedLine.erase(prevText + 1, spaces);
4595                                 spacePadNum -= spaces;
4596                         }
4597                 }
4598         }
4599         else if (currentChar == ')')
4600         {
4601                 size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
4602                 if (nextText == string::npos)
4603                         return;
4604                 int spaces = nextText - charNum - 1;
4605
4606                 if (shouldPadParamType)
4607                 {
4608                         if (spaces == 0)
4609                         {
4610                                 // this will already be padded if pad-paren is used
4611                                 if (formattedLine[formattedLine.length() - 1] != ' ')
4612                                 {
4613                                         formattedLine.append(" ");
4614                                         spacePadNum += 1;
4615                                 }
4616                         }
4617                         else if (spaces > 1)
4618                         {
4619                                 // do not use goForward here
4620                                 currentLine.erase(charNum + 1, spaces - 1);
4621                                 spacePadNum -= spaces - 1;
4622                         }
4623                 }
4624                 // this option will be ignored if used with pad-param-type
4625                 else if (shouldUnPadParamType)
4626                 {
4627                         // this will already be padded if pad-paren is used
4628                         if (formattedLine[formattedLine.length() - 1] == ' ')
4629                         {
4630                                 spacePadNum -= 1;
4631                                 int lastText = formattedLine.find_last_not_of(" \t");
4632                                 formattedLine.resize(lastText + 1);
4633                         }
4634                         if (spaces > 0)
4635                         {
4636                                 // do not use goForward here
4637                                 currentLine.erase(charNum + 1, spaces);
4638                                 spacePadNum -= spaces;
4639                         }
4640                 }
4641         }
4642 }
4643
4644 /**
4645  * format opening brace as attached or broken
4646  * currentChar contains the brace
4647  * the braces will be appended to the current formattedLine or a new formattedLine as necessary
4648  * the calling function should have a continue statement after calling this method
4649  *
4650  * @param braceType    the type of brace to be formatted.
4651  */
4652 void ASFormatter::formatOpeningBrace(BraceType braceType)
4653 {
4654         assert(!isBraceType(braceType, ARRAY_TYPE));
4655         assert(currentChar == '{');
4656
4657         parenStack->emplace_back(0);
4658
4659         bool breakBrace = isCurrentBraceBroken();
4660
4661         if (breakBrace)
4662         {
4663                 if (isBeforeAnyComment() && isOkToBreakBlock(braceType))
4664                 {
4665                         // if comment is at line end leave the comment on this line
4666                         if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace)
4667                         {
4668                                 currentChar = ' ';              // remove brace from current line
4669                                 if (parenStack->size() > 1)
4670                                         parenStack->pop_back();
4671                                 currentLine[charNum] = currentChar;
4672                                 appendOpeningBrace = true;      // append brace to following line
4673                         }
4674                         // else put comment after the brace
4675                         else if (!isBeforeMultipleLineEndComments(charNum))
4676                                 breakLine();
4677                 }
4678                 else if (!isBraceType(braceType, SINGLE_LINE_TYPE))
4679                 {
4680                         formattedLine = rtrim(formattedLine);
4681                         breakLine();
4682                 }
4683                 else if ((shouldBreakOneLineBlocks || isBraceType(braceType, BREAK_BLOCK_TYPE))
4684                          && !isBraceType(braceType, EMPTY_BLOCK_TYPE))
4685                         breakLine();
4686                 else if (!isInLineBreak)
4687                         appendSpacePad();
4688
4689                 appendCurrentChar();
4690
4691                 // should a following comment break from the brace?
4692                 // must break the line AFTER the brace
4693                 if (isBeforeComment()
4694                         && formattedLine.length() > 0
4695                         && formattedLine[0] == '{'
4696                         && isOkToBreakBlock(braceType)
4697                         && (braceFormatMode == BREAK_MODE
4698                             || braceFormatMode == LINUX_MODE))
4699                 {
4700                         shouldBreakLineAtNextChar = true;
4701                 }
4702         }
4703         else    // attach brace
4704         {
4705                 // are there comments before the brace?
4706                 if (isCharImmediatelyPostComment || isCharImmediatelyPostLineComment)
4707                 {
4708                         if (isOkToBreakBlock(braceType)
4709                                 && !(isCharImmediatelyPostComment && isCharImmediatelyPostLineComment)  // don't attach if two comments on the line
4710                                 && !isImmediatelyPostPreprocessor
4711 //                              && peekNextChar() != '}'                // don't attach { }             // removed release 2.03
4712                                 && previousCommandChar != '{'   // don't attach { {
4713                                 && previousCommandChar != '}'   // don't attach } {
4714                                 && previousCommandChar != ';')  // don't attach ; {
4715                         {
4716                                 appendCharInsideComments();
4717                         }
4718                         else
4719                         {
4720                                 appendCurrentChar();                            // don't attach
4721                         }
4722                 }
4723                 else if (previousCommandChar == '{'
4724                          || (previousCommandChar == '}' && !isInClassInitializer)
4725                          || previousCommandChar == ';')         // '}' , ';' chars added for proper handling of '{' immediately after a '}' or ';'
4726                 {
4727                         appendCurrentChar();                                    // don't attach
4728                 }
4729                 else
4730                 {
4731                         // if a blank line precedes this don't attach
4732                         if (isEmptyLine(formattedLine))
4733                                 appendCurrentChar();                            // don't attach
4734                         else if (isOkToBreakBlock(braceType)
4735                                  && !(isImmediatelyPostPreprocessor
4736                                       && currentLineBeginsWithBrace))
4737                         {
4738                                 if (!isBraceType(braceType, EMPTY_BLOCK_TYPE))
4739                                 {
4740                                         appendSpacePad();
4741                                         appendCurrentChar(false);                               // OK to attach
4742                                         testForTimeToSplitFormattedLine();              // line length will have changed
4743                                         // should a following comment attach with the brace?
4744                                         // insert spaces to reposition the comment
4745                                         if (isBeforeComment()
4746                                                 && !isBeforeMultipleLineEndComments(charNum)
4747                                                 && (!isBeforeAnyLineEndComment(charNum) || currentLineBeginsWithBrace))
4748                                         {
4749                                                 shouldBreakLineAtNextChar = true;
4750                                                 currentLine.insert(charNum + 1, charNum + 1, ' ');
4751                                         }
4752                                         else if (!isBeforeAnyComment())         // added in release 2.03
4753                                         {
4754                                                 shouldBreakLineAtNextChar = true;
4755                                         }
4756                                 }
4757                                 else
4758                                 {
4759                                         if (currentLineBeginsWithBrace && charNum == (int) currentLineFirstBraceNum)
4760                                         {
4761                                                 appendSpacePad();
4762                                                 appendCurrentChar(false);               // attach
4763                                                 shouldBreakLineAtNextChar = true;
4764                                         }
4765                                         else
4766                                         {
4767                                                 appendSpacePad();
4768                                                 appendCurrentChar();            // don't attach
4769                                         }
4770                                 }
4771                         }
4772                         else
4773                         {
4774                                 if (!isInLineBreak)
4775                                         appendSpacePad();
4776                                 appendCurrentChar();                            // don't attach
4777                         }
4778                 }
4779         }
4780 }
4781
4782 /**
4783  * format closing brace
4784  * currentChar contains the brace
4785  * the calling function should have a continue statement after calling this method
4786  *
4787  * @param braceType    the type of the opening brace for this closing brace.
4788  */
4789 void ASFormatter::formatClosingBrace(BraceType braceType)
4790 {
4791         assert(!isBraceType(braceType, ARRAY_TYPE));
4792         assert(currentChar == '}');
4793
4794         // parenStack must contain one entry
4795         if (parenStack->size() > 1)
4796                 parenStack->pop_back();
4797
4798         // mark state of immediately after empty block
4799         // this state will be used for locating braces that appear immediately AFTER an empty block (e.g. '{} \n}').
4800         if (previousCommandChar == '{')
4801                 isImmediatelyPostEmptyBlock = true;
4802
4803         if (attachClosingBraceMode)
4804         {
4805                 // for now, namespaces and classes will be attached. Uncomment the lines below to break.
4806                 if ((isEmptyLine(formattedLine)                 // if a blank line precedes this
4807                         || isCharImmediatelyPostLineComment
4808                         || isCharImmediatelyPostComment
4809                         || (isImmediatelyPostPreprocessor && (int) currentLine.find_first_not_of(" \t") == charNum)
4810 //                      || (isBraceType(braceType, CLASS_TYPE) && isOkToBreakBlock(braceType) && previousNonWSChar != '{')
4811 //                      || (isBraceType(braceType, NAMESPACE_TYPE) && isOkToBreakBlock(braceType) && previousNonWSChar != '{')
4812                     )
4813                         && (!isBraceType(braceType, SINGLE_LINE_TYPE) || isOkToBreakBlock(braceType)))
4814                 {
4815                         breakLine();
4816                         appendCurrentChar();                            // don't attach
4817                 }
4818                 else
4819                 {
4820                         if (previousNonWSChar != '{'
4821                                 && (!isBraceType(braceType, SINGLE_LINE_TYPE)
4822                                     || isOkToBreakBlock(braceType)))
4823                                 appendSpacePad();
4824                         appendCurrentChar(false);                       // attach
4825                 }
4826         }
4827         else if (!isBraceType(braceType, EMPTY_BLOCK_TYPE)
4828                  && (isBraceType(braceType, BREAK_BLOCK_TYPE)
4829                      || isOkToBreakBlock(braceType)))
4830         {
4831                 breakLine();
4832                 appendCurrentChar();
4833         }
4834         else
4835         {
4836                 appendCurrentChar();
4837         }
4838
4839         // if a declaration follows a definition, space pad
4840         if (isLegalNameChar(peekNextChar()))
4841                 appendSpaceAfter();
4842
4843         if (shouldBreakBlocks
4844                 && currentHeader != nullptr
4845                 && !isHeaderInMultiStatementLine
4846                 && parenStack->back() == 0)
4847         {
4848                 if (currentHeader == &AS_CASE || currentHeader == &AS_DEFAULT)
4849                 {
4850                         // do not yet insert a line if "break" statement is outside the braces
4851                         string nextText = peekNextText(currentLine.substr(charNum + 1));
4852                         if (nextText.length() > 0
4853                                 && nextText.substr(0, 5) != "break")
4854                                 isAppendPostBlockEmptyLineRequested = true;
4855                 }
4856                 else
4857                         isAppendPostBlockEmptyLineRequested = true;
4858         }
4859 }
4860
4861 /**
4862  * format array braces as attached or broken
4863  * determine if the braces can have an inStatement indent
4864  * currentChar contains the brace
4865  * the braces will be appended to the current formattedLine or a new formattedLine as necessary
4866  * the calling function should have a continue statement after calling this method
4867  *
4868  * @param braceType            the type of brace to be formatted, must be an ARRAY_TYPE.
4869  * @param isOpeningArrayBrace  indicates if this is the opening brace for the array block.
4870  */
4871 void ASFormatter::formatArrayBraces(BraceType braceType, bool isOpeningArrayBrace)
4872 {
4873         assert(isBraceType(braceType, ARRAY_TYPE));
4874         assert(currentChar == '{' || currentChar == '}');
4875
4876         if (currentChar == '{')
4877         {
4878                 // is this the first opening brace in the array?
4879                 if (isOpeningArrayBrace)
4880                 {
4881                         if (braceFormatMode == ATTACH_MODE
4882                                 || braceFormatMode == LINUX_MODE)
4883                         {
4884                                 // break an enum if mozilla
4885                                 if (isBraceType(braceType, ENUM_TYPE)
4886                                         && formattingStyle == STYLE_MOZILLA)
4887                                 {
4888                                         isInLineBreak = true;
4889                                         appendCurrentChar();                // don't attach
4890                                 }
4891                                 // don't attach to a preprocessor directive or '\' line
4892                                 else if ((isImmediatelyPostPreprocessor
4893                                           || (formattedLine.length() > 0
4894                                               && formattedLine[formattedLine.length() - 1] == '\\'))
4895                                          && currentLineBeginsWithBrace)
4896                                 {
4897                                         isInLineBreak = true;
4898                                         appendCurrentChar();                // don't attach
4899                                 }
4900                                 else if (isCharImmediatelyPostComment)
4901                                 {
4902                                         // TODO: attach brace to line-end comment
4903                                         appendCurrentChar();                // don't attach
4904                                 }
4905                                 else if (isCharImmediatelyPostLineComment && !isBraceType(braceType, SINGLE_LINE_TYPE))
4906                                 {
4907                                         appendCharInsideComments();
4908                                 }
4909                                 else
4910                                 {
4911                                         // if a blank line precedes this don't attach
4912                                         if (isEmptyLine(formattedLine))
4913                                                 appendCurrentChar();            // don't attach
4914                                         else
4915                                         {
4916                                                 // if brace is broken or not an assignment
4917                                                 if (currentLineBeginsWithBrace
4918                                                         && !isBraceType(braceType, SINGLE_LINE_TYPE))
4919                                                 {
4920                                                         appendSpacePad();
4921                                                         appendCurrentChar(false);                               // OK to attach
4922                                                         // TODO: debug the following line
4923                                                         testForTimeToSplitFormattedLine();              // line length will have changed
4924
4925                                                         if (currentLineBeginsWithBrace
4926                                                                 && (int) currentLineFirstBraceNum == charNum)
4927                                                                 shouldBreakLineAtNextChar = true;
4928                                                 }
4929                                                 else
4930                                                 {
4931                                                         if (previousNonWSChar != '(')
4932                                                         {
4933                                                                 // don't space pad C++11 uniform initialization
4934                                                                 if (!isBraceType(braceType, INIT_TYPE))
4935                                                                         appendSpacePad();
4936                                                         }
4937                                                         appendCurrentChar();
4938                                                 }
4939                                         }
4940                                 }
4941                         }
4942                         else if (braceFormatMode == BREAK_MODE)
4943                         {
4944                                 if (isWhiteSpace(peekNextChar()) && !isInVirginLine)
4945                                         breakLine();
4946                                 else if (isBeforeAnyComment())
4947                                 {
4948                                         // do not break unless comment is at line end
4949                                         if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace)
4950                                         {
4951                                                 currentChar = ' ';            // remove brace from current line
4952                                                 appendOpeningBrace = true;    // append brace to following line
4953                                         }
4954                                 }
4955                                 if (!isInLineBreak && previousNonWSChar != '(')
4956                                 {
4957                                         // don't space pad C++11 uniform initialization
4958                                         if (!isBraceType(braceType, INIT_TYPE))
4959                                                 appendSpacePad();
4960                                 }
4961                                 appendCurrentChar();
4962
4963                                 if (currentLineBeginsWithBrace
4964                                         && (int) currentLineFirstBraceNum == charNum
4965                                         && !isBraceType(braceType, SINGLE_LINE_TYPE))
4966                                         shouldBreakLineAtNextChar = true;
4967                         }
4968                         else if (braceFormatMode == RUN_IN_MODE)
4969                         {
4970                                 if (isWhiteSpace(peekNextChar()) && !isInVirginLine)
4971                                         breakLine();
4972                                 else if (isBeforeAnyComment())
4973                                 {
4974                                         // do not break unless comment is at line end
4975                                         if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace)
4976                                         {
4977                                                 currentChar = ' ';            // remove brace from current line
4978                                                 appendOpeningBrace = true;    // append brace to following line
4979                                         }
4980                                 }
4981                                 if (!isInLineBreak && previousNonWSChar != '(')
4982                                 {
4983                                         // don't space pad C++11 uniform initialization
4984                                         if (!isBraceType(braceType, INIT_TYPE))
4985                                                 appendSpacePad();
4986                                 }
4987                                 appendCurrentChar();
4988                         }
4989                         else if (braceFormatMode == NONE_MODE)
4990                         {
4991                                 if (currentLineBeginsWithBrace
4992                                         && charNum == (int) currentLineFirstBraceNum)
4993                                 {
4994                                         appendCurrentChar();                // don't attach
4995                                 }
4996                                 else
4997                                 {
4998                                         if (previousNonWSChar != '(')
4999                                         {
5000                                                 // don't space pad C++11 uniform initialization
5001                                                 if (!isBraceType(braceType, INIT_TYPE))
5002                                                         appendSpacePad();
5003                                         }
5004                                         appendCurrentChar(false);           // OK to attach
5005                                 }
5006                         }
5007                 }
5008                 else         // not the first opening brace
5009                 {
5010                         if (braceFormatMode == RUN_IN_MODE)
5011                         {
5012                                 if (previousNonWSChar == '{'
5013                                         && braceTypeStack->size() > 2
5014                                         && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2],
5015                                                         SINGLE_LINE_TYPE))
5016                                         formatArrayRunIn();
5017                         }
5018                         else if (!isInLineBreak
5019                                  && !isWhiteSpace(peekNextChar())
5020                                  && previousNonWSChar == '{'
5021                                  && braceTypeStack->size() > 2
5022                                  && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2],
5023                                                  SINGLE_LINE_TYPE))
5024                                 formatArrayRunIn();
5025
5026                         appendCurrentChar();
5027                 }
5028         }
5029         else if (currentChar == '}')
5030         {
5031                 if (attachClosingBraceMode)
5032                 {
5033                         if (isEmptyLine(formattedLine)                  // if a blank line precedes this
5034                                 || isImmediatelyPostPreprocessor
5035                                 || isCharImmediatelyPostLineComment
5036                                 || isCharImmediatelyPostComment)
5037                                 appendCurrentChar();                            // don't attach
5038                         else
5039                         {
5040                                 appendSpacePad();
5041                                 appendCurrentChar(false);                       // attach
5042                         }
5043                 }
5044                 else
5045                 {
5046                         // does this close the first opening brace in the array?
5047                         // must check if the block is still a single line because of anonymous statements
5048                         if (!isBraceType(braceType, INIT_TYPE)
5049                                 && (!isBraceType(braceType, SINGLE_LINE_TYPE)
5050                                     || formattedLine.find('{') == string::npos))
5051                                 breakLine();
5052                         appendCurrentChar();
5053                 }
5054
5055                 // if a declaration follows an enum definition, space pad
5056                 char peekedChar = peekNextChar();
5057                 if (isLegalNameChar(peekedChar)
5058                         || peekedChar == '[')
5059                         appendSpaceAfter();
5060         }
5061 }
5062
5063 /**
5064  * determine if a run-in can be attached.
5065  * if it can insert the indents in formattedLine and reset the current line break.
5066  */
5067 void ASFormatter::formatRunIn()
5068 {
5069         assert(braceFormatMode == RUN_IN_MODE || braceFormatMode == NONE_MODE);
5070
5071         // keep one line blocks returns true without indenting the run-in
5072         if (formattingStyle != STYLE_PICO
5073                 && !isOkToBreakBlock(braceTypeStack->back()))
5074                 return; // true;
5075
5076         // make sure the line begins with a brace
5077         size_t lastText = formattedLine.find_last_not_of(" \t");
5078         if (lastText == string::npos || formattedLine[lastText] != '{')
5079                 return; // false;
5080
5081         // make sure the brace is broken
5082         if (formattedLine.find_first_not_of(" \t{") != string::npos)
5083                 return; // false;
5084
5085         if (isBraceType(braceTypeStack->back(), NAMESPACE_TYPE))
5086                 return; // false;
5087
5088         bool extraIndent = false;
5089         bool extraHalfIndent = false;
5090         isInLineBreak = true;
5091
5092         // cannot attach a class modifier without indent-classes
5093         if (isCStyle()
5094                 && isCharPotentialHeader(currentLine, charNum)
5095                 && (isBraceType(braceTypeStack->back(), CLASS_TYPE)
5096                     || (isBraceType(braceTypeStack->back(), STRUCT_TYPE)
5097                         && isInIndentableStruct)))
5098         {
5099                 if (findKeyword(currentLine, charNum, AS_PUBLIC)
5100                         || findKeyword(currentLine, charNum, AS_PRIVATE)
5101                         || findKeyword(currentLine, charNum, AS_PROTECTED))
5102                 {
5103                         if (getModifierIndent())
5104                                 extraHalfIndent = true;
5105                         else if (!getClassIndent())
5106                                 return; // false;
5107                 }
5108                 else if (getClassIndent())
5109                         extraIndent = true;
5110         }
5111
5112         // cannot attach a 'case' statement without indent-switches
5113         if (!getSwitchIndent()
5114                 && isCharPotentialHeader(currentLine, charNum)
5115                 && (findKeyword(currentLine, charNum, AS_CASE)
5116                     || findKeyword(currentLine, charNum, AS_DEFAULT)))
5117                 return; // false;
5118
5119         // extra indent for switch statements
5120         if (getSwitchIndent()
5121                 && !preBraceHeaderStack->empty()
5122                 && preBraceHeaderStack->back() == &AS_SWITCH
5123                 && ((isLegalNameChar(currentChar)
5124                      && !findKeyword(currentLine, charNum, AS_CASE))))
5125                 extraIndent = true;
5126
5127         isInLineBreak = false;
5128         // remove for extra whitespace
5129         if (formattedLine.length() > lastText + 1
5130                 && formattedLine.find_first_not_of(" \t", lastText + 1) == string::npos)
5131                 formattedLine.erase(lastText + 1);
5132
5133         if (extraHalfIndent)
5134         {
5135                 int indentLength_ = getIndentLength();
5136                 runInIndentChars = indentLength_ / 2;
5137                 formattedLine.append(runInIndentChars - 1, ' ');
5138         }
5139         else if (getForceTabIndentation() && getIndentLength() != getTabLength())
5140         {
5141                 // insert the space indents
5142                 string indent;
5143                 int indentLength_ = getIndentLength();
5144                 int tabLength_ = getTabLength();
5145                 indent.append(indentLength_, ' ');
5146                 if (extraIndent)
5147                         indent.append(indentLength_, ' ');
5148                 // replace spaces indents with tab indents
5149                 size_t tabCount = indent.length() / tabLength_;         // truncate extra spaces
5150                 indent.replace(0U, tabCount * tabLength_, tabCount, '\t');
5151                 runInIndentChars = indentLength_;
5152                 if (indent[0] == ' ')                   // allow for brace
5153                         indent.erase(0, 1);
5154                 formattedLine.append(indent);
5155         }
5156         else if (getIndentString() == "\t")
5157         {
5158                 appendChar('\t', false);
5159                 runInIndentChars = 2;   // one for { and one for tab
5160                 if (extraIndent)
5161                 {
5162                         appendChar('\t', false);
5163                         runInIndentChars++;
5164                 }
5165         }
5166         else // spaces
5167         {
5168                 int indentLength_ = getIndentLength();
5169                 formattedLine.append(indentLength_ - 1, ' ');
5170                 runInIndentChars = indentLength_;
5171                 if (extraIndent)
5172                 {
5173                         formattedLine.append(indentLength_, ' ');
5174                         runInIndentChars += indentLength_;
5175                 }
5176         }
5177         isInBraceRunIn = true;
5178 }
5179
5180 /**
5181  * remove whitespace and add indentation for an array run-in.
5182  */
5183 void ASFormatter::formatArrayRunIn()
5184 {
5185         assert(isBraceType(braceTypeStack->back(), ARRAY_TYPE));
5186
5187         // make sure the brace is broken
5188         if (formattedLine.find_first_not_of(" \t{") != string::npos)
5189                 return;
5190
5191         size_t lastText = formattedLine.find_last_not_of(" \t");
5192         if (lastText == string::npos || formattedLine[lastText] != '{')
5193                 return;
5194
5195         // check for extra whitespace
5196         if (formattedLine.length() > lastText + 1
5197                 && formattedLine.find_first_not_of(" \t", lastText + 1) == string::npos)
5198                 formattedLine.erase(lastText + 1);
5199
5200         if (getIndentString() == "\t")
5201         {
5202                 appendChar('\t', false);
5203                 runInIndentChars = 2;   // one for { and one for tab
5204         }
5205         else
5206         {
5207                 int indent = getIndentLength();
5208                 formattedLine.append(indent - 1, ' ');
5209                 runInIndentChars = indent;
5210         }
5211         isInBraceRunIn = true;
5212         isInLineBreak = false;
5213 }
5214
5215 /**
5216  * delete a braceTypeStack vector object
5217  * BraceTypeStack did not work with the DeleteContainer template
5218  */
5219 void ASFormatter::deleteContainer(vector<BraceType>*& container)
5220 {
5221         if (container != nullptr)
5222         {
5223                 container->clear();
5224                 delete (container);
5225                 container = nullptr;
5226         }
5227 }
5228
5229 /**
5230  * delete a vector object
5231  * T is the type of vector
5232  * used for all vectors except braceTypeStack
5233  */
5234 template<typename T>
5235 void ASFormatter::deleteContainer(T& container)
5236 {
5237         if (container != nullptr)
5238         {
5239                 container->clear();
5240                 delete (container);
5241                 container = nullptr;
5242         }
5243 }
5244
5245 /**
5246  * initialize a braceType vector object
5247  * braceType did not work with the DeleteContainer template
5248  */
5249 void ASFormatter::initContainer(vector<BraceType>*& container, vector<BraceType>* value)
5250 {
5251         if (container != nullptr)
5252                 deleteContainer(container);
5253         container = value;
5254 }
5255
5256 /**
5257  * initialize a vector object
5258  * T is the type of vector
5259  * used for all vectors except braceTypeStack
5260  */
5261 template<typename T>
5262 void ASFormatter::initContainer(T& container, T value)
5263 {
5264         // since the ASFormatter object is never deleted,
5265         // the existing vectors must be deleted before creating new ones
5266         if (container != nullptr)
5267                 deleteContainer(container);
5268         container = value;
5269 }
5270
5271 /**
5272  * convert a tab to spaces.
5273  * charNum points to the current character to convert to spaces.
5274  * tabIncrementIn is the increment that must be added for tab indent characters
5275  *     to get the correct column for the current tab.
5276  * replaces the tab in currentLine with the required number of spaces.
5277  * replaces the value of currentChar.
5278  */
5279 void ASFormatter::convertTabToSpaces()
5280 {
5281         assert(currentChar == '\t');
5282
5283         // do NOT replace if in quotes
5284         if (isInQuote || isInQuoteContinuation)
5285                 return;
5286
5287         size_t tabSize = getTabLength();
5288         size_t numSpaces = tabSize - ((tabIncrementIn + charNum) % tabSize);
5289         currentLine.replace(charNum, 1, numSpaces, ' ');
5290         currentChar = currentLine[charNum];
5291 }
5292
5293 /**
5294 * is it ok to break this block?
5295 */
5296 bool ASFormatter::isOkToBreakBlock(BraceType braceType) const
5297 {
5298         // Actually, there should not be an ARRAY_TYPE brace here.
5299         // But this will avoid breaking a one line block when there is.
5300         // Otherwise they will be formatted differently on consecutive runs.
5301         if (isBraceType(braceType, ARRAY_TYPE)
5302                 && isBraceType(braceType, SINGLE_LINE_TYPE))
5303                 return false;
5304         if (isBraceType(braceType, COMMAND_TYPE)
5305                 && isBraceType(braceType, EMPTY_BLOCK_TYPE))
5306                 return false;
5307         if (!isBraceType(braceType, SINGLE_LINE_TYPE)
5308                 || isBraceType(braceType, BREAK_BLOCK_TYPE)
5309                 || shouldBreakOneLineBlocks)
5310                 return true;
5311         return false;
5312 }
5313
5314 /**
5315 * check if a sharp header is a paren or non-paren header
5316 */
5317 bool ASFormatter::isSharpStyleWithParen(const string* header) const
5318 {
5319         return (isSharpStyle() && peekNextChar() == '('
5320                 && (header == &AS_CATCH
5321                     || header == &AS_DELEGATE));
5322 }
5323
5324 /**
5325  * Check for a following header when a comment is reached.
5326  * firstLine must contain the start of the comment.
5327  * return value is a pointer to the header or nullptr.
5328  */
5329 const string* ASFormatter::checkForHeaderFollowingComment(const string& firstLine) const
5330 {
5331         assert(isInComment || isInLineComment);
5332         assert(shouldBreakElseIfs || shouldBreakBlocks || isInSwitchStatement());
5333         // look ahead to find the next non-comment text
5334         bool endOnEmptyLine = (currentHeader == nullptr);
5335         if (isInSwitchStatement())
5336                 endOnEmptyLine = false;
5337         string nextText = peekNextText(firstLine, endOnEmptyLine);
5338
5339         if (nextText.length() == 0 || !isCharPotentialHeader(nextText, 0))
5340                 return nullptr;
5341
5342         return ASBase::findHeader(nextText, 0, headers);
5343 }
5344
5345 /**
5346  * process preprocessor statements.
5347  * charNum should be the index of the #.
5348  *
5349  * delete braceTypeStack entries added by #if if a #else is found.
5350  * prevents double entries in the braceTypeStack.
5351  */
5352 void ASFormatter::processPreprocessor()
5353 {
5354         assert(currentChar == '#');
5355
5356         const size_t preproc = currentLine.find_first_not_of(" \t", charNum + 1);
5357
5358         if (preproc == string::npos)
5359                 return;
5360
5361         if (currentLine.compare(preproc, 2, "if") == 0)
5362         {
5363                 preprocBraceTypeStackSize = braceTypeStack->size();
5364         }
5365         else if (currentLine.compare(preproc, 4, "else") == 0)
5366         {
5367                 // delete stack entries added in #if
5368                 // should be replaced by #else
5369                 if (preprocBraceTypeStackSize > 0)
5370                 {
5371                         int addedPreproc = braceTypeStack->size() - preprocBraceTypeStackSize;
5372                         for (int i = 0; i < addedPreproc; i++)
5373                                 braceTypeStack->pop_back();
5374                 }
5375         }
5376 }
5377
5378 /**
5379  * determine if the next line starts a comment
5380  * and a header follows the comment or comments.
5381  */
5382 bool ASFormatter::commentAndHeaderFollows()
5383 {
5384         // called ONLY IF shouldDeleteEmptyLines and shouldBreakBlocks are TRUE.
5385         assert(shouldDeleteEmptyLines && shouldBreakBlocks);
5386
5387         // is the next line a comment
5388         auto stream = make_shared<ASPeekStream>(sourceIterator);
5389         if (!stream->hasMoreLines())
5390                 return false;
5391         string nextLine_ = stream->peekNextLine();
5392         size_t firstChar = nextLine_.find_first_not_of(" \t");
5393         if (firstChar == string::npos
5394                 || !(nextLine_.compare(firstChar, 2, "//") == 0
5395                      || nextLine_.compare(firstChar, 2, "/*") == 0))
5396                 return false;
5397
5398         // find the next non-comment text, and reset
5399         string nextText = peekNextText(nextLine_, false, stream);
5400         if (nextText.length() == 0 || !isCharPotentialHeader(nextText, 0))
5401                 return false;
5402
5403         const string* newHeader = ASBase::findHeader(nextText, 0, headers);
5404
5405         if (newHeader == nullptr)
5406                 return false;
5407
5408         // if a closing header, reset break unless break is requested
5409         if (isClosingHeader(newHeader) && !shouldBreakClosingHeaderBlocks)
5410         {
5411                 isAppendPostBlockEmptyLineRequested = false;
5412                 return false;
5413         }
5414
5415         return true;
5416 }
5417
5418 /**
5419  * determine if a brace should be attached or broken
5420  * uses braces in the braceTypeStack
5421  * the last brace in the braceTypeStack is the one being formatted
5422  * returns true if the brace should be broken
5423  */
5424 bool ASFormatter::isCurrentBraceBroken() const
5425 {
5426         assert(braceTypeStack->size() > 1);
5427
5428         bool breakBrace = false;
5429         size_t stackEnd = braceTypeStack->size() - 1;
5430
5431         // check brace modifiers
5432         if (shouldAttachExternC
5433                 && isBraceType((*braceTypeStack)[stackEnd], EXTERN_TYPE))
5434         {
5435                 return false;
5436         }
5437         if (shouldAttachNamespace
5438                 && isBraceType((*braceTypeStack)[stackEnd], NAMESPACE_TYPE))
5439         {
5440                 return false;
5441         }
5442         if (shouldAttachClass
5443                 && (isBraceType((*braceTypeStack)[stackEnd], CLASS_TYPE)
5444                     || isBraceType((*braceTypeStack)[stackEnd], INTERFACE_TYPE)))
5445         {
5446                 return false;
5447         }
5448         if (shouldAttachInline
5449                 && isCStyle()                   // for C++ only
5450                 && braceFormatMode != RUN_IN_MODE
5451                 && !(currentLineBeginsWithBrace && peekNextChar() == '/')
5452                 && isBraceType((*braceTypeStack)[stackEnd], COMMAND_TYPE))
5453         {
5454                 size_t i;
5455                 for (i = 1; i < braceTypeStack->size(); i++)
5456                         if (isBraceType((*braceTypeStack)[i], CLASS_TYPE)
5457                                 || isBraceType((*braceTypeStack)[i], STRUCT_TYPE))
5458                                 return false;
5459         }
5460
5461         // check braces
5462         if (isBraceType((*braceTypeStack)[stackEnd], EXTERN_TYPE))
5463         {
5464                 if (currentLineBeginsWithBrace
5465                         || braceFormatMode == RUN_IN_MODE)
5466                         breakBrace = true;
5467         }
5468         else if (braceFormatMode == NONE_MODE)
5469         {
5470                 if (currentLineBeginsWithBrace
5471                         && (int) currentLineFirstBraceNum == charNum)
5472                         breakBrace = true;
5473         }
5474         else if (braceFormatMode == BREAK_MODE || braceFormatMode == RUN_IN_MODE)
5475         {
5476                 breakBrace = true;
5477         }
5478         else if (braceFormatMode == LINUX_MODE)
5479         {
5480                 // break a namespace if NOT stroustrup or mozilla
5481                 if (isBraceType((*braceTypeStack)[stackEnd], NAMESPACE_TYPE))
5482                 {
5483                         if (formattingStyle != STYLE_STROUSTRUP
5484                                 && formattingStyle != STYLE_MOZILLA)
5485                                 breakBrace = true;
5486                 }
5487                 // break a class or interface if NOT stroustrup
5488                 else if (isBraceType((*braceTypeStack)[stackEnd], CLASS_TYPE)
5489                          || isBraceType((*braceTypeStack)[stackEnd], INTERFACE_TYPE))
5490                 {
5491                         if (formattingStyle != STYLE_STROUSTRUP)
5492                                 breakBrace = true;
5493                 }
5494                 // break a struct if mozilla - an enum is processed as an array brace
5495                 else if (isBraceType((*braceTypeStack)[stackEnd], STRUCT_TYPE))
5496                 {
5497                         if (formattingStyle == STYLE_MOZILLA)
5498                                 breakBrace = true;
5499                 }
5500                 // break the first brace if a function
5501                 else if (isBraceType((*braceTypeStack)[stackEnd], COMMAND_TYPE))
5502                 {
5503                         if (stackEnd == 1)
5504                         {
5505                                 breakBrace = true;
5506                         }
5507                         else if (stackEnd > 1)
5508                         {
5509                                 // break the first brace after these if a function
5510                                 if (isBraceType((*braceTypeStack)[stackEnd - 1], NAMESPACE_TYPE)
5511                                         || isBraceType((*braceTypeStack)[stackEnd - 1], CLASS_TYPE)
5512                                         || isBraceType((*braceTypeStack)[stackEnd - 1], ARRAY_TYPE)
5513                                         || isBraceType((*braceTypeStack)[stackEnd - 1], STRUCT_TYPE)
5514                                         || isBraceType((*braceTypeStack)[stackEnd - 1], EXTERN_TYPE))
5515                                 {
5516                                         breakBrace = true;
5517                                 }
5518                         }
5519                 }
5520         }
5521         return breakBrace;
5522 }
5523
5524 /**
5525  * format comment body
5526  * the calling function should have a continue statement after calling this method
5527  */
5528 void ASFormatter::formatCommentBody()
5529 {
5530         assert(isInComment);
5531
5532         // append the comment
5533         while (charNum < (int) currentLine.length())
5534         {
5535                 currentChar = currentLine[charNum];
5536                 if (isSequenceReached("*/"))
5537                 {
5538                         formatCommentCloser();
5539                         break;
5540                 }
5541                 if (currentChar == '\t' && shouldConvertTabs)
5542                         convertTabToSpaces();
5543                 appendCurrentChar();
5544                 ++charNum;
5545         }
5546         if (shouldStripCommentPrefix)
5547                 stripCommentPrefix();
5548 }
5549
5550 /**
5551  * format a comment opener
5552  * the comment opener will be appended to the current formattedLine or a new formattedLine as necessary
5553  * the calling function should have a continue statement after calling this method
5554  */
5555 void ASFormatter::formatCommentOpener()
5556 {
5557         assert(isSequenceReached("/*"));
5558
5559         isInComment = isInCommentStartLine = true;
5560         isImmediatelyPostLineComment = false;
5561         if (previousNonWSChar == '}')
5562                 resetEndOfStatement();
5563
5564         // Check for a following header.
5565         // For speed do not check multiple comment lines more than once.
5566         // For speed do not check shouldBreakBlocks if previous line is empty, a comment, or a '{'.
5567         const string* followingHeader = nullptr;
5568         if ((doesLineStartComment
5569                 && !isImmediatelyPostCommentOnly
5570                 && isBraceType(braceTypeStack->back(), COMMAND_TYPE))
5571                 && (shouldBreakElseIfs
5572                     || isInSwitchStatement()
5573                     || (shouldBreakBlocks
5574                         && !isImmediatelyPostEmptyLine
5575                         && previousCommandChar != '{')))
5576                 followingHeader = checkForHeaderFollowingComment(currentLine.substr(charNum));
5577
5578         if (spacePadNum != 0 && !isInLineBreak)
5579                 adjustComments();
5580         formattedLineCommentNum = formattedLine.length();
5581
5582         // must be done BEFORE appendSequence
5583         if (previousCommandChar == '{'
5584                 && !isImmediatelyPostComment
5585                 && !isImmediatelyPostLineComment)
5586         {
5587                 if (isBraceType(braceTypeStack->back(), NAMESPACE_TYPE))
5588                 {
5589                         // namespace run-in is always broken.
5590                         isInLineBreak = true;
5591                 }
5592                 else if (braceFormatMode == NONE_MODE)
5593                 {
5594                         // should a run-in statement be attached?
5595                         if (currentLineBeginsWithBrace)
5596                                 formatRunIn();
5597                 }
5598                 else if (braceFormatMode == ATTACH_MODE)
5599                 {
5600                         // if the brace was not attached?
5601                         if (formattedLine.length() > 0 && formattedLine[0] == '{'
5602                                 && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE))
5603                                 isInLineBreak = true;
5604                 }
5605                 else if (braceFormatMode == RUN_IN_MODE)
5606                 {
5607                         // should a run-in statement be attached?
5608                         if (formattedLine.length() > 0 && formattedLine[0] == '{')
5609                                 formatRunIn();
5610                 }
5611         }
5612         else if (!doesLineStartComment)
5613                 noTrimCommentContinuation = true;
5614
5615         // ASBeautifier needs to know the following statements
5616         if (shouldBreakElseIfs && followingHeader == &AS_ELSE)
5617                 elseHeaderFollowsComments = true;
5618         if (followingHeader == &AS_CASE || followingHeader == &AS_DEFAULT)
5619                 caseHeaderFollowsComments = true;
5620
5621         // appendSequence will write the previous line
5622         appendSequence(AS_OPEN_COMMENT);
5623         goForward(1);
5624
5625         // must be done AFTER appendSequence
5626
5627         // Break before the comment if a header follows the line comment.
5628         // But not break if previous line is empty, a comment, or a '{'.
5629         if (shouldBreakBlocks
5630                 && followingHeader != nullptr
5631                 && !isImmediatelyPostEmptyLine
5632                 && previousCommandChar != '{')
5633         {
5634                 if (isClosingHeader(followingHeader))
5635                 {
5636                         if (!shouldBreakClosingHeaderBlocks)
5637                                 isPrependPostBlockEmptyLineRequested = false;
5638                 }
5639                 // if an opening header, break before the comment
5640                 else
5641                         isPrependPostBlockEmptyLineRequested = true;
5642         }
5643
5644         if (previousCommandChar == '}')
5645                 currentHeader = nullptr;
5646 }
5647
5648 /**
5649  * format a comment closer
5650  * the comment closer will be appended to the current formattedLine
5651  */
5652 void ASFormatter::formatCommentCloser()
5653 {
5654         assert(isSequenceReached("*/"));
5655         isInComment = false;
5656         noTrimCommentContinuation = false;
5657         isImmediatelyPostComment = true;
5658         appendSequence(AS_CLOSE_COMMENT);
5659         goForward(1);
5660         if (doesLineStartComment
5661                 && (currentLine.find_first_not_of(" \t", charNum + 1) == string::npos))
5662                 lineEndsInCommentOnly = true;
5663         if (peekNextChar() == '}'
5664                 && previousCommandChar != ';'
5665                 && !isBraceType(braceTypeStack->back(), ARRAY_TYPE)
5666                 && !isInPreprocessor
5667                 && isOkToBreakBlock(braceTypeStack->back()))
5668         {
5669                 isInLineBreak = true;
5670                 shouldBreakLineAtNextChar = true;
5671         }
5672 }
5673
5674 /**
5675  * format a line comment body
5676  * the calling function should have a continue statement after calling this method
5677  */
5678 void ASFormatter::formatLineCommentBody()
5679 {
5680         assert(isInLineComment);
5681
5682         // append the comment
5683         while (charNum < (int) currentLine.length())
5684 //              && !isLineReady // commented out in release 2.04, unnecessary
5685         {
5686                 currentChar = currentLine[charNum];
5687                 if (currentChar == '\t' && shouldConvertTabs)
5688                         convertTabToSpaces();
5689                 appendCurrentChar();
5690                 ++charNum;
5691         }
5692
5693         // explicitly break a line when a line comment's end is found.
5694         if (charNum == (int) currentLine.length())
5695         {
5696                 isInLineBreak = true;
5697                 isInLineComment = false;
5698                 isImmediatelyPostLineComment = true;
5699                 currentChar = 0;  //make sure it is a neutral char.
5700         }
5701 }
5702
5703 /**
5704  * format a line comment opener
5705  * the line comment opener will be appended to the current formattedLine or a new formattedLine as necessary
5706  * the calling function should have a continue statement after calling this method
5707  */
5708 void ASFormatter::formatLineCommentOpener()
5709 {
5710         assert(isSequenceReached("//"));
5711
5712         if ((int) currentLine.length() > charNum + 2
5713                 && currentLine[charNum + 2] == '\xf2')     // check for windows line marker
5714                 isAppendPostBlockEmptyLineRequested = false;
5715
5716         isInLineComment = true;
5717         isCharImmediatelyPostComment = false;
5718         if (previousNonWSChar == '}')
5719                 resetEndOfStatement();
5720
5721         // Check for a following header.
5722         // For speed do not check multiple comment lines more than once.
5723         // For speed do not check shouldBreakBlocks if previous line is empty, a comment, or a '{'.
5724         const string* followingHeader = nullptr;
5725         if ((lineIsLineCommentOnly
5726                 && !isImmediatelyPostCommentOnly
5727                 && isBraceType(braceTypeStack->back(), COMMAND_TYPE))
5728                 && (shouldBreakElseIfs
5729                     || isInSwitchStatement()
5730                     || (shouldBreakBlocks
5731                         && !isImmediatelyPostEmptyLine
5732                         && previousCommandChar != '{')))
5733                 followingHeader = checkForHeaderFollowingComment(currentLine.substr(charNum));
5734
5735         // do not indent if in column 1 or 2
5736         // or in a namespace before the opening brace
5737         if ((!shouldIndentCol1Comments && !lineCommentNoIndent)
5738                 || foundNamespaceHeader)
5739         {
5740                 if (charNum == 0)
5741                         lineCommentNoIndent = true;
5742                 else if (charNum == 1 && currentLine[0] == ' ')
5743                         lineCommentNoIndent = true;
5744         }
5745         // move comment if spaces were added or deleted
5746         if (!lineCommentNoIndent && spacePadNum != 0 && !isInLineBreak)
5747                 adjustComments();
5748         formattedLineCommentNum = formattedLine.length();
5749
5750         // must be done BEFORE appendSequence
5751         // check for run-in statement
5752         if (previousCommandChar == '{'
5753                 && !isImmediatelyPostComment
5754                 && !isImmediatelyPostLineComment)
5755         {
5756                 if (braceFormatMode == NONE_MODE)
5757                 {
5758                         if (currentLineBeginsWithBrace)
5759                                 formatRunIn();
5760                 }
5761                 else if (braceFormatMode == RUN_IN_MODE)
5762                 {
5763                         if (!lineCommentNoIndent)
5764                                 formatRunIn();
5765                         else
5766                                 isInLineBreak = true;
5767                 }
5768                 else if (braceFormatMode == BREAK_MODE)
5769                 {
5770                         if (formattedLine.length() > 0 && formattedLine[0] == '{')
5771                                 isInLineBreak = true;
5772                 }
5773                 else
5774                 {
5775                         if (currentLineBeginsWithBrace)
5776                                 isInLineBreak = true;
5777                 }
5778         }
5779
5780         // ASBeautifier needs to know the following statements
5781         if (shouldBreakElseIfs && followingHeader == &AS_ELSE)
5782                 elseHeaderFollowsComments = true;
5783         if (followingHeader == &AS_CASE || followingHeader == &AS_DEFAULT)
5784                 caseHeaderFollowsComments = true;
5785
5786         // appendSequence will write the previous line
5787         appendSequence(AS_OPEN_LINE_COMMENT);
5788         goForward(1);
5789
5790         // must be done AFTER appendSequence
5791
5792         // Break before the comment if a header follows the line comment.
5793         // But do not break if previous line is empty, a comment, or a '{'.
5794         if (shouldBreakBlocks
5795                 && followingHeader != nullptr
5796                 && !isImmediatelyPostEmptyLine
5797                 && previousCommandChar != '{')
5798         {
5799                 if (isClosingHeader(followingHeader))
5800                 {
5801                         if (!shouldBreakClosingHeaderBlocks)
5802                                 isPrependPostBlockEmptyLineRequested = false;
5803                 }
5804                 // if an opening header, break before the comment
5805                 else
5806                         isPrependPostBlockEmptyLineRequested = true;
5807         }
5808
5809         if (previousCommandChar == '}')
5810                 currentHeader = nullptr;
5811
5812         // if tabbed input don't convert the immediately following tabs to spaces
5813         if (getIndentString() == "\t" && lineCommentNoIndent)
5814         {
5815                 while (charNum + 1 < (int) currentLine.length()
5816                         && currentLine[charNum + 1] == '\t')
5817                 {
5818                         currentChar = currentLine[++charNum];
5819                         appendCurrentChar();
5820                 }
5821         }
5822
5823         // explicitly break a line when a line comment's end is found.
5824         if (charNum + 1 == (int) currentLine.length())
5825         {
5826                 isInLineBreak = true;
5827                 isInLineComment = false;
5828                 isImmediatelyPostLineComment = true;
5829                 currentChar = 0;  //make sure it is a neutral char.
5830         }
5831 }
5832
5833 /**
5834  * format quote body
5835  * the calling function should have a continue statement after calling this method
5836  */
5837 void ASFormatter::formatQuoteBody()
5838 {
5839         assert(isInQuote);
5840
5841         if (isSpecialChar)
5842         {
5843                 isSpecialChar = false;
5844         }
5845         else if (currentChar == '\\' && !isInVerbatimQuote)
5846         {
5847                 if (peekNextChar() == ' ')              // is this '\' at end of line
5848                         haveLineContinuationChar = true;
5849                 else
5850                         isSpecialChar = true;
5851         }
5852         else if (isInVerbatimQuote && currentChar == '"')
5853         {
5854                 if (isCStyle())
5855                 {
5856                         string delim = ')' + verbatimDelimiter;
5857                         int delimStart = charNum - delim.length();
5858                         if (delimStart > 0 && currentLine.substr(delimStart, delim.length()) == delim)
5859                         {
5860                                 isInQuote = false;
5861                                 isInVerbatimQuote = false;
5862                         }
5863                 }
5864                 else if (isSharpStyle())
5865                 {
5866                         if ((int) currentLine.length() > charNum + 1
5867                                 && currentLine[charNum + 1] == '"')                     // check consecutive quotes
5868                         {
5869                                 appendSequence("\"\"");
5870                                 goForward(1);
5871                                 return;
5872                         }
5873                         isInQuote = false;
5874                         isInVerbatimQuote = false;
5875                 }
5876         }
5877         else if (quoteChar == currentChar)
5878         {
5879                 isInQuote = false;
5880         }
5881
5882         appendCurrentChar();
5883
5884         // append the text to the ending quoteChar or an escape sequence
5885         // tabs in quotes are NOT changed by convert-tabs
5886         if (isInQuote && currentChar != '\\')
5887         {
5888                 while (charNum + 1 < (int) currentLine.length()
5889                         && currentLine[charNum + 1] != quoteChar
5890                         && currentLine[charNum + 1] != '\\')
5891                 {
5892                         currentChar = currentLine[++charNum];
5893                         appendCurrentChar();
5894                 }
5895         }
5896         if (charNum + 1 >= (int) currentLine.length()
5897                 && currentChar != '\\'
5898                 && !isInVerbatimQuote)
5899                 isInQuote = false;                              // missing closing quote
5900 }
5901
5902 /**
5903  * format a quote opener
5904  * the quote opener will be appended to the current formattedLine or a new formattedLine as necessary
5905  * the calling function should have a continue statement after calling this method
5906  */
5907 void ASFormatter::formatQuoteOpener()
5908 {
5909         assert(currentChar == '"'
5910                || (currentChar == '\'' && !isDigitSeparator(currentLine, charNum)));
5911
5912         isInQuote = true;
5913         quoteChar = currentChar;
5914         if (isCStyle() && previousChar == 'R')
5915         {
5916                 int parenPos = currentLine.find('(', charNum);
5917                 if (parenPos != -1)
5918                 {
5919                         isInVerbatimQuote = true;
5920                         verbatimDelimiter = currentLine.substr(charNum + 1, parenPos - charNum - 1);
5921                 }
5922         }
5923         else if (isSharpStyle() && previousChar == '@')
5924                 isInVerbatimQuote = true;
5925
5926         // a quote following a brace is an array
5927         if (previousCommandChar == '{'
5928                 && !isImmediatelyPostComment
5929                 && !isImmediatelyPostLineComment
5930                 && isNonInStatementArray
5931                 && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
5932                 && !isWhiteSpace(peekNextChar()))
5933         {
5934                 if (braceFormatMode == NONE_MODE)
5935                 {
5936                         if (currentLineBeginsWithBrace)
5937                                 formatRunIn();
5938                 }
5939                 else if (braceFormatMode == RUN_IN_MODE)
5940                 {
5941                         formatRunIn();
5942                 }
5943                 else if (braceFormatMode == BREAK_MODE)
5944                 {
5945                         if (formattedLine.length() > 0 && formattedLine[0] == '{')
5946                                 isInLineBreak = true;
5947                 }
5948                 else
5949                 {
5950                         if (currentLineBeginsWithBrace)
5951                                 isInLineBreak = true;
5952                 }
5953         }
5954         previousCommandChar = ' ';
5955         appendCurrentChar();
5956 }
5957
5958 /**
5959  * get the next line comment adjustment that results from breaking a closing brace.
5960  * the brace must be on the same line as the closing header.
5961  * i.e "} else" changed to "} <NL> else".
5962  */
5963 int ASFormatter::getNextLineCommentAdjustment()
5964 {
5965         assert(foundClosingHeader && previousNonWSChar == '}');
5966         if (charNum < 1)                        // "else" is in column 1
5967                 return 0;
5968         size_t lastBrace = currentLine.rfind('}', charNum - 1);
5969         if (lastBrace != string::npos)
5970                 return (lastBrace - charNum);   // return a negative number
5971         return 0;
5972 }
5973
5974 // for console build only
5975 LineEndFormat ASFormatter::getLineEndFormat() const
5976 {
5977         return lineEnd;
5978 }
5979
5980 /**
5981  * get the current line comment adjustment that results from attaching
5982  * a closing header to a closing brace.
5983  * the brace must be on the line previous to the closing header.
5984  * the adjustment is 2 chars, one for the brace and one for the space.
5985  * i.e "} <NL> else" changed to "} else".
5986  */
5987 int ASFormatter::getCurrentLineCommentAdjustment()
5988 {
5989         assert(foundClosingHeader && previousNonWSChar == '}');
5990         if (charNum < 1)
5991                 return 2;
5992         size_t lastBrace = currentLine.rfind('}', charNum - 1);
5993         if (lastBrace == string::npos)
5994                 return 2;
5995         return 0;
5996 }
5997
5998 /**
5999  * get the previous word on a line
6000  * the argument 'currPos' must point to the current position.
6001  *
6002  * @return is the previous word or an empty string if none found.
6003  */
6004 string ASFormatter::getPreviousWord(const string& line, int currPos) const
6005 {
6006         // get the last legal word (may be a number)
6007         if (currPos == 0)
6008                 return string();
6009
6010         size_t end = line.find_last_not_of(" \t", currPos - 1);
6011         if (end == string::npos || !isLegalNameChar(line[end]))
6012                 return string();
6013
6014         int start;          // start of the previous word
6015         for (start = end; start > -1; start--)
6016         {
6017                 if (!isLegalNameChar(line[start]) || line[start] == '.')
6018                         break;
6019         }
6020         start++;
6021
6022         return (line.substr(start, end - start + 1));
6023 }
6024
6025 /**
6026  * check if a line break is needed when a closing brace
6027  * is followed by a closing header.
6028  * the break depends on the braceFormatMode and other factors.
6029  */
6030 void ASFormatter::isLineBreakBeforeClosingHeader()
6031 {
6032         assert(foundClosingHeader && previousNonWSChar == '}');
6033
6034         if (currentHeader == &AS_WHILE && shouldAttachClosingWhile)
6035         {
6036                 appendClosingHeader();
6037                 return;
6038         }
6039
6040         if (braceFormatMode == BREAK_MODE
6041                 || braceFormatMode == RUN_IN_MODE
6042                 || attachClosingBraceMode)
6043         {
6044                 isInLineBreak = true;
6045         }
6046         else if (braceFormatMode == NONE_MODE)
6047         {
6048                 if (shouldBreakClosingHeaderBraces
6049                         || getBraceIndent() || getBlockIndent())
6050                 {
6051                         isInLineBreak = true;
6052                 }
6053                 else
6054                 {
6055                         appendSpacePad();
6056                         // is closing brace broken?
6057                         size_t i = currentLine.find_first_not_of(" \t");
6058                         if (i != string::npos && currentLine[i] == '}')
6059                                 isInLineBreak = false;
6060
6061                         if (shouldBreakBlocks)
6062                                 isAppendPostBlockEmptyLineRequested = false;
6063                 }
6064         }
6065         // braceFormatMode == ATTACH_MODE, LINUX_MODE
6066         else
6067         {
6068                 if (shouldBreakClosingHeaderBraces
6069                         || getBraceIndent() || getBlockIndent())
6070                 {
6071                         isInLineBreak = true;
6072                 }
6073                 else
6074                 {
6075                         appendClosingHeader();
6076                         if (shouldBreakBlocks)
6077                                 isAppendPostBlockEmptyLineRequested = false;
6078                 }
6079         }
6080 }
6081
6082 /**
6083  * Append a closing header to the previous closing brace, if possible
6084  */
6085 void ASFormatter::appendClosingHeader()
6086 {
6087         // if a blank line does not precede this
6088         // or last line is not a one line block, attach header
6089         bool previousLineIsEmpty = isEmptyLine(formattedLine);
6090         int previousLineIsOneLineBlock = 0;
6091         size_t firstBrace = findNextChar(formattedLine, '{');
6092         if (firstBrace != string::npos)
6093                 previousLineIsOneLineBlock = isOneLineBlockReached(formattedLine, firstBrace);
6094         if (!previousLineIsEmpty
6095                 && previousLineIsOneLineBlock == 0)
6096         {
6097                 isInLineBreak = false;
6098                 appendSpacePad();
6099                 spacePadNum = 0;        // don't count as comment padding
6100         }
6101 }
6102
6103 /**
6104  * Add braces to a single line statement following a header.
6105  * braces are not added if the proper conditions are not met.
6106  * braces are added to the currentLine.
6107  */
6108 bool ASFormatter::addBracesToStatement()
6109 {
6110         assert(isImmediatelyPostHeader);
6111
6112         if (currentHeader != &AS_IF
6113                 && currentHeader != &AS_ELSE
6114                 && currentHeader != &AS_FOR
6115                 && currentHeader != &AS_WHILE
6116                 && currentHeader != &AS_DO
6117                 && currentHeader != &AS_FOREACH
6118                 && currentHeader != &AS_QFOREACH
6119                 && currentHeader != &AS_QFOREVER
6120                 && currentHeader != &AS_FOREVER)
6121                 return false;
6122
6123         if (currentHeader == &AS_WHILE && foundClosingHeader)   // do-while
6124                 return false;
6125
6126         // do not brace an empty statement
6127         if (currentChar == ';')
6128                 return false;
6129
6130         // do not add if a header follows
6131         if (isCharPotentialHeader(currentLine, charNum))
6132                 if (findHeader(headers) != nullptr)
6133                         return false;
6134
6135         // find the next semi-colon
6136         size_t nextSemiColon = charNum;
6137         if (currentChar != ';')
6138                 nextSemiColon = findNextChar(currentLine, ';', charNum + 1);
6139         if (nextSemiColon == string::npos)
6140                 return false;
6141
6142         // add closing brace before changing the line length
6143         if (nextSemiColon == currentLine.length() - 1)
6144                 currentLine.append(" }");
6145         else
6146                 currentLine.insert(nextSemiColon + 1, " }");
6147         // add opening brace
6148         currentLine.insert(charNum, "{ ");
6149         assert(computeChecksumIn("{}"));
6150         currentChar = '{';
6151         if ((int) currentLine.find_first_not_of(" \t") == charNum)
6152                 currentLineBeginsWithBrace = true;
6153         // remove extra spaces
6154         if (!shouldAddOneLineBraces)
6155         {
6156                 size_t lastText = formattedLine.find_last_not_of(" \t");
6157                 if ((formattedLine.length() - 1) - lastText > 1)
6158                         formattedLine.erase(lastText + 1);
6159         }
6160         return true;
6161 }
6162
6163 /**
6164  * Remove braces from a single line statement following a header.
6165  * braces are not removed if the proper conditions are not met.
6166  * The first brace is replaced by a space.
6167  */
6168 bool ASFormatter::removeBracesFromStatement()
6169 {
6170         assert(isImmediatelyPostHeader);
6171         assert(currentChar == '{');
6172
6173         if (currentHeader != &AS_IF
6174                 && currentHeader != &AS_ELSE
6175                 && currentHeader != &AS_FOR
6176                 && currentHeader != &AS_WHILE
6177                 && currentHeader != &AS_FOREACH)
6178                 return false;
6179
6180         if (currentHeader == &AS_WHILE && foundClosingHeader)   // do-while
6181                 return false;
6182
6183         bool isFirstLine = true;
6184         string nextLine_;
6185         // leave nextLine_ empty if end of line comment follows
6186         if (!isBeforeAnyLineEndComment(charNum) || currentLineBeginsWithBrace)
6187                 nextLine_ = currentLine.substr(charNum + 1);
6188         size_t nextChar = 0;
6189
6190         // find the first non-blank text
6191         ASPeekStream stream(sourceIterator);
6192         while (stream.hasMoreLines() || isFirstLine)
6193         {
6194                 if (isFirstLine)
6195                         isFirstLine = false;
6196                 else
6197                 {
6198                         nextLine_ = stream.peekNextLine();
6199                         nextChar = 0;
6200                 }
6201
6202                 nextChar = nextLine_.find_first_not_of(" \t", nextChar);
6203                 if (nextChar != string::npos)
6204                         break;
6205         }
6206
6207         // don't remove if comments or a header follow the brace
6208         if ((nextLine_.compare(nextChar, 2, "/*") == 0)
6209                 || (nextLine_.compare(nextChar, 2, "//") == 0)
6210                 || (isCharPotentialHeader(nextLine_, nextChar)
6211                     && ASBase::findHeader(nextLine_, nextChar, headers) != nullptr))
6212                 return false;
6213
6214         // find the next semi-colon
6215         size_t nextSemiColon = nextChar;
6216         if (nextLine_[nextChar] != ';')
6217                 nextSemiColon = findNextChar(nextLine_, ';', nextChar + 1);
6218         if (nextSemiColon == string::npos)
6219                 return false;
6220
6221         // find the closing brace
6222         isFirstLine = true;
6223         nextChar = nextSemiColon + 1;
6224         while (stream.hasMoreLines() || isFirstLine)
6225         {
6226                 if (isFirstLine)
6227                         isFirstLine = false;
6228                 else
6229                 {
6230                         nextLine_ = stream.peekNextLine();
6231                         nextChar = 0;
6232                 }
6233                 nextChar = nextLine_.find_first_not_of(" \t", nextChar);
6234                 if (nextChar != string::npos)
6235                         break;
6236         }
6237         if (nextLine_.length() == 0 || nextLine_[nextChar] != '}')
6238                 return false;
6239
6240         // remove opening brace
6241         currentLine[charNum] = currentChar = ' ';
6242         assert(adjustChecksumIn(-'{'));
6243         return true;
6244 }
6245
6246 /**
6247  * Find the next character that is not in quotes or a comment.
6248  *
6249  * @param line         the line to be searched.
6250  * @param searchChar   the char to find.
6251  * @param searchStart  the start position on the line (default is 0).
6252  * @return the position on the line or string::npos if not found.
6253  */
6254 size_t ASFormatter::findNextChar(const string& line, char searchChar, int searchStart /*0*/) const
6255 {
6256         // find the next searchChar
6257         size_t i;
6258         for (i = searchStart; i < line.length(); i++)
6259         {
6260                 if (line.compare(i, 2, "//") == 0)
6261                         return string::npos;
6262                 if (line.compare(i, 2, "/*") == 0)
6263                 {
6264                         size_t endComment = line.find("*/", i + 2);
6265                         if (endComment == string::npos)
6266                                 return string::npos;
6267                         i = endComment + 2;
6268                         if (i >= line.length())
6269                                 return string::npos;
6270                 }
6271                 if (line[i] == '"'
6272                         || (line[i] == '\'' && !isDigitSeparator(line, i)))
6273                 {
6274                         char quote = line[i];
6275                         while (i < line.length())
6276                         {
6277                                 size_t endQuote = line.find(quote, i + 1);
6278                                 if (endQuote == string::npos)
6279                                         return string::npos;
6280                                 i = endQuote;
6281                                 if (line[endQuote - 1] != '\\') // check for '\"'
6282                                         break;
6283                                 if (line[endQuote - 2] == '\\') // check for '\\'
6284                                         break;
6285                         }
6286                 }
6287
6288                 if (line[i] == searchChar)
6289                         break;
6290
6291                 // for now don't process C# 'delegate' braces
6292                 // do this last in case the search char is a '{'
6293                 if (line[i] == '{')
6294                         return string::npos;
6295         }
6296         if (i >= line.length()) // didn't find searchChar
6297                 return string::npos;
6298
6299         return i;
6300 }
6301
6302 /**
6303  * Look ahead in the file to see if a struct has access modifiers.
6304  *
6305  * @param firstLine     a reference to the line to indent.
6306  * @param index         the current line index.
6307  * @return              true if the struct has access modifiers.
6308  */
6309 bool ASFormatter::isStructAccessModified(const string& firstLine, size_t index) const
6310 {
6311         assert(firstLine[index] == '{');
6312         assert(isCStyle());
6313
6314         bool isFirstLine = true;
6315         size_t braceCount = 1;
6316         string nextLine_ = firstLine.substr(index + 1);
6317         ASPeekStream stream(sourceIterator);
6318
6319         // find the first non-blank text, bypassing all comments and quotes.
6320         bool isInComment_ = false;
6321         bool isInQuote_ = false;
6322         char quoteChar_ = ' ';
6323         while (stream.hasMoreLines() || isFirstLine)
6324         {
6325                 if (isFirstLine)
6326                         isFirstLine = false;
6327                 else
6328                         nextLine_ = stream.peekNextLine();
6329                 // parse the line
6330                 for (size_t i = 0; i < nextLine_.length(); i++)
6331                 {
6332                         if (isWhiteSpace(nextLine_[i]))
6333                                 continue;
6334                         if (nextLine_.compare(i, 2, "/*") == 0)
6335                                 isInComment_ = true;
6336                         if (isInComment_)
6337                         {
6338                                 if (nextLine_.compare(i, 2, "*/") == 0)
6339                                 {
6340                                         isInComment_ = false;
6341                                         ++i;
6342                                 }
6343                                 continue;
6344                         }
6345                         if (nextLine_[i] == '\\')
6346                         {
6347                                 ++i;
6348                                 continue;
6349                         }
6350
6351                         if (isInQuote_)
6352                         {
6353                                 if (nextLine_[i] == quoteChar_)
6354                                         isInQuote_ = false;
6355                                 continue;
6356                         }
6357
6358                         if (nextLine_[i] == '"'
6359                                 || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i)))
6360                         {
6361                                 isInQuote_ = true;
6362                                 quoteChar_ = nextLine_[i];
6363                                 continue;
6364                         }
6365                         if (nextLine_.compare(i, 2, "//") == 0)
6366                         {
6367                                 i = nextLine_.length();
6368                                 continue;
6369                         }
6370                         // handle braces
6371                         if (nextLine_[i] == '{')
6372                                 ++braceCount;
6373                         if (nextLine_[i] == '}')
6374                                 --braceCount;
6375                         if (braceCount == 0)
6376                                 return false;
6377                         // check for access modifiers
6378                         if (isCharPotentialHeader(nextLine_, i))
6379                         {
6380                                 if (findKeyword(nextLine_, i, AS_PUBLIC)
6381                                         || findKeyword(nextLine_, i, AS_PRIVATE)
6382                                         || findKeyword(nextLine_, i, AS_PROTECTED))
6383                                         return true;
6384                                 string name = getCurrentWord(nextLine_, i);
6385                                 i += name.length() - 1;
6386                         }
6387                 }       // end of for loop
6388         }       // end of while loop
6389
6390         return false;
6391 }
6392
6393 /**
6394 * Look ahead in the file to see if a preprocessor block is indentable.
6395 *
6396 * @param firstLine     a reference to the line to indent.
6397 * @param index         the current line index.
6398 * @return              true if the block is indentable.
6399 */
6400 bool ASFormatter::isIndentablePreprocessorBlock(const string& firstLine, size_t index)
6401 {
6402         assert(firstLine[index] == '#');
6403
6404         bool isFirstLine = true;
6405         bool isInIndentableBlock = false;
6406         bool blockContainsBraces = false;
6407         bool blockContainsDefineContinuation = false;
6408         bool isInClassConstructor = false;
6409         bool isPotentialHeaderGuard = false;    // ifndef is first preproc statement
6410         bool isPotentialHeaderGuard2 = false;   // define is within the first proproc
6411         int  numBlockIndents = 0;
6412         int  lineParenCount = 0;
6413         string nextLine_ = firstLine.substr(index);
6414         auto stream = make_shared<ASPeekStream>(sourceIterator);
6415
6416         // find end of the block, bypassing all comments and quotes.
6417         bool isInComment_ = false;
6418         bool isInQuote_ = false;
6419         char quoteChar_ = ' ';
6420         while (stream->hasMoreLines() || isFirstLine)
6421         {
6422                 if (isFirstLine)
6423                         isFirstLine = false;
6424                 else
6425                         nextLine_ = stream->peekNextLine();
6426                 // parse the line
6427                 for (size_t i = 0; i < nextLine_.length(); i++)
6428                 {
6429                         if (isWhiteSpace(nextLine_[i]))
6430                                 continue;
6431                         if (nextLine_.compare(i, 2, "/*") == 0)
6432                                 isInComment_ = true;
6433                         if (isInComment_)
6434                         {
6435                                 if (nextLine_.compare(i, 2, "*/") == 0)
6436                                 {
6437                                         isInComment_ = false;
6438                                         ++i;
6439                                 }
6440                                 continue;
6441                         }
6442                         if (nextLine_[i] == '\\')
6443                         {
6444                                 ++i;
6445                                 continue;
6446                         }
6447                         if (isInQuote_)
6448                         {
6449                                 if (nextLine_[i] == quoteChar_)
6450                                         isInQuote_ = false;
6451                                 continue;
6452                         }
6453
6454                         if (nextLine_[i] == '"'
6455                                 || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i)))
6456                         {
6457                                 isInQuote_ = true;
6458                                 quoteChar_ = nextLine_[i];
6459                                 continue;
6460                         }
6461                         if (nextLine_.compare(i, 2, "//") == 0)
6462                         {
6463                                 i = nextLine_.length();
6464                                 continue;
6465                         }
6466                         // handle preprocessor statement
6467                         if (nextLine_[i] == '#')
6468                         {
6469                                 string preproc = ASBeautifier::extractPreprocessorStatement(nextLine_);
6470                                 if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef
6471                                 {
6472                                         numBlockIndents += 1;
6473                                         isInIndentableBlock = true;
6474                                         // flag first preprocessor conditional for header include guard check
6475                                         if (!processedFirstConditional)
6476                                         {
6477                                                 processedFirstConditional = true;
6478                                                 isFirstPreprocConditional = true;
6479                                                 if (isNDefPreprocStatement(nextLine_, preproc))
6480                                                         isPotentialHeaderGuard = true;
6481                                         }
6482                                 }
6483                                 else if (preproc == "endif")
6484                                 {
6485                                         if (numBlockIndents > 0)
6486                                                 numBlockIndents -= 1;
6487                                         // must exit BOTH loops
6488                                         if (numBlockIndents == 0)
6489                                                 goto EndOfWhileLoop;
6490                                 }
6491                                 else if (preproc == "define")
6492                                 {
6493                                         if (nextLine_[nextLine_.length() - 1] == '\\')
6494                                                 blockContainsDefineContinuation = true;
6495                                         // check for potential header include guards
6496                                         else if (isPotentialHeaderGuard && numBlockIndents == 1)
6497                                                 isPotentialHeaderGuard2 = true;
6498                                 }
6499                                 i = nextLine_.length();
6500                                 continue;
6501                         }
6502                         // handle exceptions
6503                         if (nextLine_[i] == '{' || nextLine_[i] == '}')
6504                                 blockContainsBraces = true;
6505                         else if (nextLine_[i] == '(')
6506                                 ++lineParenCount;
6507                         else if (nextLine_[i] == ')')
6508                                 --lineParenCount;
6509                         else if (nextLine_[i] == ':')
6510                         {
6511                                 // check for '::'
6512                                 if (nextLine_.length() > i && nextLine_[i + 1] == ':')
6513                                         ++i;
6514                                 else
6515                                         isInClassConstructor = true;
6516                         }
6517                         // bypass unnecessary parsing - must exit BOTH loops
6518                         if (blockContainsBraces || isInClassConstructor || blockContainsDefineContinuation)
6519                                 goto EndOfWhileLoop;
6520                 }       // end of for loop, end of line
6521                 if (lineParenCount != 0)
6522                         break;
6523         }       // end of while loop
6524 EndOfWhileLoop:
6525         preprocBlockEnd = sourceIterator->tellg();
6526         if (preprocBlockEnd < 0)
6527                 preprocBlockEnd = sourceIterator->getStreamLength();
6528         if (blockContainsBraces
6529                 || isInClassConstructor
6530                 || blockContainsDefineContinuation
6531                 || lineParenCount != 0
6532                 || numBlockIndents != 0)
6533                 isInIndentableBlock = false;
6534         // find next executable instruction
6535         // this WILL RESET the get pointer
6536         string nextText = peekNextText("", false, stream);
6537         // bypass header include guards
6538         if (isFirstPreprocConditional)
6539         {
6540                 isFirstPreprocConditional = false;
6541                 if (nextText.empty() && isPotentialHeaderGuard2)
6542                 {
6543                         isInIndentableBlock = false;
6544                         preprocBlockEnd = 0;
6545                 }
6546         }
6547         // this allows preprocessor blocks within this block to be indented
6548         if (!isInIndentableBlock)
6549                 preprocBlockEnd = 0;
6550         // peekReset() is done by previous peekNextText()
6551         return isInIndentableBlock;
6552 }
6553
6554 bool ASFormatter::isNDefPreprocStatement(const string& nextLine_, const string& preproc) const
6555 {
6556         if (preproc == "ifndef")
6557                 return true;
6558         // check for '!defined'
6559         if (preproc == "if")
6560         {
6561                 size_t i = nextLine_.find('!');
6562                 if (i == string::npos)
6563                         return false;
6564                 i = nextLine_.find_first_not_of(" \t", ++i);
6565                 if (i != string::npos && nextLine_.compare(i, 7, "defined") == 0)
6566                         return true;
6567         }
6568         return false;
6569 }
6570
6571 /**
6572  * Check to see if this is an EXEC SQL statement.
6573  *
6574  * @param line          a reference to the line to indent.
6575  * @param index         the current line index.
6576  * @return              true if the statement is EXEC SQL.
6577  */
6578 bool ASFormatter::isExecSQL(const string& line, size_t index) const
6579 {
6580         if (line[index] != 'e' && line[index] != 'E')   // quick check to reject most
6581                 return false;
6582         string word;
6583         if (isCharPotentialHeader(line, index))
6584                 word = getCurrentWord(line, index);
6585         for (size_t i = 0; i < word.length(); i++)
6586                 word[i] = (char) toupper(word[i]);
6587         if (word != "EXEC")
6588                 return false;
6589         size_t index2 = index + word.length();
6590         index2 = line.find_first_not_of(" \t", index2);
6591         if (index2 == string::npos)
6592                 return false;
6593         word.erase();
6594         if (isCharPotentialHeader(line, index2))
6595                 word = getCurrentWord(line, index2);
6596         for (size_t i = 0; i < word.length(); i++)
6597                 word[i] = (char) toupper(word[i]);
6598         if (word != "SQL")
6599                 return false;
6600         return true;
6601 }
6602
6603 /**
6604  * The continuation lines must be adjusted so the leading spaces
6605  *     is equivalent to the text on the opening line.
6606  *
6607  * Updates currentLine and charNum.
6608  */
6609 void ASFormatter::trimContinuationLine()
6610 {
6611         size_t len = currentLine.length();
6612         size_t tabSize = getTabLength();
6613         charNum = 0;
6614
6615         if (leadingSpaces > 0 && len > 0)
6616         {
6617                 size_t i;
6618                 size_t continuationIncrementIn = 0;
6619                 for (i = 0; (i < len) && (i + continuationIncrementIn < leadingSpaces); i++)
6620                 {
6621                         if (!isWhiteSpace(currentLine[i]))              // don't delete any text
6622                         {
6623                                 if (i < continuationIncrementIn)
6624                                         leadingSpaces = i + tabIncrementIn;
6625                                 continuationIncrementIn = tabIncrementIn;
6626                                 break;
6627                         }
6628                         if (currentLine[i] == '\t')
6629                                 continuationIncrementIn += tabSize - 1 - ((continuationIncrementIn + i) % tabSize);
6630                 }
6631
6632                 if ((int) continuationIncrementIn == tabIncrementIn)
6633                         charNum = i;
6634                 else
6635                 {
6636                         // build a new line with the equivalent leading chars
6637                         string newLine;
6638                         int leadingChars = 0;
6639                         if ((int) leadingSpaces > tabIncrementIn)
6640                                 leadingChars = leadingSpaces - tabIncrementIn;
6641                         newLine.append(leadingChars, ' ');
6642                         newLine.append(currentLine, i, len - i);
6643                         currentLine = newLine;
6644                         charNum = leadingChars;
6645                         if (currentLine.length() == 0)
6646                                 currentLine = string(" ");        // a null is inserted if this is not done
6647                 }
6648                 if (i >= len)
6649                         charNum = 0;
6650         }
6651 }
6652
6653 /**
6654  * Determine if a header is a closing header
6655  *
6656  * @return      true if the header is a closing header.
6657  */
6658 bool ASFormatter::isClosingHeader(const string* header) const
6659 {
6660         return (header == &AS_ELSE
6661                 || header == &AS_CATCH
6662                 || header == &AS_FINALLY);
6663 }
6664
6665 /**
6666  * Determine if a * following a closing paren is immediately.
6667  * after a cast. If so it is a deference and not a multiply.
6668  * e.g. "(int*) *ptr" is a deference.
6669  */
6670 bool ASFormatter::isImmediatelyPostCast() const
6671 {
6672         assert(previousNonWSChar == ')' && currentChar == '*');
6673         // find preceding closing paren on currentLine or readyFormattedLine
6674         string line;            // currentLine or readyFormattedLine
6675         size_t paren = currentLine.rfind(')', charNum);
6676         if (paren != string::npos)
6677                 line = currentLine;
6678         // if not on currentLine it must be on the previous line
6679         else
6680         {
6681                 line = readyFormattedLine;
6682                 paren = line.rfind(')');
6683                 if (paren == string::npos)
6684                         return false;
6685         }
6686         if (paren == 0)
6687                 return false;
6688
6689         // find character preceding the closing paren
6690         size_t lastChar = line.find_last_not_of(" \t", paren - 1);
6691         if (lastChar == string::npos)
6692                 return false;
6693         // check for pointer cast
6694         if (line[lastChar] == '*')
6695                 return true;
6696         return false;
6697 }
6698
6699 /**
6700  * Determine if a < is a template definition or instantiation.
6701  * Sets the class variables isInTemplate and templateDepth.
6702  */
6703 void ASFormatter::checkIfTemplateOpener()
6704 {
6705         assert(!isInTemplate && currentChar == '<');
6706
6707         // find first char after the '<' operators
6708         size_t firstChar = currentLine.find_first_not_of("< \t", charNum);
6709         if (firstChar == string::npos
6710                 || currentLine[firstChar] == '=')
6711         {
6712                 // this is not a template -> leave...
6713                 isInTemplate = false;
6714                 return;
6715         }
6716
6717         bool isFirstLine = true;
6718         int parenDepth_ = 0;
6719         int maxTemplateDepth = 0;
6720         templateDepth = 0;
6721         string nextLine_ = currentLine.substr(charNum);
6722         ASPeekStream stream(sourceIterator);
6723
6724         // find the angle braces, bypassing all comments and quotes.
6725         bool isInComment_ = false;
6726         bool isInQuote_ = false;
6727         char quoteChar_ = ' ';
6728         while (stream.hasMoreLines() || isFirstLine)
6729         {
6730                 if (isFirstLine)
6731                         isFirstLine = false;
6732                 else
6733                         nextLine_ = stream.peekNextLine();
6734                 // parse the line
6735                 for (size_t i = 0; i < nextLine_.length(); i++)
6736                 {
6737                         char currentChar_ = nextLine_[i];
6738                         if (isWhiteSpace(currentChar_))
6739                                 continue;
6740                         if (nextLine_.compare(i, 2, "/*") == 0)
6741                                 isInComment_ = true;
6742                         if (isInComment_)
6743                         {
6744                                 if (nextLine_.compare(i, 2, "*/") == 0)
6745                                 {
6746                                         isInComment_ = false;
6747                                         ++i;
6748                                 }
6749                                 continue;
6750                         }
6751                         if (currentChar_ == '\\')
6752                         {
6753                                 ++i;
6754                                 continue;
6755                         }
6756
6757                         if (isInQuote_)
6758                         {
6759                                 if (currentChar_ == quoteChar_)
6760                                         isInQuote_ = false;
6761                                 continue;
6762                         }
6763
6764                         if (currentChar_ == '"'
6765                                 || (currentChar_ == '\'' && !isDigitSeparator(nextLine_, i)))
6766                         {
6767                                 isInQuote_ = true;
6768                                 quoteChar_ = currentChar_;
6769                                 continue;
6770                         }
6771                         if (nextLine_.compare(i, 2, "//") == 0)
6772                         {
6773                                 i = nextLine_.length();
6774                                 continue;
6775                         }
6776
6777                         // not in a comment or quote
6778                         if (currentChar_ == '<')
6779                         {
6780                                 ++templateDepth;
6781                                 ++maxTemplateDepth;
6782                                 continue;
6783                         }
6784                         else if (currentChar_ == '>')
6785                         {
6786                                 --templateDepth;
6787                                 if (templateDepth == 0)
6788                                 {
6789                                         if (parenDepth_ == 0)
6790                                         {
6791                                                 // this is a template!
6792                                                 isInTemplate = true;
6793                                                 templateDepth = maxTemplateDepth;
6794                                         }
6795                                         return;
6796                                 }
6797                                 continue;
6798                         }
6799                         else if (currentChar_ == '(' || currentChar_ == ')')
6800                         {
6801                                 if (currentChar_ == '(')
6802                                         ++parenDepth_;
6803                                 else
6804                                         --parenDepth_;
6805                                 if (parenDepth_ >= 0)
6806                                         continue;
6807                                 // this is not a template -> leave...
6808                                 isInTemplate = false;
6809                                 templateDepth = 0;
6810                                 return;
6811                         }
6812                         else if (nextLine_.compare(i, 2, AS_AND) == 0
6813                                  || nextLine_.compare(i, 2, AS_OR) == 0)
6814                         {
6815                                 // this is not a template -> leave...
6816                                 isInTemplate = false;
6817                                 templateDepth = 0;
6818                                 return;
6819                         }
6820                         else if (currentChar_ == ','  // comma,     e.g. A<int, char>
6821                                  || currentChar_ == '&'    // reference, e.g. A<int&>
6822                                  || currentChar_ == '*'    // pointer,   e.g. A<int*>
6823                                  || currentChar_ == '^'    // C++/CLI managed pointer, e.g. A<int^>
6824                                  || currentChar_ == ':'    // ::,        e.g. std::string
6825                                  || currentChar_ == '='    // assign     e.g. default parameter
6826                                  || currentChar_ == '['    // []         e.g. string[]
6827                                  || currentChar_ == ']'    // []         e.g. string[]
6828                                  || currentChar_ == '('    // (...)      e.g. function definition
6829                                  || currentChar_ == ')'    // (...)      e.g. function definition
6830                                  || (isJavaStyle() && currentChar_ == '?')   // Java wildcard
6831                                 )
6832                         {
6833                                 continue;
6834                         }
6835                         else if (!isLegalNameChar(currentChar_))
6836                         {
6837                                 // this is not a template -> leave...
6838                                 isInTemplate = false;
6839                                 templateDepth = 0;
6840                                 return;
6841                         }
6842                         string name = getCurrentWord(nextLine_, i);
6843                         i += name.length() - 1;
6844                 }       // end for loop
6845         }       // end while loop
6846 }
6847
6848 void ASFormatter::updateFormattedLineSplitPoints(char appendedChar)
6849 {
6850         assert(maxCodeLength != string::npos);
6851         assert(formattedLine.length() > 0);
6852
6853         if (!isOkToSplitFormattedLine())
6854                 return;
6855
6856         char nextChar = peekNextChar();
6857
6858         // don't split before an end of line comment
6859         if (nextChar == '/')
6860                 return;
6861
6862         // don't split before or after a brace
6863         if (appendedChar == '{' || appendedChar == '}'
6864                 || previousNonWSChar == '{' || previousNonWSChar == '}'
6865                 || nextChar == '{' || nextChar == '}'
6866                 || currentChar == '{' || currentChar == '}')    // currentChar tests for an appended brace
6867                 return;
6868
6869         // don't split before or after a block paren
6870         if (appendedChar == '[' || appendedChar == ']'
6871                 || previousNonWSChar == '['
6872                 || nextChar == '[' || nextChar == ']')
6873                 return;
6874
6875         if (isWhiteSpace(appendedChar))
6876         {
6877                 if (nextChar != ')'                                             // space before a closing paren
6878                         && nextChar != '('                              // space before an opening paren
6879                         && nextChar != '/'                              // space before a comment
6880                         && nextChar != ':'                              // space before a colon
6881                         && currentChar != ')'                   // appended space before and after a closing paren
6882                         && currentChar != '('                   // appended space before and after a opening paren
6883                         && previousNonWSChar != '('             // decided at the '('
6884                         // don't break before a pointer or reference aligned to type
6885                         && !(nextChar == '*'
6886                              && !isCharPotentialOperator(previousNonWSChar)
6887                              && pointerAlignment == PTR_ALIGN_TYPE)
6888                         && !(nextChar == '&'
6889                              && !isCharPotentialOperator(previousNonWSChar)
6890                              && (referenceAlignment == REF_ALIGN_TYPE
6891                                  || (referenceAlignment == REF_SAME_AS_PTR && pointerAlignment == PTR_ALIGN_TYPE)))
6892                    )
6893                 {
6894                         if (formattedLine.length() - 1 <= maxCodeLength)
6895                                 maxWhiteSpace = formattedLine.length() - 1;
6896                         else
6897                                 maxWhiteSpacePending = formattedLine.length() - 1;
6898                 }
6899         }
6900         // unpadded closing parens may split after the paren (counts as whitespace)
6901         else if (appendedChar == ')')
6902         {
6903                 if (nextChar != ')'
6904                         && nextChar != ' '
6905                         && nextChar != ';'
6906                         && nextChar != ','
6907                         && nextChar != '.'
6908                         && !(nextChar == '-' && pointerSymbolFollows()))        // check for ->
6909                 {
6910                         if (formattedLine.length() <= maxCodeLength)
6911                                 maxWhiteSpace = formattedLine.length();
6912                         else
6913                                 maxWhiteSpacePending = formattedLine.length();
6914                 }
6915         }
6916         // unpadded commas may split after the comma
6917         else if (appendedChar == ',')
6918         {
6919                 if (formattedLine.length() <= maxCodeLength)
6920                         maxComma = formattedLine.length();
6921                 else
6922                         maxCommaPending = formattedLine.length();
6923         }
6924         else if (appendedChar == '(')
6925         {
6926                 if (nextChar != ')' && nextChar != '(' && nextChar != '"' && nextChar != '\'')
6927                 {
6928                         // if follows an operator break before
6929                         size_t parenNum;
6930                         if (isCharPotentialOperator(previousNonWSChar))
6931                                 parenNum = formattedLine.length() - 1;
6932                         else
6933                                 parenNum = formattedLine.length();
6934                         if (formattedLine.length() <= maxCodeLength)
6935                                 maxParen = parenNum;
6936                         else
6937                                 maxParenPending = parenNum;
6938                 }
6939         }
6940         else if (appendedChar == ';')
6941         {
6942                 if (nextChar != ' '  && nextChar != '}' && nextChar != '/')     // check for following comment
6943                 {
6944                         if (formattedLine.length() <= maxCodeLength)
6945                                 maxSemi = formattedLine.length();
6946                         else
6947                                 maxSemiPending = formattedLine.length();
6948                 }
6949         }
6950 }
6951
6952 void ASFormatter::updateFormattedLineSplitPointsOperator(const string& sequence)
6953 {
6954         assert(maxCodeLength != string::npos);
6955         assert(formattedLine.length() > 0);
6956
6957         if (!isOkToSplitFormattedLine())
6958                 return;
6959
6960         char nextChar = peekNextChar();
6961
6962         // don't split before an end of line comment
6963         if (nextChar == '/')
6964                 return;
6965
6966         // check for logical conditional
6967         if (sequence == "||" || sequence == "&&" || sequence == "or" || sequence == "and")
6968         {
6969                 if (shouldBreakLineAfterLogical)
6970                 {
6971                         if (formattedLine.length() <= maxCodeLength)
6972                                 maxAndOr = formattedLine.length();
6973                         else
6974                                 maxAndOrPending = formattedLine.length();
6975                 }
6976                 else
6977                 {
6978                         // adjust for leading space in the sequence
6979                         size_t sequenceLength = sequence.length();
6980                         if (formattedLine.length() > sequenceLength
6981                                 && isWhiteSpace(formattedLine[formattedLine.length() - sequenceLength - 1]))
6982                                 sequenceLength++;
6983                         if (formattedLine.length() - sequenceLength <= maxCodeLength)
6984                                 maxAndOr = formattedLine.length() - sequenceLength;
6985                         else
6986                                 maxAndOrPending = formattedLine.length() - sequenceLength;
6987                 }
6988         }
6989         // comparison operators will split after the operator (counts as whitespace)
6990         else if (sequence == "==" || sequence == "!=" || sequence == ">=" || sequence == "<=")
6991         {
6992                 if (formattedLine.length() <= maxCodeLength)
6993                         maxWhiteSpace = formattedLine.length();
6994                 else
6995                         maxWhiteSpacePending = formattedLine.length();
6996         }
6997         // unpadded operators that will split BEFORE the operator (counts as whitespace)
6998         else if (sequence == "+" || sequence == "-" || sequence == "?")
6999         {
7000                 if (charNum > 0
7001                         && !(sequence == "+" && isInExponent())
7002                         && !(sequence == "-"  && isInExponent())
7003                         && (isLegalNameChar(currentLine[charNum - 1])
7004                             || currentLine[charNum - 1] == ')'
7005                             || currentLine[charNum - 1] == ']'
7006                             || currentLine[charNum - 1] == '\"'))
7007                 {
7008                         if (formattedLine.length() - 1 <= maxCodeLength)
7009                                 maxWhiteSpace = formattedLine.length() - 1;
7010                         else
7011                                 maxWhiteSpacePending = formattedLine.length() - 1;
7012                 }
7013         }
7014         // unpadded operators that will USUALLY split AFTER the operator (counts as whitespace)
7015         else if (sequence == "=" || sequence == ":")
7016         {
7017                 // split BEFORE if the line is too long
7018                 // do NOT use <= here, must allow for a brace attached to an array
7019                 size_t splitPoint = 0;
7020                 if (formattedLine.length() < maxCodeLength)
7021                         splitPoint = formattedLine.length();
7022                 else
7023                         splitPoint = formattedLine.length() - 1;
7024                 // padded or unpadded arrays
7025                 if (previousNonWSChar == ']')
7026                 {
7027                         if (formattedLine.length() - 1 <= maxCodeLength)
7028                                 maxWhiteSpace = splitPoint;
7029                         else
7030                                 maxWhiteSpacePending = splitPoint;
7031                 }
7032                 else if (charNum > 0
7033                          && (isLegalNameChar(currentLine[charNum - 1])
7034                              || currentLine[charNum - 1] == ')'
7035                              || currentLine[charNum - 1] == ']'))
7036                 {
7037                         if (formattedLine.length() <= maxCodeLength)
7038                                 maxWhiteSpace = splitPoint;
7039                         else
7040                                 maxWhiteSpacePending = splitPoint;
7041                 }
7042         }
7043 }
7044
7045 /**
7046  * Update the split point when a pointer or reference is formatted.
7047  * The argument is the maximum index of the last whitespace character.
7048  */
7049 void ASFormatter::updateFormattedLineSplitPointsPointerOrReference(size_t index)
7050 {
7051         assert(maxCodeLength != string::npos);
7052         assert(formattedLine.length() > 0);
7053         assert(index < formattedLine.length());
7054
7055         if (!isOkToSplitFormattedLine())
7056                 return;
7057
7058         if (index < maxWhiteSpace)              // just in case
7059                 return;
7060
7061         if (index <= maxCodeLength)
7062                 maxWhiteSpace = index;
7063         else
7064                 maxWhiteSpacePending = index;
7065 }
7066
7067 bool ASFormatter::isOkToSplitFormattedLine()
7068 {
7069         assert(maxCodeLength != string::npos);
7070         // Is it OK to split the line?
7071         if (shouldKeepLineUnbroken
7072                 || isInLineComment
7073                 || isInComment
7074                 || isInQuote
7075                 || isInCase
7076                 || isInPreprocessor
7077                 || isInExecSQL
7078                 || isInAsm || isInAsmOneLine || isInAsmBlock
7079                 || isInTemplate)
7080                 return false;
7081
7082         if (!isOkToBreakBlock(braceTypeStack->back()) && currentChar != '{')
7083         {
7084                 shouldKeepLineUnbroken = true;
7085                 clearFormattedLineSplitPoints();
7086                 return false;
7087         }
7088         if (isBraceType(braceTypeStack->back(), ARRAY_TYPE))
7089         {
7090                 shouldKeepLineUnbroken = true;
7091                 if (!isBraceType(braceTypeStack->back(), ARRAY_NIS_TYPE))
7092                         clearFormattedLineSplitPoints();
7093                 return false;
7094         }
7095         return true;
7096 }
7097
7098 /* This is called if the option maxCodeLength is set.
7099  */
7100 void ASFormatter::testForTimeToSplitFormattedLine()
7101 {
7102         //      DO NOT ASSERT maxCodeLength HERE
7103         // should the line be split
7104         if (formattedLine.length() > maxCodeLength && !isLineReady)
7105         {
7106                 size_t splitPoint = findFormattedLineSplitPoint();
7107                 if (splitPoint > 0 && splitPoint < formattedLine.length())
7108                 {
7109                         string splitLine = formattedLine.substr(splitPoint);
7110                         formattedLine = formattedLine.substr(0, splitPoint);
7111                         breakLine(true);
7112                         formattedLine = splitLine;
7113                         // if break-blocks is requested and this is a one-line statement
7114                         string nextWord = ASBeautifier::getNextWord(currentLine, charNum - 1);
7115                         if (isAppendPostBlockEmptyLineRequested
7116                                 && (nextWord == "break" || nextWord == "continue"))
7117                         {
7118                                 isAppendPostBlockEmptyLineRequested = false;
7119                                 isPrependPostBlockEmptyLineRequested = true;
7120                         }
7121                         else
7122                                 isPrependPostBlockEmptyLineRequested = false;
7123                         // adjust max split points
7124                         maxAndOr = (maxAndOr > splitPoint) ? (maxAndOr - splitPoint) : 0;
7125                         maxSemi = (maxSemi > splitPoint) ? (maxSemi - splitPoint) : 0;
7126                         maxComma = (maxComma > splitPoint) ? (maxComma - splitPoint) : 0;
7127                         maxParen = (maxParen > splitPoint) ? (maxParen - splitPoint) : 0;
7128                         maxWhiteSpace = (maxWhiteSpace > splitPoint) ? (maxWhiteSpace - splitPoint) : 0;
7129                         if (maxSemiPending > 0)
7130                         {
7131                                 maxSemi = (maxSemiPending > splitPoint) ? (maxSemiPending - splitPoint) : 0;
7132                                 maxSemiPending = 0;
7133                         }
7134                         if (maxAndOrPending > 0)
7135                         {
7136                                 maxAndOr = (maxAndOrPending > splitPoint) ? (maxAndOrPending - splitPoint) : 0;
7137                                 maxAndOrPending = 0;
7138                         }
7139                         if (maxCommaPending > 0)
7140                         {
7141                                 maxComma = (maxCommaPending > splitPoint) ? (maxCommaPending - splitPoint) : 0;
7142                                 maxCommaPending = 0;
7143                         }
7144                         if (maxParenPending > 0)
7145                         {
7146                                 maxParen = (maxParenPending > splitPoint) ? (maxParenPending - splitPoint) : 0;
7147                                 maxParenPending = 0;
7148                         }
7149                         if (maxWhiteSpacePending > 0)
7150                         {
7151                                 maxWhiteSpace = (maxWhiteSpacePending > splitPoint) ? (maxWhiteSpacePending - splitPoint) : 0;
7152                                 maxWhiteSpacePending = 0;
7153                         }
7154                         // don't allow an empty formatted line
7155                         size_t firstText = formattedLine.find_first_not_of(" \t");
7156                         if (firstText == string::npos && formattedLine.length() > 0)
7157                         {
7158                                 formattedLine.erase();
7159                                 clearFormattedLineSplitPoints();
7160                                 if (isWhiteSpace(currentChar))
7161                                         for (size_t i = charNum + 1; i < currentLine.length() && isWhiteSpace(currentLine[i]); i++)
7162                                                 goForward(1);
7163                         }
7164                         else if (firstText > 0)
7165                         {
7166                                 formattedLine.erase(0, firstText);
7167                                 maxSemi = (maxSemi > firstText) ? (maxSemi - firstText) : 0;
7168                                 maxAndOr = (maxAndOr > firstText) ? (maxAndOr - firstText) : 0;
7169                                 maxComma = (maxComma > firstText) ? (maxComma - firstText) : 0;
7170                                 maxParen = (maxParen > firstText) ? (maxParen - firstText) : 0;
7171                                 maxWhiteSpace = (maxWhiteSpace > firstText) ? (maxWhiteSpace - firstText) : 0;
7172                         }
7173                         // reset formattedLineCommentNum
7174                         if (formattedLineCommentNum != string::npos)
7175                         {
7176                                 formattedLineCommentNum = formattedLine.find("//");
7177                                 if (formattedLineCommentNum == string::npos)
7178                                         formattedLineCommentNum = formattedLine.find("/*");
7179                         }
7180                 }
7181         }
7182 }
7183
7184 size_t ASFormatter::findFormattedLineSplitPoint() const
7185 {
7186         assert(maxCodeLength != string::npos);
7187         // determine where to split
7188         size_t minCodeLength = 10;
7189         size_t splitPoint = 0;
7190         splitPoint = maxSemi;
7191         if (maxAndOr >= minCodeLength)
7192                 splitPoint = maxAndOr;
7193         if (splitPoint < minCodeLength)
7194         {
7195                 splitPoint = maxWhiteSpace;
7196                 // use maxParen instead if it is long enough
7197                 if (maxParen > splitPoint
7198                         || maxParen >= maxCodeLength * .7)
7199                         splitPoint = maxParen;
7200                 // use maxComma instead if it is long enough
7201                 // increasing the multiplier causes more splits at whitespace
7202                 if (maxComma > splitPoint
7203                         || maxComma >= maxCodeLength * .3)
7204                         splitPoint = maxComma;
7205         }
7206         // replace split point with first available break point
7207         if (splitPoint < minCodeLength)
7208         {
7209                 splitPoint = string::npos;
7210                 if (maxSemiPending > 0 && maxSemiPending < splitPoint)
7211                         splitPoint = maxSemiPending;
7212                 if (maxAndOrPending > 0 && maxAndOrPending < splitPoint)
7213                         splitPoint = maxAndOrPending;
7214                 if (maxCommaPending > 0 && maxCommaPending < splitPoint)
7215                         splitPoint = maxCommaPending;
7216                 if (maxParenPending > 0 && maxParenPending < splitPoint)
7217                         splitPoint = maxParenPending;
7218                 if (maxWhiteSpacePending > 0 && maxWhiteSpacePending < splitPoint)
7219                         splitPoint = maxWhiteSpacePending;
7220                 if (splitPoint == string::npos)
7221                         splitPoint = 0;
7222         }
7223         // if remaining line after split is too long
7224         else if (formattedLine.length() - splitPoint > maxCodeLength)
7225         {
7226                 // if end of the currentLine, find a new split point
7227                 size_t newCharNum;
7228                 if (isCharPotentialHeader(currentLine, charNum))
7229                         newCharNum = getCurrentWord(currentLine, charNum).length() + charNum;
7230                 else
7231                         newCharNum = charNum + 2;
7232                 if (newCharNum + 1 > currentLine.length())
7233                 {
7234                         // don't move splitPoint from before a conditional to after
7235                         if (maxWhiteSpace > splitPoint + 3)
7236                                 splitPoint = maxWhiteSpace;
7237                         if (maxParen > splitPoint)
7238                                 splitPoint = maxParen;
7239                 }
7240         }
7241
7242         return splitPoint;
7243 }
7244
7245 void ASFormatter::clearFormattedLineSplitPoints()
7246 {
7247         maxSemi = 0;
7248         maxAndOr = 0;
7249         maxComma = 0;
7250         maxParen = 0;
7251         maxWhiteSpace = 0;
7252         maxSemiPending = 0;
7253         maxAndOrPending = 0;
7254         maxCommaPending = 0;
7255         maxParenPending = 0;
7256         maxWhiteSpacePending = 0;
7257 }
7258
7259 /**
7260  * Check if a pointer symbol (->) follows on the currentLine.
7261  */
7262 bool ASFormatter::pointerSymbolFollows() const
7263 {
7264         size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
7265         if (peekNum == string::npos || currentLine.compare(peekNum, 2, "->") != 0)
7266                 return false;
7267         return true;
7268 }
7269
7270 /**
7271  * Compute the input checksum.
7272  * This is called as an assert so it for is debug config only
7273  */
7274 bool ASFormatter::computeChecksumIn(const string& currentLine_)
7275 {
7276         for (size_t i = 0; i < currentLine_.length(); i++)
7277                 if (!isWhiteSpace(currentLine_[i]))
7278                         checksumIn += currentLine_[i];
7279         return true;
7280 }
7281
7282 /**
7283  * Adjust the input checksum for deleted chars.
7284  * This is called as an assert so it for is debug config only
7285  */
7286 bool ASFormatter::adjustChecksumIn(int adjustment)
7287 {
7288         checksumIn += adjustment;
7289         return true;
7290 }
7291
7292 /**
7293  * get the value of checksumIn for unit testing
7294  *
7295  * @return   checksumIn.
7296  */
7297 size_t ASFormatter::getChecksumIn() const
7298 {
7299         return checksumIn;
7300 }
7301
7302 /**
7303  * Compute the output checksum.
7304  * This is called as an assert so it is for debug config only
7305  */
7306 bool ASFormatter::computeChecksumOut(const string& beautifiedLine)
7307 {
7308         for (size_t i = 0; i < beautifiedLine.length(); i++)
7309                 if (!isWhiteSpace(beautifiedLine[i]))
7310                         checksumOut += beautifiedLine[i];
7311         return true;
7312 }
7313
7314 /**
7315  * Return isLineReady for the final check at end of file.
7316  */
7317 bool ASFormatter::getIsLineReady() const
7318 {
7319         return isLineReady;
7320 }
7321
7322 /**
7323  * get the value of checksumOut for unit testing
7324  *
7325  * @return   checksumOut.
7326  */
7327 size_t ASFormatter::getChecksumOut() const
7328 {
7329         return checksumOut;
7330 }
7331
7332 /**
7333  * Return the difference in checksums.
7334  * If zero all is okay.
7335  */
7336 int ASFormatter::getChecksumDiff() const
7337 {
7338         return checksumOut - checksumIn;
7339 }
7340
7341 // for unit testing
7342 int ASFormatter::getFormatterFileType() const
7343 {
7344         return formatterFileType;
7345 }
7346
7347 // Check if an operator follows the next word.
7348 // The next word must be a legal name.
7349 const string* ASFormatter::getFollowingOperator() const
7350 {
7351         // find next word
7352         size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);
7353         if (nextNum == string::npos)
7354                 return nullptr;
7355
7356         if (!isLegalNameChar(currentLine[nextNum]))
7357                 return nullptr;
7358
7359         // bypass next word and following spaces
7360         while (nextNum < currentLine.length())
7361         {
7362                 if (!isLegalNameChar(currentLine[nextNum])
7363                         && !isWhiteSpace(currentLine[nextNum]))
7364                         break;
7365                 nextNum++;
7366         }
7367
7368         if (nextNum >= currentLine.length()
7369                 || !isCharPotentialOperator(currentLine[nextNum])
7370                 || currentLine[nextNum] == '/')         // comment
7371                 return nullptr;
7372
7373         const string* newOperator = ASBase::findOperator(currentLine, nextNum, operators);
7374         return newOperator;
7375 }
7376
7377 // Check following data to determine if the current character is an array operator.
7378 bool ASFormatter::isArrayOperator() const
7379 {
7380         assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
7381         assert(isBraceType(braceTypeStack->back(), ARRAY_TYPE));
7382
7383         // find next word
7384         size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);
7385         if (nextNum == string::npos)
7386                 return false;
7387
7388         if (!isLegalNameChar(currentLine[nextNum]))
7389                 return false;
7390
7391         // bypass next word and following spaces
7392         while (nextNum < currentLine.length())
7393         {
7394                 if (!isLegalNameChar(currentLine[nextNum])
7395                         && !isWhiteSpace(currentLine[nextNum]))
7396                         break;
7397                 nextNum++;
7398         }
7399
7400         // check for characters that indicate an operator
7401         if (currentLine[nextNum] == ','
7402                 || currentLine[nextNum] == '}'
7403                 || currentLine[nextNum] == ')'
7404                 || currentLine[nextNum] == '(')
7405                 return true;
7406         return false;
7407 }
7408
7409 // Reset the flags that indicate various statement information.
7410 void ASFormatter::resetEndOfStatement()
7411 {
7412         foundQuestionMark = false;
7413         foundNamespaceHeader = false;
7414         foundClassHeader = false;
7415         foundStructHeader = false;
7416         foundInterfaceHeader = false;
7417         foundPreDefinitionHeader = false;
7418         foundPreCommandHeader = false;
7419         foundPreCommandMacro = false;
7420         foundTrailingReturnType = false;
7421         foundCastOperator = false;
7422         isInPotentialCalculation = false;
7423         isSharpAccessor = false;
7424         isSharpDelegate = false;
7425         isInObjCMethodDefinition = false;
7426         isInObjCInterface = false;
7427         isInObjCSelector = false;
7428         isInEnum = false;
7429         isInExternC = false;
7430         elseHeaderFollowsComments = false;
7431         nonInStatementBrace = 0;
7432         while (!questionMarkStack->empty())
7433                 questionMarkStack->pop_back();
7434 }
7435
7436 // Find the colon alignment for Objective-C method definitions and method calls.
7437 int ASFormatter::findObjCColonAlignment() const
7438 {
7439         assert(currentChar == '+' || currentChar == '-' || currentChar == '[');
7440         assert(getAlignMethodColon());
7441
7442         bool isFirstLine = true;
7443         bool haveFirstColon = false;
7444         bool foundMethodColon = false;
7445         bool isInComment_ = false;
7446         bool isInQuote_ = false;
7447         char quoteChar_ = ' ';
7448         int  sqBracketCount = 0;
7449         int  colonAdjust = 0;
7450         int  colonAlign = 0;
7451         string nextLine_ = currentLine;
7452         ASPeekStream stream(sourceIterator);
7453
7454         // peek next line
7455         while (sourceIterator->hasMoreLines() || isFirstLine)
7456         {
7457                 if (!isFirstLine)
7458                         nextLine_ = stream.peekNextLine();
7459                 // parse the line
7460                 haveFirstColon = false;
7461                 nextLine_ = ASBeautifier::trim(nextLine_);
7462                 for (size_t i = 0; i < nextLine_.length(); i++)
7463                 {
7464                         if (isWhiteSpace(nextLine_[i]))
7465                                 continue;
7466                         if (nextLine_.compare(i, 2, "/*") == 0)
7467                                 isInComment_ = true;
7468                         if (isInComment_)
7469                         {
7470                                 if (nextLine_.compare(i, 2, "*/") == 0)
7471                                 {
7472                                         isInComment_ = false;
7473                                         ++i;
7474                                 }
7475                                 continue;
7476                         }
7477                         if (nextLine_[i] == '\\')
7478                         {
7479                                 ++i;
7480                                 continue;
7481                         }
7482                         if (isInQuote_)
7483                         {
7484                                 if (nextLine_[i] == quoteChar_)
7485                                         isInQuote_ = false;
7486                                 continue;
7487                         }
7488
7489                         if (nextLine_[i] == '"'
7490                                 || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i)))
7491                         {
7492                                 isInQuote_ = true;
7493                                 quoteChar_ = nextLine_[i];
7494                                 continue;
7495                         }
7496                         if (nextLine_.compare(i, 2, "//") == 0)
7497                         {
7498                                 i = nextLine_.length();
7499                                 continue;
7500                         }
7501                         // process the current char
7502                         if ((nextLine_[i] == '{' && (currentChar == '-' || currentChar == '+'))
7503                                 || nextLine_[i] == ';')
7504                                 goto EndOfWhileLoop;       // end of method definition
7505                         if (nextLine_[i] == ']')
7506                         {
7507                                 --sqBracketCount;
7508                                 if (sqBracketCount == 0)
7509                                         goto EndOfWhileLoop;   // end of method call
7510                         }
7511                         if (nextLine_[i] == '[')
7512                                 ++sqBracketCount;
7513                         if (isFirstLine)         // colon align does not include the first line
7514                                 continue;
7515                         if (sqBracketCount > 1)
7516                                 continue;
7517                         if (haveFirstColon)  // multiple colons per line
7518                                 continue;
7519                         // compute colon adjustment
7520                         if (nextLine_[i] == ':')
7521                         {
7522                                 haveFirstColon = true;
7523                                 foundMethodColon = true;
7524                                 if (shouldPadMethodColon)
7525                                 {
7526                                         int spacesStart;
7527                                         for (spacesStart = i; spacesStart > 0; spacesStart--)
7528                                                 if (!isWhiteSpace(nextLine_[spacesStart - 1]))
7529                                                         break;
7530                                         int spaces = i - spacesStart;
7531                                         if (objCColonPadMode == COLON_PAD_ALL || objCColonPadMode == COLON_PAD_BEFORE)
7532                                                 colonAdjust = 1 - spaces;
7533                                         else if (objCColonPadMode == COLON_PAD_NONE || objCColonPadMode == COLON_PAD_AFTER)
7534                                                 colonAdjust = 0 - spaces;
7535                                 }
7536                                 // compute alignment
7537                                 int colonPosition = i + colonAdjust;
7538                                 if (colonPosition > colonAlign)
7539                                         colonAlign = colonPosition;
7540                         }
7541                 }       // end of for loop
7542                 isFirstLine = false;
7543         }       // end of while loop
7544 EndOfWhileLoop:
7545         if (!foundMethodColon)
7546                 colonAlign = -1;
7547         return colonAlign;
7548 }
7549
7550 // pad an Objective-C method colon
7551 void ASFormatter::padObjCMethodColon()
7552 {
7553         assert(currentChar == ':');
7554         int commentAdjust = 0;
7555         char nextChar = peekNextChar();
7556         if (objCColonPadMode == COLON_PAD_NONE
7557                 || objCColonPadMode == COLON_PAD_AFTER
7558                 || nextChar == ')')
7559         {
7560                 // remove spaces before
7561                 for (int i = formattedLine.length() - 1; (i > -1) && isWhiteSpace(formattedLine[i]); i--)
7562                 {
7563                         formattedLine.erase(i);
7564                         --commentAdjust;
7565                 }
7566         }
7567         else
7568         {
7569                 // pad space before
7570                 for (int i = formattedLine.length() - 1; (i > 0) && isWhiteSpace(formattedLine[i]); i--)
7571                         if (isWhiteSpace(formattedLine[i - 1]))
7572                         {
7573                                 formattedLine.erase(i);
7574                                 --commentAdjust;
7575                         }
7576                 appendSpacePad();
7577         }
7578         if (objCColonPadMode == COLON_PAD_NONE
7579                 || objCColonPadMode == COLON_PAD_BEFORE
7580                 || nextChar == ')')
7581         {
7582                 // remove spaces after
7583                 int nextText = currentLine.find_first_not_of(" \t", charNum + 1);
7584                 if (nextText == (int)string::npos)
7585                         nextText = currentLine.length();
7586                 int spaces = nextText - charNum - 1;
7587                 if (spaces > 0)
7588                 {
7589                         // do not use goForward here
7590                         currentLine.erase(charNum + 1, spaces);
7591                         spacePadNum -= spaces;
7592                 }
7593         }
7594         else
7595         {
7596                 // pad space after
7597                 int nextText = currentLine.find_first_not_of(" \t", charNum + 1);
7598                 if (nextText == (int)string::npos)
7599                         nextText = currentLine.length();
7600                 int spaces = nextText - charNum - 1;
7601                 if (spaces == 0)
7602                 {
7603                         currentLine.insert(charNum + 1, 1, ' ');
7604                         spacePadNum += 1;
7605                 }
7606                 else if (spaces > 1)
7607                 {
7608                         // do not use goForward here
7609                         currentLine.erase(charNum + 1, spaces - 1);
7610                         spacePadNum -= spaces - 1;
7611                 }
7612         }
7613         spacePadNum += commentAdjust;
7614 }
7615
7616 // Remove the leading '*' from a comment line and indent to the next tab.
7617 void ASFormatter::stripCommentPrefix()
7618 {
7619         int firstChar = formattedLine.find_first_not_of(" \t");
7620         if (firstChar < 0)
7621                 return;
7622
7623         if (isInCommentStartLine)
7624         {
7625                 // comment opener must begin the line
7626                 if (formattedLine.compare(firstChar, 2, "/*") != 0)
7627                         return;
7628                 int commentOpener = firstChar;
7629                 // ignore single line comments
7630                 int commentEnd = formattedLine.find("*/", firstChar + 2);
7631                 if (commentEnd != -1)
7632                         return;
7633                 // first char after the comment opener must be at least one indent
7634                 int followingText = formattedLine.find_first_not_of(" \t", commentOpener + 2);
7635                 if (followingText < 0)
7636                         return;
7637                 if (formattedLine[followingText] == '*' || formattedLine[followingText] == '!')
7638                         followingText = formattedLine.find_first_not_of(" \t", followingText + 1);
7639                 if (followingText < 0)
7640                         return;
7641                 if (formattedLine[followingText] == '*')
7642                         return;
7643                 int indentLen = getIndentLength();
7644                 int followingTextIndent = followingText - commentOpener;
7645                 if (followingTextIndent < indentLen)
7646                 {
7647                         string stringToInsert(indentLen - followingTextIndent, ' ');
7648                         formattedLine.insert(followingText, stringToInsert);
7649                 }
7650                 return;
7651         }
7652         // comment body including the closer
7653         if (formattedLine[firstChar] == '*')
7654         {
7655                 if (formattedLine.compare(firstChar, 2, "*/") == 0)
7656                 {
7657                         // line starts with an end comment
7658                         formattedLine = "*/";
7659                 }
7660                 else
7661                 {
7662                         // build a new line with one indent
7663                         int secondChar = formattedLine.find_first_not_of(" \t", firstChar + 1);
7664                         if (secondChar < 0)
7665                         {
7666                                 adjustChecksumIn(-'*');
7667                                 formattedLine.erase();
7668                                 return;
7669                         }
7670                         if (formattedLine[secondChar] == '*')
7671                                 return;
7672                         // replace the leading '*'
7673                         int indentLen = getIndentLength();
7674                         adjustChecksumIn(-'*');
7675                         // second char must be at least one indent
7676                         if (formattedLine.substr(0, secondChar).find('\t') != string::npos)
7677                         {
7678                                 formattedLine.erase(firstChar, 1);
7679                         }
7680                         else
7681                         {
7682                                 int spacesToInsert = 0;
7683                                 if (secondChar >= indentLen)
7684                                         spacesToInsert = secondChar;
7685                                 else
7686                                         spacesToInsert = indentLen;
7687                                 formattedLine = string(spacesToInsert, ' ') + formattedLine.substr(secondChar);
7688                         }
7689                         // remove a trailing '*'
7690                         int lastChar = formattedLine.find_last_not_of(" \t");
7691                         if (lastChar > -1 && formattedLine[lastChar] == '*')
7692                         {
7693                                 adjustChecksumIn(-'*');
7694                                 formattedLine[lastChar] = ' ';
7695                         }
7696                 }
7697         }
7698         else
7699         {
7700                 // first char not a '*'
7701                 // first char must be at least one indent
7702                 if (formattedLine.substr(0, firstChar).find('\t') == string::npos)
7703                 {
7704                         int indentLen = getIndentLength();
7705                         if (firstChar < indentLen)
7706                         {
7707                                 string stringToInsert(indentLen, ' ');
7708                                 formattedLine = stringToInsert + formattedLine.substr(firstChar);
7709                         }
7710                 }
7711         }
7712 }
7713
7714 }   // end namespace astyle