Add mechanisms to reformant and check code style (#128)
[openjpeg.git] / thirdparty / astyle / ASBeautifier.cpp
1 // ASBeautifier.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
14 //-----------------------------------------------------------------------------
15 // astyle namespace
16 //-----------------------------------------------------------------------------
17
18 namespace astyle {
19 //
20 // this must be global
21 static int g_preprocessorCppExternCBrace;
22
23 //-----------------------------------------------------------------------------
24 // ASBeautifier class
25 //-----------------------------------------------------------------------------
26
27 /**
28  * ASBeautifier's constructor
29  * This constructor is called only once for each source file.
30  * The cloned ASBeautifier objects are created with the copy constructor.
31  */
32 ASBeautifier::ASBeautifier()
33 {
34         waitingBeautifierStack = nullptr;
35         activeBeautifierStack = nullptr;
36         waitingBeautifierStackLengthStack = nullptr;
37         activeBeautifierStackLengthStack = nullptr;
38
39         headerStack = nullptr;
40         tempStacks = nullptr;
41         squareBracketDepthStack = nullptr;
42         blockStatementStack = nullptr;
43         parenStatementStack = nullptr;
44         braceBlockStateStack = nullptr;
45         continuationIndentStack = nullptr;
46         continuationIndentStackSizeStack = nullptr;
47         parenIndentStack = nullptr;
48         preprocIndentStack = nullptr;
49         sourceIterator = nullptr;
50         isModeManuallySet = false;
51         shouldForceTabIndentation = false;
52         setSpaceIndentation(4);
53         setContinuationIndentation(1);
54         setMinConditionalIndentOption(MINCOND_TWO);
55         setMaxContinuationIndentLength(40);
56         classInitializerIndents = 1;
57         tabLength = 0;
58         setClassIndent(false);
59         setModifierIndent(false);
60         setSwitchIndent(false);
61         setCaseIndent(false);
62         setBlockIndent(false);
63         setBraceIndent(false);
64         setBraceIndentVtk(false);
65         setNamespaceIndent(false);
66         setAfterParenIndent(false);
67         setLabelIndent(false);
68         setEmptyLineFill(false);
69         setCStyle();
70         setPreprocDefineIndent(false);
71         setPreprocConditionalIndent(false);
72         setAlignMethodColon(false);
73
74         // initialize ASBeautifier member vectors
75         beautifierFileType = 9;         // reset to an invalid type
76         headers = new vector<const string*>;
77         nonParenHeaders = new vector<const string*>;
78         assignmentOperators = new vector<const string*>;
79         nonAssignmentOperators = new vector<const string*>;
80         preBlockStatements = new vector<const string*>;
81         preCommandHeaders = new vector<const string*>;
82         indentableHeaders = new vector<const string*>;
83 }
84
85 /**
86  * ASBeautifier's copy constructor
87  * Copy the vector objects to vectors in the new ASBeautifier
88  * object so the new object can be destroyed without deleting
89  * the vector objects in the copied vector.
90  * This is the reason a copy constructor is needed.
91  *
92  * Must explicitly call the base class copy constructor.
93  */
94 ASBeautifier::ASBeautifier(const ASBeautifier& other) : ASBase(other)
95 {
96         // these don't need to copy the stack
97         waitingBeautifierStack = nullptr;
98         activeBeautifierStack = nullptr;
99         waitingBeautifierStackLengthStack = nullptr;
100         activeBeautifierStackLengthStack = nullptr;
101
102         // vector '=' operator performs a DEEP copy of all elements in the vector
103
104         headerStack = new vector<const string*>;
105         *headerStack = *other.headerStack;
106
107         tempStacks = copyTempStacks(other);
108
109         squareBracketDepthStack = new vector<int>;
110         *squareBracketDepthStack = *other.squareBracketDepthStack;
111
112         blockStatementStack = new vector<bool>;
113         *blockStatementStack = *other.blockStatementStack;
114
115         parenStatementStack = new vector<bool>;
116         *parenStatementStack = *other.parenStatementStack;
117
118         braceBlockStateStack = new vector<bool>;
119         *braceBlockStateStack = *other.braceBlockStateStack;
120
121         continuationIndentStack = new vector<int>;
122         *continuationIndentStack = *other.continuationIndentStack;
123
124         continuationIndentStackSizeStack = new vector<int>;
125         *continuationIndentStackSizeStack = *other.continuationIndentStackSizeStack;
126
127         parenIndentStack = new vector<int>;
128         *parenIndentStack = *other.parenIndentStack;
129
130         preprocIndentStack = new vector<pair<int, int> >;
131         *preprocIndentStack = *other.preprocIndentStack;
132
133         // Copy the pointers to vectors.
134         // This is ok because the original ASBeautifier object
135         // is not deleted until end of job.
136         beautifierFileType = other.beautifierFileType;
137         headers = other.headers;
138         nonParenHeaders = other.nonParenHeaders;
139         assignmentOperators = other.assignmentOperators;
140         nonAssignmentOperators = other.nonAssignmentOperators;
141         preBlockStatements = other.preBlockStatements;
142         preCommandHeaders = other.preCommandHeaders;
143         indentableHeaders = other.indentableHeaders;
144
145         // protected variables
146         // variables set by ASFormatter
147         // must also be updated in activeBeautifierStack
148         inLineNumber = other.inLineNumber;
149         runInIndentContinuation = other.runInIndentContinuation;
150         nonInStatementBrace = other.nonInStatementBrace;
151         objCColonAlignSubsequent = other.objCColonAlignSubsequent;
152         lineCommentNoBeautify = other.lineCommentNoBeautify;
153         isElseHeaderIndent = other.isElseHeaderIndent;
154         isCaseHeaderCommentIndent = other.isCaseHeaderCommentIndent;
155         isNonInStatementArray = other.isNonInStatementArray;
156         isSharpAccessor = other.isSharpAccessor;
157         isSharpDelegate = other.isSharpDelegate;
158         isInExternC = other.isInExternC;
159         isInBeautifySQL = other.isInBeautifySQL;
160         isInIndentableStruct = other.isInIndentableStruct;
161         isInIndentablePreproc = other.isInIndentablePreproc;
162
163         // private variables
164         sourceIterator = other.sourceIterator;
165         currentHeader = other.currentHeader;
166         previousLastLineHeader = other.previousLastLineHeader;
167         probationHeader = other.probationHeader;
168         lastLineHeader = other.lastLineHeader;
169         indentString = other.indentString;
170         verbatimDelimiter = other.verbatimDelimiter;
171         isInQuote = other.isInQuote;
172         isInVerbatimQuote = other.isInVerbatimQuote;
173         haveLineContinuationChar = other.haveLineContinuationChar;
174         isInAsm = other.isInAsm;
175         isInAsmOneLine = other.isInAsmOneLine;
176         isInAsmBlock = other.isInAsmBlock;
177         isInComment = other.isInComment;
178         isInPreprocessorComment = other.isInPreprocessorComment;
179         isInRunInComment = other.isInRunInComment;
180         isInCase = other.isInCase;
181         isInQuestion = other.isInQuestion;
182         isContinuation = other.isContinuation;
183         isInHeader = other.isInHeader;
184         isInTemplate = other.isInTemplate;
185         isInDefine = other.isInDefine;
186         isInDefineDefinition = other.isInDefineDefinition;
187         classIndent = other.classIndent;
188         isIndentModeOff = other.isIndentModeOff;
189         isInClassHeader = other.isInClassHeader;
190         isInClassHeaderTab = other.isInClassHeaderTab;
191         isInClassInitializer = other.isInClassInitializer;
192         isInClass = other.isInClass;
193         isInObjCMethodDefinition = other.isInObjCMethodDefinition;
194         isInObjCMethodCall = other.isInObjCMethodCall;
195         isInObjCMethodCallFirst = other.isInObjCMethodCallFirst;
196         isImmediatelyPostObjCMethodDefinition = other.isImmediatelyPostObjCMethodDefinition;
197         isImmediatelyPostObjCMethodCall = other.isImmediatelyPostObjCMethodCall;
198         isInIndentablePreprocBlock = other.isInIndentablePreprocBlock;
199         isInObjCInterface = other.isInObjCInterface;
200         isInEnum = other.isInEnum;
201         isInEnumTypeID = other.isInEnumTypeID;
202         isInLet = other.isInLet;
203         modifierIndent = other.modifierIndent;
204         switchIndent = other.switchIndent;
205         caseIndent = other.caseIndent;
206         namespaceIndent = other.namespaceIndent;
207         braceIndent = other.braceIndent;
208         braceIndentVtk = other.braceIndentVtk;
209         blockIndent = other.blockIndent;
210         shouldIndentAfterParen = other.shouldIndentAfterParen;
211         labelIndent = other.labelIndent;
212         isInConditional = other.isInConditional;
213         isModeManuallySet = other.isModeManuallySet;
214         shouldForceTabIndentation = other.shouldForceTabIndentation;
215         emptyLineFill = other.emptyLineFill;
216         lineOpensWithLineComment = other.lineOpensWithLineComment;
217         lineOpensWithComment = other.lineOpensWithComment;
218         lineStartsInComment = other.lineStartsInComment;
219         backslashEndsPrevLine = other.backslashEndsPrevLine;
220         blockCommentNoIndent = other.blockCommentNoIndent;
221         blockCommentNoBeautify = other.blockCommentNoBeautify;
222         previousLineProbationTab = other.previousLineProbationTab;
223         lineBeginsWithOpenBrace = other.lineBeginsWithOpenBrace;
224         lineBeginsWithCloseBrace = other.lineBeginsWithCloseBrace;
225         lineBeginsWithComma = other.lineBeginsWithComma;
226         lineIsCommentOnly = other.lineIsCommentOnly;
227         lineIsLineCommentOnly = other.lineIsLineCommentOnly;
228         shouldIndentBracedLine = other.shouldIndentBracedLine;
229         isInSwitch = other.isInSwitch;
230         foundPreCommandHeader = other.foundPreCommandHeader;
231         foundPreCommandMacro = other.foundPreCommandMacro;
232         shouldAlignMethodColon = other.shouldAlignMethodColon;
233         shouldIndentPreprocDefine = other.shouldIndentPreprocDefine;
234         shouldIndentPreprocConditional = other.shouldIndentPreprocConditional;
235         indentCount = other.indentCount;
236         spaceIndentCount = other.spaceIndentCount;
237         spaceIndentObjCMethodAlignment = other.spaceIndentObjCMethodAlignment;
238         bracePosObjCMethodAlignment = other.bracePosObjCMethodAlignment;
239         colonIndentObjCMethodAlignment = other.colonIndentObjCMethodAlignment;
240         lineOpeningBlocksNum = other.lineOpeningBlocksNum;
241         lineClosingBlocksNum = other.lineClosingBlocksNum;
242         fileType = other.fileType;
243         minConditionalOption = other.minConditionalOption;
244         minConditionalIndent = other.minConditionalIndent;
245         parenDepth = other.parenDepth;
246         indentLength = other.indentLength;
247         tabLength = other.tabLength;
248         continuationIndent = other.continuationIndent;
249         blockTabCount = other.blockTabCount;
250         maxContinuationIndent = other.maxContinuationIndent;
251         classInitializerIndents = other.classInitializerIndents;
252         templateDepth = other.templateDepth;
253         squareBracketCount = other.squareBracketCount;
254         prevFinalLineSpaceIndentCount = other.prevFinalLineSpaceIndentCount;
255         prevFinalLineIndentCount = other.prevFinalLineIndentCount;
256         defineIndentCount = other.defineIndentCount;
257         preprocBlockIndent = other.preprocBlockIndent;
258         quoteChar = other.quoteChar;
259         prevNonSpaceCh = other.prevNonSpaceCh;
260         currentNonSpaceCh = other.currentNonSpaceCh;
261         currentNonLegalCh = other.currentNonLegalCh;
262         prevNonLegalCh = other.prevNonLegalCh;
263 }
264
265 /**
266  * ASBeautifier's destructor
267  */
268 ASBeautifier::~ASBeautifier()
269 {
270         deleteBeautifierContainer(waitingBeautifierStack);
271         deleteBeautifierContainer(activeBeautifierStack);
272         deleteContainer(waitingBeautifierStackLengthStack);
273         deleteContainer(activeBeautifierStackLengthStack);
274         deleteContainer(headerStack);
275         deleteTempStacksContainer(tempStacks);
276         deleteContainer(squareBracketDepthStack);
277         deleteContainer(blockStatementStack);
278         deleteContainer(parenStatementStack);
279         deleteContainer(braceBlockStateStack);
280         deleteContainer(continuationIndentStack);
281         deleteContainer(continuationIndentStackSizeStack);
282         deleteContainer(parenIndentStack);
283         deleteContainer(preprocIndentStack);
284 }
285
286 /**
287  * initialize the ASBeautifier.
288  *
289  * This init() should be called every time a ABeautifier object is to start
290  * beautifying a NEW source file.
291  * It is called only when a new ASFormatter object is created.
292  * init() receives a pointer to a ASSourceIterator object that will be
293  * used to iterate through the source code.
294  *
295  * @param iter     a pointer to the ASSourceIterator or ASStreamIterator object.
296  */
297 void ASBeautifier::init(ASSourceIterator* iter)
298 {
299         sourceIterator = iter;
300         initVectors();
301         ASBase::init(getFileType());
302         g_preprocessorCppExternCBrace = 0;
303
304         initContainer(waitingBeautifierStack, new vector<ASBeautifier*>);
305         initContainer(activeBeautifierStack, new vector<ASBeautifier*>);
306
307         initContainer(waitingBeautifierStackLengthStack, new vector<int>);
308         initContainer(activeBeautifierStackLengthStack, new vector<int>);
309
310         initContainer(headerStack, new vector<const string*>);
311
312         initTempStacksContainer(tempStacks, new vector<vector<const string*>*>);
313         tempStacks->emplace_back(new vector<const string*>);
314
315         initContainer(squareBracketDepthStack, new vector<int>);
316         initContainer(blockStatementStack, new vector<bool>);
317         initContainer(parenStatementStack, new vector<bool>);
318         initContainer(braceBlockStateStack, new vector<bool>);
319         braceBlockStateStack->push_back(true);
320         initContainer(continuationIndentStack, new vector<int>);
321         initContainer(continuationIndentStackSizeStack, new vector<int>);
322         continuationIndentStackSizeStack->emplace_back(0);
323         initContainer(parenIndentStack, new vector<int>);
324         initContainer(preprocIndentStack, new vector<pair<int, int> >);
325
326         previousLastLineHeader = nullptr;
327         currentHeader = nullptr;
328
329         isInQuote = false;
330         isInVerbatimQuote = false;
331         haveLineContinuationChar = false;
332         isInAsm = false;
333         isInAsmOneLine = false;
334         isInAsmBlock = false;
335         isInComment = false;
336         isInPreprocessorComment = false;
337         isInRunInComment = false;
338         isContinuation = false;
339         isInCase = false;
340         isInQuestion = false;
341         isIndentModeOff = false;
342         isInClassHeader = false;
343         isInClassHeaderTab = false;
344         isInClassInitializer = false;
345         isInClass = false;
346         isInObjCMethodDefinition = false;
347         isInObjCMethodCall = false;
348         isInObjCMethodCallFirst = false;
349         isImmediatelyPostObjCMethodDefinition = false;
350         isImmediatelyPostObjCMethodCall = false;
351         isInIndentablePreprocBlock = false;
352         isInObjCInterface = false;
353         isInEnum = false;
354         isInEnumTypeID = false;
355         isInLet = false;
356         isInHeader = false;
357         isInTemplate = false;
358         isInConditional = false;
359
360         indentCount = 0;
361         spaceIndentCount = 0;
362         spaceIndentObjCMethodAlignment = 0;
363         bracePosObjCMethodAlignment = 0;
364         colonIndentObjCMethodAlignment = 0;
365         lineOpeningBlocksNum = 0;
366         lineClosingBlocksNum = 0;
367         templateDepth = 0;
368         squareBracketCount = 0;
369         parenDepth = 0;
370         blockTabCount = 0;
371         prevFinalLineSpaceIndentCount = 0;
372         prevFinalLineIndentCount = 0;
373         defineIndentCount = 0;
374         preprocBlockIndent = 0;
375         prevNonSpaceCh = '{';
376         currentNonSpaceCh = '{';
377         prevNonLegalCh = '{';
378         currentNonLegalCh = '{';
379         quoteChar = ' ';
380         probationHeader = nullptr;
381         lastLineHeader = nullptr;
382         backslashEndsPrevLine = false;
383         lineOpensWithLineComment = false;
384         lineOpensWithComment = false;
385         lineStartsInComment = false;
386         isInDefine = false;
387         isInDefineDefinition = false;
388         lineCommentNoBeautify = false;
389         isElseHeaderIndent = false;
390         isCaseHeaderCommentIndent = false;
391         blockCommentNoIndent = false;
392         blockCommentNoBeautify = false;
393         previousLineProbationTab = false;
394         lineBeginsWithOpenBrace = false;
395         lineBeginsWithCloseBrace = false;
396         lineBeginsWithComma = false;
397         lineIsCommentOnly = false;
398         lineIsLineCommentOnly = false;
399         shouldIndentBracedLine = true;
400         isInSwitch = false;
401         foundPreCommandHeader = false;
402         foundPreCommandMacro = false;
403
404         isNonInStatementArray = false;
405         isSharpAccessor = false;
406         isSharpDelegate = false;
407         isInExternC = false;
408         isInBeautifySQL = false;
409         isInIndentableStruct = false;
410         isInIndentablePreproc = false;
411         inLineNumber = 0;
412         runInIndentContinuation = 0;
413         nonInStatementBrace = 0;
414         objCColonAlignSubsequent = 0;
415 }
416
417 /*
418  * initialize the vectors
419  */
420 void ASBeautifier::initVectors()
421 {
422         if (fileType == beautifierFileType)    // don't build unless necessary
423                 return;
424
425         beautifierFileType = fileType;
426
427         headers->clear();
428         nonParenHeaders->clear();
429         assignmentOperators->clear();
430         nonAssignmentOperators->clear();
431         preBlockStatements->clear();
432         preCommandHeaders->clear();
433         indentableHeaders->clear();
434
435         ASResource::buildHeaders(headers, fileType, true);
436         ASResource::buildNonParenHeaders(nonParenHeaders, fileType, true);
437         ASResource::buildAssignmentOperators(assignmentOperators);
438         ASResource::buildNonAssignmentOperators(nonAssignmentOperators);
439         ASResource::buildPreBlockStatements(preBlockStatements, fileType);
440         ASResource::buildPreCommandHeaders(preCommandHeaders, fileType);
441         ASResource::buildIndentableHeaders(indentableHeaders);
442 }
443
444 /**
445  * set indentation style to C/C++.
446  */
447 void ASBeautifier::setCStyle()
448 {
449         fileType = C_TYPE;
450 }
451
452 /**
453  * set indentation style to Java.
454  */
455 void ASBeautifier::setJavaStyle()
456 {
457         fileType = JAVA_TYPE;
458 }
459
460 /**
461  * set indentation style to C#.
462  */
463 void ASBeautifier::setSharpStyle()
464 {
465         fileType = SHARP_TYPE;
466 }
467
468 /**
469  * set mode manually set flag
470  */
471 void ASBeautifier::setModeManuallySet(bool state)
472 {
473         isModeManuallySet = state;
474 }
475
476 /**
477  * set tabLength equal to indentLength.
478  * This is done when tabLength is not explicitly set by
479  * "indent=force-tab-x"
480  *
481  */
482 void ASBeautifier::setDefaultTabLength()
483 {
484         tabLength = indentLength;
485 }
486
487 /**
488  * indent using a different tab setting for indent=force-tab
489  *
490  * @param   length     number of spaces per tab.
491  */
492 void ASBeautifier::setForceTabXIndentation(int length)
493 {
494         // set tabLength instead of indentLength
495         indentString = "\t";
496         tabLength = length;
497         shouldForceTabIndentation = true;
498 }
499
500 /**
501  * indent using one tab per indentation
502  */
503 void ASBeautifier::setTabIndentation(int length, bool forceTabs)
504 {
505         indentString = "\t";
506         indentLength = length;
507         shouldForceTabIndentation = forceTabs;
508 }
509
510 /**
511  * indent using a number of spaces per indentation.
512  *
513  * @param   length     number of spaces per indent.
514  */
515 void ASBeautifier::setSpaceIndentation(int length)
516 {
517         indentString = string(length, ' ');
518         indentLength = length;
519 }
520
521 /**
522 * indent continuation lines using a number of indents.
523 *
524 * @param   indent     number of indents per line.
525 */
526 void ASBeautifier::setContinuationIndentation(int indent)
527 {
528         continuationIndent = indent;
529 }
530
531 /**
532  * set the maximum indentation between two lines in a multi-line statement.
533  *
534  * @param   max     maximum indentation length.
535  */
536 void ASBeautifier::setMaxContinuationIndentLength(int max)
537 {
538         maxContinuationIndent = max;
539 }
540
541 // retained for compatability with release 2.06
542 // "MaxInStatementIndent" has been changed to "MaxContinuationIndent" in 3.0
543 // it is referenced only by the old "MaxInStatementIndent" options
544 void ASBeautifier::setMaxInStatementIndentLength(int max)
545 {
546         setMaxContinuationIndentLength(max);
547 }
548
549 /**
550  * set the minimum conditional indentation option.
551  *
552  * @param   min     minimal indentation option.
553  */
554 void ASBeautifier::setMinConditionalIndentOption(int min)
555 {
556         minConditionalOption = min;
557 }
558
559 /**
560  * set minConditionalIndent from the minConditionalOption.
561  */
562 void ASBeautifier::setMinConditionalIndentLength()
563 {
564         if (minConditionalOption == MINCOND_ZERO)
565                 minConditionalIndent = 0;
566         else if (minConditionalOption == MINCOND_ONE)
567                 minConditionalIndent = indentLength;
568         else if (minConditionalOption == MINCOND_ONEHALF)
569                 minConditionalIndent = indentLength / 2;
570         // minConditionalOption = INDENT_TWO
571         else
572                 minConditionalIndent = indentLength * 2;
573 }
574
575 /**
576  * set the state of the brace indent option. If true, braces will
577  * be indented one additional indent.
578  *
579  * @param   state             state of option.
580  */
581 void ASBeautifier::setBraceIndent(bool state)
582 {
583         braceIndent = state;
584 }
585
586 /**
587 * set the state of the brace indent VTK option. If true, braces will
588 * be indented one additional indent, except for the opening brace.
589 *
590 * @param   state             state of option.
591 */
592 void ASBeautifier::setBraceIndentVtk(bool state)
593 {
594         // need to set both of these
595         setBraceIndent(state);
596         braceIndentVtk = state;
597 }
598
599 /**
600  * set the state of the block indentation option. If true, entire blocks
601  * will be indented one additional indent, similar to the GNU indent style.
602  *
603  * @param   state             state of option.
604  */
605 void ASBeautifier::setBlockIndent(bool state)
606 {
607         blockIndent = state;
608 }
609
610 /**
611  * set the state of the class indentation option. If true, C++ class
612  * definitions will be indented one additional indent.
613  *
614  * @param   state             state of option.
615  */
616 void ASBeautifier::setClassIndent(bool state)
617 {
618         classIndent = state;
619 }
620
621 /**
622  * set the state of the modifier indentation option. If true, C++ class
623  * access modifiers will be indented one-half an indent.
624  *
625  * @param   state             state of option.
626  */
627 void ASBeautifier::setModifierIndent(bool state)
628 {
629         modifierIndent = state;
630 }
631
632 /**
633  * set the state of the switch indentation option. If true, blocks of 'switch'
634  * statements will be indented one additional indent.
635  *
636  * @param   state             state of option.
637  */
638 void ASBeautifier::setSwitchIndent(bool state)
639 {
640         switchIndent = state;
641 }
642
643 /**
644  * set the state of the case indentation option. If true, lines of 'case'
645  * statements will be indented one additional indent.
646  *
647  * @param   state             state of option.
648  */
649 void ASBeautifier::setCaseIndent(bool state)
650 {
651         caseIndent = state;
652 }
653
654 /**
655  * set the state of the namespace indentation option.
656  * If true, blocks of 'namespace' statements will be indented one
657  * additional indent. Otherwise, NO indentation will be added.
658  *
659  * @param   state             state of option.
660  */
661 void ASBeautifier::setNamespaceIndent(bool state)
662 {
663         namespaceIndent = state;
664 }
665
666 /**
667 * set the state of the indent after parens option.
668 *
669 * @param   state             state of option.
670 */
671 void ASBeautifier::setAfterParenIndent(bool state)
672 {
673         shouldIndentAfterParen = state;
674 }
675
676 /**
677  * set the state of the label indentation option.
678  * If true, labels will be indented one indent LESS than the
679  * current indentation level.
680  * If false, labels will be flushed to the left with NO
681  * indent at all.
682  *
683  * @param   state             state of option.
684  */
685 void ASBeautifier::setLabelIndent(bool state)
686 {
687         labelIndent = state;
688 }
689
690 /**
691  * set the state of the preprocessor indentation option.
692  * If true, multi-line #define statements will be indented.
693  *
694  * @param   state             state of option.
695  */
696 void ASBeautifier::setPreprocDefineIndent(bool state)
697 {
698         shouldIndentPreprocDefine = state;
699 }
700
701 void ASBeautifier::setPreprocConditionalIndent(bool state)
702 {
703         shouldIndentPreprocConditional = state;
704 }
705
706 /**
707  * set the state of the empty line fill option.
708  * If true, empty lines will be filled with the whitespace.
709  * of their previous lines.
710  * If false, these lines will remain empty.
711  *
712  * @param   state             state of option.
713  */
714 void ASBeautifier::setEmptyLineFill(bool state)
715 {
716         emptyLineFill = state;
717 }
718
719 void ASBeautifier::setAlignMethodColon(bool state)
720 {
721         shouldAlignMethodColon = state;
722 }
723
724 /**
725  * get the file type.
726  */
727 int ASBeautifier::getFileType() const
728 {
729         return fileType;
730 }
731
732 /**
733  * get the number of spaces per indent
734  *
735  * @return   value of indentLength option.
736  */
737 int ASBeautifier::getIndentLength() const
738 {
739         return indentLength;
740 }
741
742 /**
743  * get the char used for indentation, space or tab
744  *
745  * @return   the char used for indentation.
746  */
747 string ASBeautifier::getIndentString() const
748 {
749         return indentString;
750 }
751
752 /**
753  * get mode manually set flag
754  */
755 bool ASBeautifier::getModeManuallySet() const
756 {
757         return isModeManuallySet;
758 }
759
760 /**
761  * get the state of the force tab indentation option.
762  *
763  * @return   state of force tab indentation.
764  */
765 bool ASBeautifier::getForceTabIndentation() const
766 {
767         return shouldForceTabIndentation;
768 }
769
770 /**
771 * Get the state of the Objective-C align method colon option.
772 *
773 * @return   state of shouldAlignMethodColon option.
774 */
775 bool ASBeautifier::getAlignMethodColon() const
776 {
777         return shouldAlignMethodColon;
778 }
779
780 /**
781  * get the state of the block indentation option.
782  *
783  * @return   state of blockIndent option.
784  */
785 bool ASBeautifier::getBlockIndent() const
786 {
787         return blockIndent;
788 }
789
790 /**
791  * get the state of the brace indentation option.
792  *
793  * @return   state of braceIndent option.
794  */
795 bool ASBeautifier::getBraceIndent() const
796 {
797         return braceIndent;
798 }
799
800 /**
801 * Get the state of the namespace indentation option. If true, blocks
802 * of the 'namespace' statement will be indented one additional indent.
803 *
804 * @return   state of namespaceIndent option.
805 */
806 bool ASBeautifier::getNamespaceIndent() const
807 {
808         return namespaceIndent;
809 }
810
811 /**
812  * Get the state of the class indentation option. If true, blocks of
813  * the 'class' statement will be indented one additional indent.
814  *
815  * @return   state of classIndent option.
816  */
817 bool ASBeautifier::getClassIndent() const
818 {
819         return classIndent;
820 }
821
822 /**
823  * Get the state of the class access modifier indentation option.
824  * If true, the class access modifiers will be indented one-half indent.
825  *
826  * @return   state of modifierIndent option.
827  */
828 bool ASBeautifier::getModifierIndent() const
829 {
830         return modifierIndent;
831 }
832
833 /**
834  * get the state of the switch indentation option. If true, blocks of
835  * the 'switch' statement will be indented one additional indent.
836  *
837  * @return   state of switchIndent option.
838  */
839 bool ASBeautifier::getSwitchIndent() const
840 {
841         return switchIndent;
842 }
843
844 /**
845  * get the state of the case indentation option. If true, lines of 'case'
846  * statements will be indented one additional indent.
847  *
848  * @return   state of caseIndent option.
849  */
850 bool ASBeautifier::getCaseIndent() const
851 {
852         return caseIndent;
853 }
854
855 /**
856  * get the state of the empty line fill option.
857  * If true, empty lines will be filled with the whitespace.
858  * of their previous lines.
859  * If false, these lines will remain empty.
860  *
861  * @return   state of emptyLineFill option.
862  */
863 bool ASBeautifier::getEmptyLineFill() const
864 {
865         return emptyLineFill;
866 }
867
868 /**
869  * get the state of the preprocessor indentation option.
870  * If true, preprocessor "define" lines will be indented.
871  * If false, preprocessor "define" lines will be unchanged.
872  *
873  * @return   state of shouldIndentPreprocDefine option.
874  */
875 bool ASBeautifier::getPreprocDefineIndent() const
876 {
877         return shouldIndentPreprocDefine;
878 }
879
880 /**
881  * get the length of the tab indentation option.
882  *
883  * @return   length of tab indent option.
884  */
885 int ASBeautifier::getTabLength() const
886 {
887         return tabLength;
888 }
889
890 /**
891  * beautify a line of source code.
892  * every line of source code in a source code file should be sent
893  * one after the other to the beautify method.
894  *
895  * @return      the indented line.
896  * @param originalLine       the original unindented line.
897  */
898 string ASBeautifier::beautify(const string& originalLine)
899 {
900         string line;
901         bool isInQuoteContinuation = isInVerbatimQuote || haveLineContinuationChar;
902
903         currentHeader = nullptr;
904         lastLineHeader = nullptr;
905         blockCommentNoBeautify = blockCommentNoIndent;
906         isInClass = false;
907         isInSwitch = false;
908         lineBeginsWithOpenBrace = false;
909         lineBeginsWithCloseBrace = false;
910         lineBeginsWithComma = false;
911         lineIsCommentOnly = false;
912         lineIsLineCommentOnly = false;
913         shouldIndentBracedLine = true;
914         isInAsmOneLine = false;
915         lineOpensWithLineComment = false;
916         lineOpensWithComment = false;
917         lineStartsInComment = isInComment;
918         previousLineProbationTab = false;
919         lineOpeningBlocksNum = 0;
920         lineClosingBlocksNum = 0;
921         if (isImmediatelyPostObjCMethodDefinition)
922                 clearObjCMethodDefinitionAlignment();
923         if (isImmediatelyPostObjCMethodCall)
924         {
925                 isImmediatelyPostObjCMethodCall = false;
926                 isInObjCMethodCall = false;
927                 objCColonAlignSubsequent = 0;
928         }
929
930         // handle and remove white spaces around the line:
931         // If not in comment, first find out size of white space before line,
932         // so that possible comments starting in the line continue in
933         // relation to the preliminary white-space.
934         if (isInQuoteContinuation)
935         {
936                 // trim a single space added by ASFormatter, otherwise leave it alone
937                 if (!(originalLine.length() == 1 && originalLine[0] == ' '))
938                         line = originalLine;
939         }
940         else if (isInComment || isInBeautifySQL)
941         {
942                 // trim the end of comment and SQL lines
943                 line = originalLine;
944                 size_t trimEnd = line.find_last_not_of(" \t");
945                 if (trimEnd == string::npos)
946                         trimEnd = 0;
947                 else
948                         trimEnd++;
949                 if (trimEnd < line.length())
950                         line.erase(trimEnd);
951                 // does a brace open the line
952                 size_t firstChar = line.find_first_not_of(" \t");
953                 if (firstChar != string::npos)
954                 {
955                         if (line[firstChar] == '{')
956                                 lineBeginsWithOpenBrace = true;
957                         else if (line[firstChar] == '}')
958                                 lineBeginsWithCloseBrace = true;
959                         else if (line[firstChar] == ',')
960                                 lineBeginsWithComma = true;
961                 }
962         }
963         else
964         {
965                 line = trim(originalLine);
966                 if (line.length() > 0)
967                 {
968                         if (line[0] == '{')
969                                 lineBeginsWithOpenBrace = true;
970                         else if (line[0] == '}')
971                                 lineBeginsWithCloseBrace = true;
972                         else if (line[0] == ',')
973                                 lineBeginsWithComma = true;
974                         else if (line.compare(0, 2, "//") == 0)
975                                 lineIsLineCommentOnly = true;
976                         else if (line.compare(0, 2, "/*") == 0)
977                         {
978                                 if (line.find("*/", 2) != string::npos)
979                                         lineIsCommentOnly = true;
980                         }
981                 }
982
983                 isInRunInComment = false;
984                 size_t j = line.find_first_not_of(" \t{");
985                 if (j != string::npos && line.compare(j, 2, "//") == 0)
986                         lineOpensWithLineComment = true;
987                 if (j != string::npos && line.compare(j, 2, "/*") == 0)
988                 {
989                         lineOpensWithComment = true;
990                         size_t k = line.find_first_not_of(" \t");
991                         if (k != string::npos && line.compare(k, 1, "{") == 0)
992                                 isInRunInComment = true;
993                 }
994         }
995
996         // When indent is OFF the lines must still be processed by ASBeautifier.
997         // Otherwise the lines immediately following may not be indented correctly.
998         if ((lineIsLineCommentOnly || lineIsCommentOnly)
999                 && line.find("*INDENT-OFF*", 0) != string::npos)
1000                 isIndentModeOff = true;
1001
1002         if (line.length() == 0)
1003         {
1004                 if (backslashEndsPrevLine)
1005                 {
1006                         backslashEndsPrevLine = false;
1007                         // check if this line ends a multi-line #define
1008                         // if so, remove the #define's cloned beautifier from the active
1009                         // beautifier stack and delete it.
1010                         if (isInDefineDefinition && !isInDefine)
1011                         {
1012                                 isInDefineDefinition = false;
1013                                 ASBeautifier* defineBeautifier = activeBeautifierStack->back();
1014                                 activeBeautifierStack->pop_back();
1015                                 delete defineBeautifier;
1016                         }
1017                 }
1018                 if (emptyLineFill && !isInQuoteContinuation)
1019                 {
1020                         if (isInIndentablePreprocBlock)
1021                                 return preLineWS(preprocBlockIndent, 0);
1022                         if (!headerStack->empty() || isInEnum)
1023                                 return preLineWS(prevFinalLineIndentCount, prevFinalLineSpaceIndentCount);
1024                         // must fall thru here
1025                 }
1026                 else
1027                         return line;
1028         }
1029
1030         // handle preprocessor commands
1031         if (isInIndentablePreprocBlock
1032                 && line.length() > 0
1033                 && line[0] != '#')
1034         {
1035                 string indentedLine;
1036                 if (isInClassHeaderTab || isInClassInitializer)
1037                 {
1038                         // parsing is turned off in ASFormatter by indent-off
1039                         // the originalLine will probably never be returned here
1040                         indentedLine = preLineWS(prevFinalLineIndentCount, prevFinalLineSpaceIndentCount) + line;
1041                         return getIndentedLineReturn(indentedLine, originalLine);
1042                 }
1043                 indentedLine = preLineWS(preprocBlockIndent, 0) + line;
1044                 return getIndentedLineReturn(indentedLine, originalLine);
1045         }
1046
1047         if (!isInComment
1048                 && !isInQuoteContinuation
1049                 && line.length() > 0
1050                 && ((line[0] == '#' && !isIndentedPreprocessor(line, 0))
1051                     || backslashEndsPrevLine))
1052         {
1053                 if (line[0] == '#' && !isInDefine)
1054                 {
1055                         string preproc = extractPreprocessorStatement(line);
1056                         processPreprocessor(preproc, line);
1057                         if (isInIndentablePreprocBlock || isInIndentablePreproc)
1058                         {
1059                                 string indentedLine;
1060                                 if ((preproc.length() >= 2 && preproc.substr(0, 2) == "if")) // #if, #ifdef, #ifndef
1061                                 {
1062                                         indentedLine = preLineWS(preprocBlockIndent, 0) + line;
1063                                         preprocBlockIndent += 1;
1064                                         isInIndentablePreprocBlock = true;
1065                                 }
1066                                 else if (preproc == "else" || preproc == "elif")
1067                                 {
1068                                         indentedLine = preLineWS(preprocBlockIndent - 1, 0) + line;
1069                                 }
1070                                 else if (preproc == "endif")
1071                                 {
1072                                         preprocBlockIndent -= 1;
1073                                         indentedLine = preLineWS(preprocBlockIndent, 0) + line;
1074                                         if (preprocBlockIndent == 0)
1075                                                 isInIndentablePreprocBlock = false;
1076                                 }
1077                                 else
1078                                         indentedLine = preLineWS(preprocBlockIndent, 0) + line;
1079                                 return getIndentedLineReturn(indentedLine, originalLine);
1080                         }
1081                         if (shouldIndentPreprocConditional && preproc.length() > 0)
1082                         {
1083                                 string indentedLine;
1084                                 if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef
1085                                 {
1086                                         pair<int, int> entry;   // indentCount, spaceIndentCount
1087                                         if (!isInDefine && activeBeautifierStack != nullptr && !activeBeautifierStack->empty())
1088                                                 entry = activeBeautifierStack->back()->computePreprocessorIndent();
1089                                         else
1090                                                 entry = computePreprocessorIndent();
1091                                         preprocIndentStack->emplace_back(entry);
1092                                         indentedLine = preLineWS(preprocIndentStack->back().first,
1093                                                                  preprocIndentStack->back().second) + line;
1094                                         return getIndentedLineReturn(indentedLine, originalLine);
1095                                 }
1096                                 if (preproc == "else" || preproc == "elif")
1097                                 {
1098                                         if (!preprocIndentStack->empty())       // if no entry don't indent
1099                                         {
1100                                                 indentedLine = preLineWS(preprocIndentStack->back().first,
1101                                                                          preprocIndentStack->back().second) + line;
1102                                                 return getIndentedLineReturn(indentedLine, originalLine);
1103                                         }
1104                                 }
1105                                 else if (preproc == "endif")
1106                                 {
1107                                         if (!preprocIndentStack->empty())       // if no entry don't indent
1108                                         {
1109                                                 indentedLine = preLineWS(preprocIndentStack->back().first,
1110                                                                          preprocIndentStack->back().second) + line;
1111                                                 preprocIndentStack->pop_back();
1112                                                 return getIndentedLineReturn(indentedLine, originalLine);
1113                                         }
1114                                 }
1115                         }
1116                 }
1117
1118                 // check if the last char is a backslash
1119                 if (line.length() > 0)
1120                         backslashEndsPrevLine = (line[line.length() - 1] == '\\');
1121                 // comments within the definition line can be continued without the backslash
1122                 if (isInPreprocessorUnterminatedComment(line))
1123                         backslashEndsPrevLine = true;
1124
1125                 // check if this line ends a multi-line #define
1126                 // if so, use the #define's cloned beautifier for the line's indentation
1127                 // and then remove it from the active beautifier stack and delete it.
1128                 if (!backslashEndsPrevLine && isInDefineDefinition && !isInDefine)
1129                 {
1130                         isInDefineDefinition = false;
1131                         ASBeautifier* defineBeautifier = activeBeautifierStack->back();
1132                         activeBeautifierStack->pop_back();
1133
1134                         string indentedLine = defineBeautifier->beautify(line);
1135                         delete defineBeautifier;
1136                         return getIndentedLineReturn(indentedLine, originalLine);
1137                 }
1138
1139                 // unless this is a multi-line #define, return this precompiler line as is.
1140                 if (!isInDefine && !isInDefineDefinition)
1141                         return originalLine;
1142         }
1143
1144         // if there exists any worker beautifier in the activeBeautifierStack,
1145         // then use it instead of me to indent the current line.
1146         // variables set by ASFormatter must be updated.
1147         if (!isInDefine && activeBeautifierStack != nullptr && !activeBeautifierStack->empty())
1148         {
1149                 activeBeautifierStack->back()->inLineNumber = inLineNumber;
1150                 activeBeautifierStack->back()->runInIndentContinuation = runInIndentContinuation;
1151                 activeBeautifierStack->back()->nonInStatementBrace = nonInStatementBrace;
1152                 activeBeautifierStack->back()->objCColonAlignSubsequent = objCColonAlignSubsequent;
1153                 activeBeautifierStack->back()->lineCommentNoBeautify = lineCommentNoBeautify;
1154                 activeBeautifierStack->back()->isElseHeaderIndent = isElseHeaderIndent;
1155                 activeBeautifierStack->back()->isCaseHeaderCommentIndent = isCaseHeaderCommentIndent;
1156                 activeBeautifierStack->back()->isNonInStatementArray = isNonInStatementArray;
1157                 activeBeautifierStack->back()->isSharpAccessor = isSharpAccessor;
1158                 activeBeautifierStack->back()->isSharpDelegate = isSharpDelegate;
1159                 activeBeautifierStack->back()->isInExternC = isInExternC;
1160                 activeBeautifierStack->back()->isInBeautifySQL = isInBeautifySQL;
1161                 activeBeautifierStack->back()->isInIndentableStruct = isInIndentableStruct;
1162                 activeBeautifierStack->back()->isInIndentablePreproc = isInIndentablePreproc;
1163                 // must return originalLine not the trimmed line
1164                 return activeBeautifierStack->back()->beautify(originalLine);
1165         }
1166
1167         // Flag an indented header in case this line is a one-line block.
1168         // The header in the header stack will be deleted by a one-line block.
1169         bool isInExtraHeaderIndent = false;
1170         if (!headerStack->empty()
1171                 && lineBeginsWithOpenBrace
1172                 && (headerStack->back() != &AS_OPEN_BRACE
1173                     || probationHeader != nullptr))
1174                 isInExtraHeaderIndent = true;
1175
1176         size_t iPrelim = headerStack->size();
1177
1178         // calculate preliminary indentation based on headerStack and data from past lines
1179         computePreliminaryIndentation();
1180
1181         // parse characters in the current line.
1182         parseCurrentLine(line);
1183
1184         // handle special cases of indentation
1185         adjustParsedLineIndentation(iPrelim, isInExtraHeaderIndent);
1186
1187         if (isInObjCMethodDefinition)
1188                 adjustObjCMethodDefinitionIndentation(line);
1189
1190         if (isInObjCMethodCall)
1191                 adjustObjCMethodCallIndentation(line);
1192
1193         if (isInDefine)
1194         {
1195                 if (line.length() > 0 && line[0] == '#')
1196                 {
1197                         // the 'define' does not have to be attached to the '#'
1198                         string preproc = trim(line.substr(1));
1199                         if (preproc.compare(0, 6, "define") == 0)
1200                         {
1201                                 if (!continuationIndentStack->empty()
1202                                         && continuationIndentStack->back() > 0)
1203                                 {
1204                                         defineIndentCount = indentCount;
1205                                 }
1206                                 else
1207                                 {
1208                                         defineIndentCount = indentCount - 1;
1209                                         --indentCount;
1210                                 }
1211                         }
1212                 }
1213
1214                 indentCount -= defineIndentCount;
1215         }
1216
1217         if (indentCount < 0)
1218                 indentCount = 0;
1219
1220         if (lineCommentNoBeautify || blockCommentNoBeautify || isInQuoteContinuation)
1221                 indentCount = spaceIndentCount = 0;
1222
1223         // finally, insert indentations into beginning of line
1224
1225         string indentedLine = preLineWS(indentCount, spaceIndentCount) + line;
1226         indentedLine = getIndentedLineReturn(indentedLine, originalLine);
1227
1228         prevFinalLineSpaceIndentCount = spaceIndentCount;
1229         prevFinalLineIndentCount = indentCount;
1230
1231         if (lastLineHeader != nullptr)
1232                 previousLastLineHeader = lastLineHeader;
1233
1234         if ((lineIsLineCommentOnly || lineIsCommentOnly)
1235                 && line.find("*INDENT-ON*", 0) != string::npos)
1236                 isIndentModeOff = false;
1237
1238         return indentedLine;
1239 }
1240
1241 const string& ASBeautifier::getIndentedLineReturn(const string& newLine, const string& originalLine) const
1242 {
1243         if (isIndentModeOff)
1244                 return originalLine;
1245         return newLine;
1246 }
1247
1248 string ASBeautifier::preLineWS(int lineIndentCount, int lineSpaceIndentCount) const
1249 {
1250         if (shouldForceTabIndentation)
1251         {
1252                 if (tabLength != indentLength)
1253                 {
1254                         // adjust for different tab length
1255                         int indentCountOrig = lineIndentCount;
1256                         int spaceIndentCountOrig = lineSpaceIndentCount;
1257                         lineIndentCount = ((indentCountOrig * indentLength) + spaceIndentCountOrig) / tabLength;
1258                         lineSpaceIndentCount = ((indentCountOrig * indentLength) + spaceIndentCountOrig) % tabLength;
1259                 }
1260                 else
1261                 {
1262                         lineIndentCount += lineSpaceIndentCount / indentLength;
1263                         lineSpaceIndentCount = lineSpaceIndentCount % indentLength;
1264                 }
1265         }
1266
1267         string ws;
1268         for (int i = 0; i < lineIndentCount; i++)
1269                 ws += indentString;
1270         while ((lineSpaceIndentCount--) > 0)
1271                 ws += string(" ");
1272         return ws;
1273 }
1274
1275 /**
1276  * register a continuation indent.
1277  */
1278 void ASBeautifier::registerContinuationIndent(const string& line, int i, int spaceIndentCount_,
1279                                               int tabIncrementIn, int minIndent, bool updateParenStack)
1280 {
1281         int remainingCharNum = line.length() - i;
1282         int nextNonWSChar = getNextProgramCharDistance(line, i);
1283
1284         // if indent is around the last char in the line OR indent-after-paren is requested,
1285         // indent with the continuation indent
1286         if (nextNonWSChar == remainingCharNum || shouldIndentAfterParen)
1287         {
1288                 int previousIndent = spaceIndentCount_;
1289                 if (!continuationIndentStack->empty())
1290                         previousIndent = continuationIndentStack->back();
1291                 int currIndent = continuationIndent * indentLength + previousIndent;
1292                 if (currIndent > maxContinuationIndent && line[i] != '{')
1293                         currIndent = indentLength * 2 + spaceIndentCount_;
1294                 continuationIndentStack->emplace_back(currIndent);
1295                 if (updateParenStack)
1296                         parenIndentStack->emplace_back(previousIndent);
1297                 return;
1298         }
1299
1300         if (updateParenStack)
1301                 parenIndentStack->emplace_back(i + spaceIndentCount_ - runInIndentContinuation);
1302
1303         int tabIncrement = tabIncrementIn;
1304
1305         // check for following tabs
1306         for (int j = i + 1; j < (i + nextNonWSChar); j++)
1307         {
1308                 if (line[j] == '\t')
1309                         tabIncrement += convertTabToSpaces(j, tabIncrement);
1310         }
1311
1312         int continuationIndentCount = i + nextNonWSChar + spaceIndentCount_ + tabIncrement;
1313
1314         // check for run-in statement
1315         if (i > 0 && line[0] == '{')
1316                 continuationIndentCount -= indentLength;
1317
1318         if (continuationIndentCount < minIndent)
1319                 continuationIndentCount = minIndent + spaceIndentCount_;
1320
1321         // this is not done for an in-statement array
1322         if (continuationIndentCount > maxContinuationIndent
1323                 && !(prevNonLegalCh == '=' && currentNonLegalCh == '{'))
1324                 continuationIndentCount = indentLength * 2 + spaceIndentCount_;
1325
1326         if (!continuationIndentStack->empty()
1327                 && continuationIndentCount < continuationIndentStack->back())
1328                 continuationIndentCount = continuationIndentStack->back();
1329
1330         // the block opener is not indented for a NonInStatementArray
1331         if ((isNonInStatementArray && line[i] == '{')
1332                 && !isInEnum && !braceBlockStateStack->empty() && braceBlockStateStack->back())
1333                 continuationIndentCount = 0;
1334
1335         continuationIndentStack->emplace_back(continuationIndentCount);
1336 }
1337
1338 /**
1339 * Register a continuation indent for a class header or a class initializer colon.
1340 */
1341 void ASBeautifier::registerContinuationIndentColon(const string& line, int i, int tabIncrementIn)
1342 {
1343         assert(line[i] == ':');
1344         assert(isInClassInitializer || isInClassHeaderTab);
1345
1346         // register indent at first word after the colon
1347         size_t firstChar = line.find_first_not_of(" \t");
1348         if (firstChar == (size_t) i)            // firstChar is ':'
1349         {
1350                 size_t firstWord = line.find_first_not_of(" \t", firstChar + 1);
1351                 if (firstChar != string::npos)
1352                 {
1353                         int continuationIndentCount = firstWord + spaceIndentCount + tabIncrementIn;
1354                         continuationIndentStack->emplace_back(continuationIndentCount);
1355                         isContinuation = true;
1356                 }
1357         }
1358 }
1359
1360 /**
1361  * Compute indentation for a preprocessor #if statement.
1362  * This may be called for the activeBeautiferStack
1363  * instead of the active ASBeautifier object.
1364  */
1365 pair<int, int> ASBeautifier::computePreprocessorIndent()
1366 {
1367         computePreliminaryIndentation();
1368         pair<int, int> entry(indentCount, spaceIndentCount);
1369         if (!headerStack->empty()
1370                 && entry.first > 0
1371                 && (headerStack->back() == &AS_IF
1372                     || headerStack->back() == &AS_ELSE
1373                     || headerStack->back() == &AS_FOR
1374                     || headerStack->back() == &AS_WHILE))
1375                 --entry.first;
1376         return entry;
1377 }
1378
1379 /**
1380  * get distance to the next non-white space, non-comment character in the line.
1381  * if no such character exists, return the length remaining to the end of the line.
1382  */
1383 int ASBeautifier::getNextProgramCharDistance(const string& line, int i) const
1384 {
1385         bool inComment = false;
1386         int  remainingCharNum = line.length() - i;
1387         int  charDistance;
1388         char ch;
1389
1390         for (charDistance = 1; charDistance < remainingCharNum; charDistance++)
1391         {
1392                 ch = line[i + charDistance];
1393                 if (inComment)
1394                 {
1395                         if (line.compare(i + charDistance, 2, "*/") == 0)
1396                         {
1397                                 charDistance++;
1398                                 inComment = false;
1399                         }
1400                         continue;
1401                 }
1402                 else if (isWhiteSpace(ch))
1403                         continue;
1404                 else if (ch == '/')
1405                 {
1406                         if (line.compare(i + charDistance, 2, "//") == 0)
1407                                 return remainingCharNum;
1408                         if (line.compare(i + charDistance, 2, "/*") == 0)
1409                         {
1410                                 charDistance++;
1411                                 inComment = true;
1412                         }
1413                 }
1414                 else
1415                         return charDistance;
1416         }
1417
1418         return charDistance;
1419 }
1420
1421 /**
1422  * find the index number of a string element in a container of strings
1423  *
1424  * @return              the index number of element in the container. -1 if element not found.
1425  * @param container     a vector of strings.
1426  * @param element       the element to find .
1427  */
1428 int ASBeautifier::indexOf(const vector<const string*>& container, const string* element) const
1429 {
1430         vector<const string*>::const_iterator where;
1431
1432         where = find(container.begin(), container.end(), element);
1433         if (where == container.end())
1434                 return -1;
1435         return (int) (where - container.begin());
1436 }
1437
1438 /**
1439  * convert tabs to spaces.
1440  * i is the position of the character to convert to spaces.
1441  * tabIncrementIn is the increment that must be added for tab indent characters
1442  *     to get the correct column for the current tab.
1443  */
1444 int ASBeautifier::convertTabToSpaces(int i, int tabIncrementIn) const
1445 {
1446         int tabToSpacesAdjustment = indentLength - 1 - ((tabIncrementIn + i) % indentLength);
1447         return tabToSpacesAdjustment;
1448 }
1449
1450 /**
1451  * trim removes the white space surrounding a line.
1452  *
1453  * @return          the trimmed line.
1454  * @param str       the line to trim.
1455  */
1456 string ASBeautifier::trim(const string& str) const
1457 {
1458         int start = 0;
1459         int end = str.length() - 1;
1460
1461         while (start < end && isWhiteSpace(str[start]))
1462                 start++;
1463
1464         while (start <= end && isWhiteSpace(str[end]))
1465                 end--;
1466
1467         // don't trim if it ends in a continuation
1468         if (end > -1 && str[end] == '\\')
1469                 end = str.length() - 1;
1470
1471         string returnStr(str, start, end + 1 - start);
1472         return returnStr;
1473 }
1474
1475 /**
1476  * rtrim removes the white space from the end of a line.
1477  *
1478  * @return          the trimmed line.
1479  * @param str       the line to trim.
1480  */
1481 string ASBeautifier::rtrim(const string& str) const
1482 {
1483         size_t len = str.length();
1484         size_t end = str.find_last_not_of(" \t");
1485         if (end == string::npos
1486                 || end == len - 1)
1487                 return str;
1488         string returnStr(str, 0, end + 1);
1489         return returnStr;
1490 }
1491
1492 /**
1493  * Copy tempStacks for the copy constructor.
1494  * The value of the vectors must also be copied.
1495  */
1496 vector<vector<const string*>*>* ASBeautifier::copyTempStacks(const ASBeautifier& other) const
1497 {
1498         vector<vector<const string*>*>* tempStacksNew = new vector<vector<const string*>*>;
1499         vector<vector<const string*>*>::iterator iter;
1500         for (iter = other.tempStacks->begin();
1501                 iter != other.tempStacks->end();
1502                 ++iter)
1503         {
1504                 vector<const string*>* newVec = new vector<const string*>;
1505                 *newVec = **iter;
1506                 tempStacksNew->emplace_back(newVec);
1507         }
1508         return tempStacksNew;
1509 }
1510
1511 /**
1512  * delete a member vectors to eliminate memory leak reporting
1513  */
1514 void ASBeautifier::deleteBeautifierVectors()
1515 {
1516         beautifierFileType = 9;         // reset to an invalid type
1517         delete headers;
1518         delete nonParenHeaders;
1519         delete preBlockStatements;
1520         delete preCommandHeaders;
1521         delete assignmentOperators;
1522         delete nonAssignmentOperators;
1523         delete indentableHeaders;
1524 }
1525
1526 /**
1527  * delete a vector object
1528  * T is the type of vector
1529  * used for all vectors except tempStacks
1530  */
1531 template<typename T>
1532 void ASBeautifier::deleteContainer(T& container)
1533 {
1534         if (container != nullptr)
1535         {
1536                 container->clear();
1537                 delete (container);
1538                 container = nullptr;
1539         }
1540 }
1541
1542 /**
1543  * Delete the ASBeautifier vector object.
1544  * This is a vector of pointers to ASBeautifier objects allocated with the 'new' operator.
1545  * Therefore the ASBeautifier objects have to be deleted in addition to the
1546  * ASBeautifier pointer entries.
1547  */
1548 void ASBeautifier::deleteBeautifierContainer(vector<ASBeautifier*>*& container)
1549 {
1550         if (container != nullptr)
1551         {
1552                 vector<ASBeautifier*>::iterator iter = container->begin();
1553                 while (iter < container->end())
1554                 {
1555                         delete *iter;
1556                         ++iter;
1557                 }
1558                 container->clear();
1559                 delete (container);
1560                 container = nullptr;
1561         }
1562 }
1563
1564 /**
1565  * Delete the tempStacks vector object.
1566  * The tempStacks is a vector of pointers to strings allocated with the 'new' operator.
1567  * Therefore the strings have to be deleted in addition to the tempStacks entries.
1568  */
1569 void ASBeautifier::deleteTempStacksContainer(vector<vector<const string*>*>*& container)
1570 {
1571         if (container != nullptr)
1572         {
1573                 vector<vector<const string*>*>::iterator iter = container->begin();
1574                 while (iter < container->end())
1575                 {
1576                         delete *iter;
1577                         ++iter;
1578                 }
1579                 container->clear();
1580                 delete (container);
1581                 container = nullptr;
1582         }
1583 }
1584
1585 /**
1586  * initialize a vector object
1587  * T is the type of vector used for all vectors
1588  */
1589 template<typename T>
1590 void ASBeautifier::initContainer(T& container, T value)
1591 {
1592         // since the ASFormatter object is never deleted,
1593         // the existing vectors must be deleted before creating new ones
1594         if (container != nullptr)
1595                 deleteContainer(container);
1596         container = value;
1597 }
1598
1599 /**
1600  * Initialize the tempStacks vector object.
1601  * The tempStacks is a vector of pointers to strings allocated with the 'new' operator.
1602  * Any residual entries are deleted before the vector is initialized.
1603  */
1604 void ASBeautifier::initTempStacksContainer(vector<vector<const string*>*>*& container,
1605                                            vector<vector<const string*>*>* value)
1606 {
1607         if (container != nullptr)
1608                 deleteTempStacksContainer(container);
1609         container = value;
1610 }
1611
1612 /**
1613  * Determine if an assignment statement ends with a comma
1614  *     that is not in a function argument. It ends with a
1615  *     comma if a comma is the last char on the line.
1616  *
1617  * @return  true if line ends with a comma, otherwise false.
1618  */
1619 bool ASBeautifier::statementEndsWithComma(const string& line, int index) const
1620 {
1621         assert(line[index] == '=');
1622
1623         bool isInComment_ = false;
1624         bool isInQuote_ = false;
1625         int parenCount = 0;
1626         size_t lineLength = line.length();
1627         size_t i = 0;
1628         char quoteChar_ = ' ';
1629
1630         for (i = index + 1; i < lineLength; ++i)
1631         {
1632                 char ch = line[i];
1633
1634                 if (isInComment_)
1635                 {
1636                         if (line.compare(i, 2, "*/") == 0)
1637                         {
1638                                 isInComment_ = false;
1639                                 ++i;
1640                         }
1641                         continue;
1642                 }
1643
1644                 if (ch == '\\')
1645                 {
1646                         ++i;
1647                         continue;
1648                 }
1649
1650                 if (isInQuote_)
1651                 {
1652                         if (ch == quoteChar_)
1653                                 isInQuote_ = false;
1654                         continue;
1655                 }
1656
1657                 if (ch == '"'
1658                         || (ch == '\'' && !isDigitSeparator(line, i)))
1659                 {
1660                         isInQuote_ = true;
1661                         quoteChar_ = ch;
1662                         continue;
1663                 }
1664
1665                 if (line.compare(i, 2, "//") == 0)
1666                         break;
1667
1668                 if (line.compare(i, 2, "/*") == 0)
1669                 {
1670                         if (isLineEndComment(line, i))
1671                                 break;
1672                         else
1673                         {
1674                                 isInComment_ = true;
1675                                 ++i;
1676                                 continue;
1677                         }
1678                 }
1679
1680                 if (ch == '(')
1681                         parenCount++;
1682                 if (ch == ')')
1683                         parenCount--;
1684         }
1685         if (isInComment_
1686                 || isInQuote_
1687                 || parenCount > 0)
1688                 return false;
1689
1690         size_t lastChar = line.find_last_not_of(" \t", i - 1);
1691
1692         if (lastChar == string::npos || line[lastChar] != ',')
1693                 return false;
1694
1695         return true;
1696 }
1697
1698 /**
1699  * check if current comment is a line-end comment
1700  *
1701  * @return     is before a line-end comment.
1702  */
1703 bool ASBeautifier::isLineEndComment(const string& line, int startPos) const
1704 {
1705         assert(line.compare(startPos, 2, "/*") == 0);
1706
1707         // comment must be closed on this line with nothing after it
1708         size_t endNum = line.find("*/", startPos + 2);
1709         if (endNum != string::npos)
1710         {
1711                 size_t nextChar = line.find_first_not_of(" \t", endNum + 2);
1712                 if (nextChar == string::npos)
1713                         return true;
1714         }
1715         return false;
1716 }
1717
1718 /**
1719  * get the previous word index for an assignment operator
1720  *
1721  * @return is the index to the previous word (the in statement indent).
1722  */
1723 int ASBeautifier::getContinuationIndentAssign(const string& line, size_t currPos) const
1724 {
1725         assert(line[currPos] == '=');
1726
1727         if (currPos == 0)
1728                 return 0;
1729
1730         // get the last legal word (may be a number)
1731         size_t end = line.find_last_not_of(" \t", currPos - 1);
1732         if (end == string::npos || !isLegalNameChar(line[end]))
1733                 return 0;
1734
1735         int start;          // start of the previous word
1736         for (start = end; start > -1; start--)
1737         {
1738                 if (!isLegalNameChar(line[start]) || line[start] == '.')
1739                         break;
1740         }
1741         start++;
1742
1743         return start;
1744 }
1745
1746 /**
1747  * get the instatement indent for a comma
1748  *
1749  * @return is the indent to the second word on the line (the in statement indent).
1750  */
1751 int ASBeautifier::getContinuationIndentComma(const string& line, size_t currPos) const
1752 {
1753         assert(line[currPos] == ',');
1754
1755         // get first word on a line
1756         size_t indent = line.find_first_not_of(" \t");
1757         if (indent == string::npos || !isLegalNameChar(line[indent]))
1758                 return 0;
1759
1760         // bypass first word
1761         for (; indent < currPos; indent++)
1762         {
1763                 if (!isLegalNameChar(line[indent]))
1764                         break;
1765         }
1766         indent++;
1767         if (indent >= currPos || indent < 4)
1768                 return 0;
1769
1770         // point to second word or assignment operator
1771         indent = line.find_first_not_of(" \t", indent);
1772         if (indent == string::npos || indent >= currPos)
1773                 return 0;
1774
1775         return indent;
1776 }
1777
1778 /**
1779  * get the next word on a line
1780  * the argument 'currPos' must point to the current position.
1781  *
1782  * @return is the next word or an empty string if none found.
1783  */
1784 string ASBeautifier::getNextWord(const string& line, size_t currPos) const
1785 {
1786         size_t lineLength = line.length();
1787         // get the last legal word (may be a number)
1788         if (currPos == lineLength - 1)
1789                 return string();
1790
1791         size_t start = line.find_first_not_of(" \t", currPos + 1);
1792         if (start == string::npos || !isLegalNameChar(line[start]))
1793                 return string();
1794
1795         size_t end;                     // end of the current word
1796         for (end = start + 1; end <= lineLength; end++)
1797         {
1798                 if (!isLegalNameChar(line[end]) || line[end] == '.')
1799                         break;
1800         }
1801
1802         return line.substr(start, end - start);
1803 }
1804
1805 /**
1806  * Check if a preprocessor directive is always indented.
1807  * C# "region" and "endregion" are always indented.
1808  * C/C++ "pragma omp" is always indented.
1809  *
1810  * @return is true or false.
1811  */
1812 bool ASBeautifier::isIndentedPreprocessor(const string& line, size_t currPos) const
1813 {
1814         assert(line[0] == '#');
1815         string nextWord = getNextWord(line, currPos);
1816         if (nextWord == "region" || nextWord == "endregion")
1817                 return true;
1818         // is it #pragma omp
1819         if (nextWord == "pragma")
1820         {
1821                 // find pragma
1822                 size_t start = line.find("pragma");
1823                 if (start == string::npos || !isLegalNameChar(line[start]))
1824                         return false;
1825                 // bypass pragma
1826                 for (; start < line.length(); start++)
1827                 {
1828                         if (!isLegalNameChar(line[start]))
1829                                 break;
1830                 }
1831                 start++;
1832                 if (start >= line.length())
1833                         return false;
1834                 // point to start of second word
1835                 start = line.find_first_not_of(" \t", start);
1836                 if (start == string::npos)
1837                         return false;
1838                 // point to end of second word
1839                 size_t end;
1840                 for (end = start; end < line.length(); end++)
1841                 {
1842                         if (!isLegalNameChar(line[end]))
1843                                 break;
1844                 }
1845                 // check for "pragma omp"
1846                 string word = line.substr(start, end - start);
1847                 if (word == "omp" || word == "region" || word == "endregion")
1848                         return true;
1849         }
1850         return false;
1851 }
1852
1853 /**
1854  * Check if a preprocessor directive is checking for __cplusplus defined.
1855  *
1856  * @return is true or false.
1857  */
1858 bool ASBeautifier::isPreprocessorConditionalCplusplus(const string& line) const
1859 {
1860         string preproc = trim(line.substr(1));
1861         if (preproc.compare(0, 5, "ifdef") == 0 && getNextWord(preproc, 4) == "__cplusplus")
1862                 return true;
1863         if (preproc.compare(0, 2, "if") == 0)
1864         {
1865                 // check for " #if defined(__cplusplus)"
1866                 size_t charNum = 2;
1867                 charNum = preproc.find_first_not_of(" \t", charNum);
1868                 if (charNum != string::npos && preproc.compare(charNum, 7, "defined") == 0)
1869                 {
1870                         charNum += 7;
1871                         charNum = preproc.find_first_not_of(" \t", charNum);
1872                         if (preproc.compare(charNum, 1, "(") == 0)
1873                         {
1874                                 ++charNum;
1875                                 charNum = preproc.find_first_not_of(" \t", charNum);
1876                                 if (preproc.compare(charNum, 11, "__cplusplus") == 0)
1877                                         return true;
1878                         }
1879                 }
1880         }
1881         return false;
1882 }
1883
1884 /**
1885  * Check if a preprocessor definition contains an unterminated comment.
1886  * Comments within a preprocessor definition can be continued without the backslash.
1887  *
1888  * @return is true or false.
1889  */
1890 bool ASBeautifier::isInPreprocessorUnterminatedComment(const string& line)
1891 {
1892         if (!isInPreprocessorComment)
1893         {
1894                 size_t startPos = line.find("/*");
1895                 if (startPos == string::npos)
1896                         return false;
1897         }
1898         size_t endNum = line.find("*/");
1899         if (endNum != string::npos)
1900         {
1901                 isInPreprocessorComment = false;
1902                 return false;
1903         }
1904         isInPreprocessorComment = true;
1905         return true;
1906 }
1907
1908 void ASBeautifier::popLastContinuationIndent()
1909 {
1910         assert(!continuationIndentStackSizeStack->empty());
1911         int previousIndentStackSize = continuationIndentStackSizeStack->back();
1912         if (continuationIndentStackSizeStack->size() > 1)
1913                 continuationIndentStackSizeStack->pop_back();
1914         while (previousIndentStackSize < (int) continuationIndentStack->size())
1915                 continuationIndentStack->pop_back();
1916 }
1917
1918 // for unit testing
1919 int ASBeautifier::getBeautifierFileType() const
1920 { return beautifierFileType; }
1921
1922 /**
1923  * Process preprocessor statements and update the beautifier stacks.
1924  */
1925 void ASBeautifier::processPreprocessor(const string& preproc, const string& line)
1926 {
1927         // When finding a multi-lined #define statement, the original beautifier
1928         // 1. sets its isInDefineDefinition flag
1929         // 2. clones a new beautifier that will be used for the actual indentation
1930         //    of the #define. This clone is put into the activeBeautifierStack in order
1931         //    to be called for the actual indentation.
1932         // The original beautifier will have isInDefineDefinition = true, isInDefine = false
1933         // The cloned beautifier will have   isInDefineDefinition = true, isInDefine = true
1934         if (shouldIndentPreprocDefine && preproc == "define" && line[line.length() - 1] == '\\')
1935         {
1936                 if (!isInDefineDefinition)
1937                 {
1938                         // this is the original beautifier
1939                         isInDefineDefinition = true;
1940
1941                         // push a new beautifier into the active stack
1942                         // this beautifier will be used for the indentation of this define
1943                         ASBeautifier* defineBeautifier = new ASBeautifier(*this);
1944                         activeBeautifierStack->emplace_back(defineBeautifier);
1945                 }
1946                 else
1947                 {
1948                         // the is the cloned beautifier that is in charge of indenting the #define.
1949                         isInDefine = true;
1950                 }
1951         }
1952         else if (preproc.length() >= 2 && preproc.substr(0, 2) == "if")
1953         {
1954                 if (isPreprocessorConditionalCplusplus(line) && !g_preprocessorCppExternCBrace)
1955                         g_preprocessorCppExternCBrace = 1;
1956                 // push a new beautifier into the stack
1957                 waitingBeautifierStackLengthStack->push_back(waitingBeautifierStack->size());
1958                 activeBeautifierStackLengthStack->push_back(activeBeautifierStack->size());
1959                 if (activeBeautifierStackLengthStack->back() == 0)
1960                         waitingBeautifierStack->emplace_back(new ASBeautifier(*this));
1961                 else
1962                         waitingBeautifierStack->emplace_back(new ASBeautifier(*activeBeautifierStack->back()));
1963         }
1964         else if (preproc == "else")
1965         {
1966                 if ((waitingBeautifierStack != nullptr) && !waitingBeautifierStack->empty())
1967                 {
1968                         // MOVE current waiting beautifier to active stack.
1969                         activeBeautifierStack->emplace_back(waitingBeautifierStack->back());
1970                         waitingBeautifierStack->pop_back();
1971                 }
1972         }
1973         else if (preproc == "elif")
1974         {
1975                 if ((waitingBeautifierStack != nullptr) && !waitingBeautifierStack->empty())
1976                 {
1977                         // append a COPY current waiting beautifier to active stack, WITHOUT deleting the original.
1978                         activeBeautifierStack->emplace_back(new ASBeautifier(*(waitingBeautifierStack->back())));
1979                 }
1980         }
1981         else if (preproc == "endif")
1982         {
1983                 int stackLength = 0;
1984                 ASBeautifier* beautifier = nullptr;
1985
1986                 if (waitingBeautifierStackLengthStack != nullptr && !waitingBeautifierStackLengthStack->empty())
1987                 {
1988                         stackLength = waitingBeautifierStackLengthStack->back();
1989                         waitingBeautifierStackLengthStack->pop_back();
1990                         while ((int) waitingBeautifierStack->size() > stackLength)
1991                         {
1992                                 beautifier = waitingBeautifierStack->back();
1993                                 waitingBeautifierStack->pop_back();
1994                                 delete beautifier;
1995                         }
1996                 }
1997
1998                 if (!activeBeautifierStackLengthStack->empty())
1999                 {
2000                         stackLength = activeBeautifierStackLengthStack->back();
2001                         activeBeautifierStackLengthStack->pop_back();
2002                         while ((int) activeBeautifierStack->size() > stackLength)
2003                         {
2004                                 beautifier = activeBeautifierStack->back();
2005                                 activeBeautifierStack->pop_back();
2006                                 delete beautifier;
2007                         }
2008                 }
2009         }
2010 }
2011
2012 // Compute the preliminary indentation based on data in the headerStack
2013 // and data from previous lines.
2014 // Update the class variable indentCount.
2015 void ASBeautifier::computePreliminaryIndentation()
2016 {
2017         indentCount = 0;
2018         spaceIndentCount = 0;
2019         isInClassHeaderTab = false;
2020
2021         if (isInObjCMethodDefinition && !continuationIndentStack->empty())
2022                 spaceIndentObjCMethodAlignment = continuationIndentStack->back();
2023
2024         if (!continuationIndentStack->empty())
2025                 spaceIndentCount = continuationIndentStack->back();
2026
2027         for (size_t i = 0; i < headerStack->size(); i++)
2028         {
2029                 isInClass = false;
2030
2031                 if (blockIndent)
2032                 {
2033                         // do NOT indent opening block for these headers
2034                         if (!((*headerStack)[i] == &AS_NAMESPACE
2035                                 || (*headerStack)[i] == &AS_MODULE
2036                                 || (*headerStack)[i] == &AS_CLASS
2037                                 || (*headerStack)[i] == &AS_STRUCT
2038                                 || (*headerStack)[i] == &AS_UNION
2039                                 || (*headerStack)[i] == &AS_INTERFACE
2040                                 || (*headerStack)[i] == &AS_THROWS
2041                                 || (*headerStack)[i] == &AS_STATIC))
2042                                 ++indentCount;
2043                 }
2044                 else if (!(i > 0 && (*headerStack)[i - 1] != &AS_OPEN_BRACE
2045                            && (*headerStack)[i] == &AS_OPEN_BRACE))
2046                         ++indentCount;
2047
2048                 if (!isJavaStyle() && !namespaceIndent && i > 0
2049                         && ((*headerStack)[i - 1] == &AS_NAMESPACE
2050                             || (*headerStack)[i - 1] == &AS_MODULE)
2051                         && (*headerStack)[i] == &AS_OPEN_BRACE)
2052                         --indentCount;
2053
2054                 if (isCStyle() && i >= 1
2055                         && (*headerStack)[i - 1] == &AS_CLASS
2056                         && (*headerStack)[i] == &AS_OPEN_BRACE)
2057                 {
2058                         if (classIndent)
2059                                 ++indentCount;
2060                         isInClass = true;
2061                 }
2062
2063                 // is the switchIndent option is on, indent switch statements an additional indent.
2064                 else if (switchIndent && i > 1
2065                          && (*headerStack)[i - 1] == &AS_SWITCH
2066                          && (*headerStack)[i] == &AS_OPEN_BRACE)
2067                 {
2068                         ++indentCount;
2069                         isInSwitch = true;
2070                 }
2071
2072         }       // end of for loop
2073
2074         if (isInClassHeader)
2075         {
2076                 if (!isJavaStyle())
2077                         isInClassHeaderTab = true;
2078                 if (lineOpensWithLineComment || lineStartsInComment || lineOpensWithComment)
2079                 {
2080                         if (!lineBeginsWithOpenBrace)
2081                                 --indentCount;
2082                         if (!continuationIndentStack->empty())
2083                                 spaceIndentCount -= continuationIndentStack->back();
2084                 }
2085                 else if (blockIndent)
2086                 {
2087                         if (!lineBeginsWithOpenBrace)
2088                                 ++indentCount;
2089                 }
2090         }
2091
2092         if (isInClassInitializer || isInEnumTypeID)
2093         {
2094                 indentCount += classInitializerIndents;
2095         }
2096
2097         if (isInEnum && lineBeginsWithComma && !continuationIndentStack->empty())
2098         {
2099                 // unregister '=' indent from the previous line
2100                 continuationIndentStack->pop_back();
2101                 isContinuation = false;
2102                 spaceIndentCount = 0;
2103         }
2104
2105         // Objective-C interface continuation line
2106         if (isInObjCInterface)
2107                 ++indentCount;
2108
2109         // unindent a class closing brace...
2110         if (!lineStartsInComment
2111                 && isCStyle()
2112                 && isInClass
2113                 && classIndent
2114                 && headerStack->size() >= 2
2115                 && (*headerStack)[headerStack->size() - 2] == &AS_CLASS
2116                 && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE
2117                 && lineBeginsWithCloseBrace
2118                 && braceBlockStateStack->back())
2119                 --indentCount;
2120
2121         // unindent an indented switch closing brace...
2122         else if (!lineStartsInComment
2123                  && isInSwitch
2124                  && switchIndent
2125                  && headerStack->size() >= 2
2126                  && (*headerStack)[headerStack->size() - 2] == &AS_SWITCH
2127                  && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE
2128                  && lineBeginsWithCloseBrace)
2129                 --indentCount;
2130
2131         // handle special case of run-in comment in an indented class statement
2132         if (isInClass
2133                 && classIndent
2134                 && isInRunInComment
2135                 && !lineOpensWithComment
2136                 && headerStack->size() > 1
2137                 && (*headerStack)[headerStack->size() - 2] == &AS_CLASS)
2138                 --indentCount;
2139
2140         if (isInConditional)
2141                 --indentCount;
2142         if (g_preprocessorCppExternCBrace >= 4)
2143                 --indentCount;
2144 }
2145
2146 void ASBeautifier::adjustParsedLineIndentation(size_t iPrelim, bool isInExtraHeaderIndent)
2147 {
2148         if (lineStartsInComment)
2149                 return;
2150
2151         // unindent a one-line statement in a header indent
2152         if (!blockIndent
2153                 && lineBeginsWithOpenBrace
2154                 && headerStack->size() < iPrelim
2155                 && isInExtraHeaderIndent
2156                 && (lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
2157                 && shouldIndentBracedLine)
2158                 --indentCount;
2159
2160         /*
2161          * if '{' doesn't follow an immediately previous '{' in the headerStack
2162          * (but rather another header such as "for" or "if", then unindent it
2163          * by one indentation relative to its block.
2164          */
2165         else if (!blockIndent
2166                  && lineBeginsWithOpenBrace
2167                  && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
2168                  && (headerStack->size() > 1 && (*headerStack)[headerStack->size() - 2] != &AS_OPEN_BRACE)
2169                  && shouldIndentBracedLine)
2170                 --indentCount;
2171
2172         // must check one less in headerStack if more than one header on a line (allow-addins)...
2173         else if (headerStack->size() > iPrelim + 1
2174                  && !blockIndent
2175                  && lineBeginsWithOpenBrace
2176                  && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
2177                  && (headerStack->size() > 2 && (*headerStack)[headerStack->size() - 3] != &AS_OPEN_BRACE)
2178                  && shouldIndentBracedLine)
2179                 --indentCount;
2180
2181         // unindent a closing brace...
2182         else if (lineBeginsWithCloseBrace
2183                  && shouldIndentBracedLine)
2184                 --indentCount;
2185
2186         // correctly indent one-line-blocks...
2187         else if (lineOpeningBlocksNum > 0
2188                  && lineOpeningBlocksNum == lineClosingBlocksNum
2189                  && previousLineProbationTab)
2190                 --indentCount;
2191
2192         if (indentCount < 0)
2193                 indentCount = 0;
2194
2195         // take care of extra brace indentation option...
2196         if (!lineStartsInComment
2197                 && braceIndent
2198                 && shouldIndentBracedLine
2199                 && (lineBeginsWithOpenBrace || lineBeginsWithCloseBrace))
2200         {
2201                 if (!braceIndentVtk)
2202                         ++indentCount;
2203                 else
2204                 {
2205                         // determine if a style VTK brace is indented
2206                         bool haveUnindentedBrace = false;
2207                         for (size_t i = 0; i < headerStack->size(); i++)
2208                         {
2209                                 if (((*headerStack)[i] == &AS_NAMESPACE
2210                                         || (*headerStack)[i] == &AS_MODULE
2211                                         || (*headerStack)[i] == &AS_CLASS
2212                                         || (*headerStack)[i] == &AS_STRUCT)
2213                                         && i + 1 < headerStack->size()
2214                                         && (*headerStack)[i + 1] == &AS_OPEN_BRACE)
2215                                         i++;
2216                                 else if (lineBeginsWithOpenBrace)
2217                                 {
2218                                         // don't double count the current brace
2219                                         if (i + 1 < headerStack->size()
2220                                                 && (*headerStack)[i] == &AS_OPEN_BRACE)
2221                                                 haveUnindentedBrace = true;
2222                                 }
2223                                 else if ((*headerStack)[i] == &AS_OPEN_BRACE)
2224                                         haveUnindentedBrace = true;
2225                         }       // end of for loop
2226                         if (haveUnindentedBrace)
2227                                 ++indentCount;
2228                 }
2229         }
2230 }
2231
2232 /**
2233  * Compute indentCount adjustment when in a series of else-if statements
2234  * and shouldBreakElseIfs is requested.
2235  * It increments by one for each 'else' in the tempStack.
2236  */
2237 int ASBeautifier::adjustIndentCountForBreakElseIfComments() const
2238 {
2239         assert(isElseHeaderIndent && !tempStacks->empty());
2240         int indentCountIncrement = 0;
2241         vector<const string*>* lastTempStack = tempStacks->back();
2242         if (lastTempStack != nullptr)
2243         {
2244                 for (size_t i = 0; i < lastTempStack->size(); i++)
2245                 {
2246                         if (*lastTempStack->at(i) == AS_ELSE)
2247                                 indentCountIncrement++;
2248                 }
2249         }
2250         return indentCountIncrement;
2251 }
2252
2253 /**
2254  * Extract a preprocessor statement without the #.
2255  * If a error occurs an empty string is returned.
2256  */
2257 string ASBeautifier::extractPreprocessorStatement(const string& line) const
2258 {
2259         string preproc;
2260         size_t start = line.find_first_not_of("#/ \t");
2261         if (start == string::npos)
2262                 return preproc;
2263         size_t end = line.find_first_of("/ \t", start);
2264         if (end == string::npos)
2265                 end = line.length();
2266         preproc = line.substr(start, end - start);
2267         return preproc;
2268 }
2269
2270 void ASBeautifier::adjustObjCMethodDefinitionIndentation(const string& line_)
2271 {
2272         // register indent for Objective-C continuation line
2273         if (line_.length() > 0
2274                 && (line_[0] == '-' || line_[0] == '+'))
2275         {
2276                 if (shouldAlignMethodColon && objCColonAlignSubsequent != -1)
2277                 {
2278                         string convertedLine = getIndentedSpaceEquivalent(line_);
2279                         colonIndentObjCMethodAlignment = convertedLine.find(':');
2280                         int objCColonAlignSubsequentIndent = objCColonAlignSubsequent + indentLength;
2281                         if (objCColonAlignSubsequentIndent > colonIndentObjCMethodAlignment)
2282                                 colonIndentObjCMethodAlignment = objCColonAlignSubsequentIndent;
2283                 }
2284                 else if (continuationIndentStack->empty()
2285                          || continuationIndentStack->back() == 0)
2286                 {
2287                         continuationIndentStack->emplace_back(indentLength);
2288                         isContinuation = true;
2289                 }
2290         }
2291         // set indent for last definition line
2292         else if (!lineBeginsWithOpenBrace)
2293         {
2294                 if (shouldAlignMethodColon)
2295                         spaceIndentCount = computeObjCColonAlignment(line_, colonIndentObjCMethodAlignment);
2296                 else if (continuationIndentStack->empty())
2297                         spaceIndentCount = spaceIndentObjCMethodAlignment;
2298         }
2299 }
2300
2301 void ASBeautifier::adjustObjCMethodCallIndentation(const string& line_)
2302 {
2303         static int keywordIndentObjCMethodAlignment = 0;
2304         if (shouldAlignMethodColon && objCColonAlignSubsequent != -1)
2305         {
2306                 if (isInObjCMethodCallFirst)
2307                 {
2308                         isInObjCMethodCallFirst = false;
2309                         string convertedLine = getIndentedSpaceEquivalent(line_);
2310                         bracePosObjCMethodAlignment = convertedLine.find('[');
2311                         keywordIndentObjCMethodAlignment =
2312                             getObjCFollowingKeyword(convertedLine, bracePosObjCMethodAlignment);
2313                         colonIndentObjCMethodAlignment = convertedLine.find(':');
2314                         if (colonIndentObjCMethodAlignment >= 0)
2315                         {
2316                                 int objCColonAlignSubsequentIndent = objCColonAlignSubsequent + indentLength;
2317                                 if (objCColonAlignSubsequentIndent > colonIndentObjCMethodAlignment)
2318                                         colonIndentObjCMethodAlignment = objCColonAlignSubsequentIndent;
2319                                 if (lineBeginsWithOpenBrace)
2320                                         colonIndentObjCMethodAlignment -= indentLength;
2321                         }
2322                 }
2323                 else
2324                 {
2325                         if (line_.find(':') != string::npos)
2326                         {
2327                                 if (colonIndentObjCMethodAlignment < 0)
2328                                         spaceIndentCount += computeObjCColonAlignment(line_, objCColonAlignSubsequent);
2329                                 else if (objCColonAlignSubsequent > colonIndentObjCMethodAlignment)
2330                                         spaceIndentCount = computeObjCColonAlignment(line_, objCColonAlignSubsequent);
2331                                 else
2332                                         spaceIndentCount = computeObjCColonAlignment(line_, colonIndentObjCMethodAlignment);
2333                         }
2334                         else
2335                         {
2336                                 if (spaceIndentCount < colonIndentObjCMethodAlignment)
2337                                         spaceIndentCount += keywordIndentObjCMethodAlignment;
2338                         }
2339                 }
2340         }
2341         else    // align keywords instead of colons
2342         {
2343                 if (isInObjCMethodCallFirst)
2344                 {
2345                         isInObjCMethodCallFirst = false;
2346                         string convertedLine = getIndentedSpaceEquivalent(line_);
2347                         bracePosObjCMethodAlignment = convertedLine.find('[');
2348                         keywordIndentObjCMethodAlignment =
2349                             getObjCFollowingKeyword(convertedLine, bracePosObjCMethodAlignment);
2350                 }
2351                 else
2352                 {
2353                         if (spaceIndentCount < keywordIndentObjCMethodAlignment + bracePosObjCMethodAlignment)
2354                                 spaceIndentCount += keywordIndentObjCMethodAlignment;
2355                 }
2356         }
2357 }
2358
2359 /**
2360  * Clear the variables used to align the Objective-C method definitions.
2361  */
2362 void ASBeautifier::clearObjCMethodDefinitionAlignment()
2363 {
2364         assert(isImmediatelyPostObjCMethodDefinition);
2365         spaceIndentCount = 0;
2366         spaceIndentObjCMethodAlignment = 0;
2367         colonIndentObjCMethodAlignment = 0;
2368         isInObjCMethodDefinition = false;
2369         isImmediatelyPostObjCMethodDefinition = false;
2370         if (!continuationIndentStack->empty())
2371                 continuationIndentStack->pop_back();
2372 }
2373
2374 /**
2375  * Compute the spaceIndentCount necessary to align the current line colon
2376  * with the colon position in the argument.
2377  * If it cannot be aligned indentLength is returned and a new colon
2378  * position is calculated.
2379  */
2380 int ASBeautifier::computeObjCColonAlignment(const string& line, int colonAlignPosition) const
2381 {
2382         int colonPosition = line.find(':');
2383         if (colonPosition < 0 || colonPosition > colonAlignPosition)
2384                 return indentLength;
2385         return (colonAlignPosition - colonPosition);
2386 }
2387
2388 /*
2389  * Compute postition of the keyword following the method call object.
2390  */
2391 int ASBeautifier::getObjCFollowingKeyword(const string& line, int bracePos) const
2392 {
2393         assert(line[bracePos] == '[');
2394         size_t firstText = line.find_first_not_of(" \t", bracePos + 1);
2395         if (firstText == string::npos)
2396                 return -(indentCount * indentLength - 1);
2397         size_t searchBeg = firstText;
2398         size_t objectEnd = 0;   // end of object text
2399         if (line[searchBeg] == '[')
2400         {
2401                 objectEnd = line.find(']', searchBeg + 1);
2402                 if (objectEnd == string::npos)
2403                         return 0;
2404         }
2405         else
2406         {
2407                 if (line[searchBeg] == '(')
2408                 {
2409                         searchBeg = line.find(')', searchBeg + 1);
2410                         if (searchBeg == string::npos)
2411                                 return 0;
2412                 }
2413                 // bypass the object name
2414                 objectEnd = line.find_first_of(" \t", searchBeg + 1);
2415                 if (objectEnd == string::npos)
2416                         return 0;
2417                 --objectEnd;
2418         }
2419         size_t keyPos = line.find_first_not_of(" \t", objectEnd + 1);
2420         if (keyPos == string::npos)
2421                 return 0;
2422         return keyPos - firstText;
2423 }
2424
2425 /**
2426  * Get a line using the current space indent with all tabs replaced by spaces.
2427  * The indentCount is NOT included
2428  * Needed to compute an accurate alignment.
2429  */
2430 string ASBeautifier::getIndentedSpaceEquivalent(const string& line_) const
2431 {
2432         string spaceIndent;
2433         spaceIndent.append(spaceIndentCount, ' ');
2434         string convertedLine = spaceIndent + line_;
2435         for (size_t i = spaceIndent.length(); i < convertedLine.length(); i++)
2436         {
2437                 if (convertedLine[i] == '\t')
2438                 {
2439                         size_t numSpaces = indentLength - (i % indentLength);
2440                         convertedLine.replace(i, 1, numSpaces, ' ');
2441                         i += indentLength - 1;
2442                 }
2443         }
2444         return convertedLine;
2445 }
2446
2447 /**
2448  * Parse the current line to update indentCount and spaceIndentCount.
2449  */
2450 void ASBeautifier::parseCurrentLine(const string& line)
2451 {
2452         bool isInLineComment = false;
2453         bool isInOperator = false;
2454         bool isSpecialChar = false;
2455         bool haveCaseIndent = false;
2456         bool haveAssignmentThisLine = false;
2457         bool closingBraceReached = false;
2458         bool previousLineProbation = (probationHeader != nullptr);
2459         char ch = ' ';
2460         int tabIncrementIn = 0;
2461         if (isInQuote
2462                 && !haveLineContinuationChar
2463                 && !isInVerbatimQuote
2464                 && !isInAsm)
2465                 isInQuote = false;                              // missing closing quote
2466         haveLineContinuationChar = false;
2467
2468         for (size_t i = 0; i < line.length(); i++)
2469         {
2470                 ch = line[i];
2471
2472                 if (isInBeautifySQL)
2473                         continue;
2474
2475                 // handle special characters (i.e. backslash+character such as \n, \t, ...)
2476                 if (isInQuote && !isInVerbatimQuote)
2477                 {
2478                         if (isSpecialChar)
2479                         {
2480                                 isSpecialChar = false;
2481                                 continue;
2482                         }
2483                         if (line.compare(i, 2, "\\\\") == 0)
2484                         {
2485                                 i++;
2486                                 continue;
2487                         }
2488                         if (ch == '\\')
2489                         {
2490                                 if (peekNextChar(line, i) == ' ')   // is this '\' at end of line
2491                                         haveLineContinuationChar = true;
2492                                 else
2493                                         isSpecialChar = true;
2494                                 continue;
2495                         }
2496                 }
2497                 else if (isInDefine && ch == '\\')
2498                         continue;
2499
2500                 // bypass whitespace here
2501                 if (isWhiteSpace(ch))
2502                 {
2503                         if (ch == '\t')
2504                                 tabIncrementIn += convertTabToSpaces(i, tabIncrementIn);
2505                         continue;
2506                 }
2507
2508                 // handle quotes (such as 'x' and "Hello Dolly")
2509                 if (!(isInComment || isInLineComment)
2510                         && (ch == '"'
2511                             || (ch == '\'' && !isDigitSeparator(line, i))))
2512                 {
2513                         if (!isInQuote)
2514                         {
2515                                 quoteChar = ch;
2516                                 isInQuote = true;
2517                                 char prevCh = i > 0 ? line[i - 1] : ' ';
2518                                 if (isCStyle() && prevCh == 'R')
2519                                 {
2520                                         int parenPos = line.find('(', i);
2521                                         if (parenPos != -1)
2522                                         {
2523                                                 isInVerbatimQuote = true;
2524                                                 verbatimDelimiter = line.substr(i + 1, parenPos - i - 1);
2525                                         }
2526                                 }
2527                                 else if (isSharpStyle() && prevCh == '@')
2528                                         isInVerbatimQuote = true;
2529                                 // check for "C" following "extern"
2530                                 else if (g_preprocessorCppExternCBrace == 2 && line.compare(i, 3, "\"C\"") == 0)
2531                                         ++g_preprocessorCppExternCBrace;
2532                         }
2533                         else if (isInVerbatimQuote && ch == '"')
2534                         {
2535                                 if (isCStyle())
2536                                 {
2537                                         string delim = ')' + verbatimDelimiter;
2538                                         int delimStart = i - delim.length();
2539                                         if (delimStart > 0 && line.substr(delimStart, delim.length()) == delim)
2540                                         {
2541                                                 isInQuote = false;
2542                                                 isInVerbatimQuote = false;
2543                                         }
2544                                 }
2545                                 else if (isSharpStyle())
2546                                 {
2547                                         if (line.compare(i, 2, "\"\"") == 0)
2548                                                 i++;
2549                                         else
2550                                         {
2551                                                 isInQuote = false;
2552                                                 isInVerbatimQuote = false;
2553                                                 continue;
2554                                         }
2555                                 }
2556                         }
2557                         else if (quoteChar == ch)
2558                         {
2559                                 isInQuote = false;
2560                                 isContinuation = true;
2561                                 continue;
2562                         }
2563                 }
2564                 if (isInQuote)
2565                         continue;
2566
2567                 // handle comments
2568
2569                 if (!(isInComment || isInLineComment) && line.compare(i, 2, "//") == 0)
2570                 {
2571                         // if there is a 'case' statement after these comments unindent by 1
2572                         if (isCaseHeaderCommentIndent)
2573                                 --indentCount;
2574                         // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
2575                         // if there is an 'else' after these comments a tempStacks indent is required
2576                         if (isElseHeaderIndent && lineOpensWithLineComment && !tempStacks->empty())
2577                                 indentCount += adjustIndentCountForBreakElseIfComments();
2578                         isInLineComment = true;
2579                         i++;
2580                         continue;
2581                 }
2582                 else if (!(isInComment || isInLineComment) && line.compare(i, 2, "/*") == 0)
2583                 {
2584                         // if there is a 'case' statement after these comments unindent by 1
2585                         if (isCaseHeaderCommentIndent && lineOpensWithComment)
2586                                 --indentCount;
2587                         // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
2588                         // if there is an 'else' after these comments a tempStacks indent is required
2589                         if (isElseHeaderIndent && lineOpensWithComment && !tempStacks->empty())
2590                                 indentCount += adjustIndentCountForBreakElseIfComments();
2591                         isInComment = true;
2592                         i++;
2593                         if (!lineOpensWithComment)                              // does line start with comment?
2594                                 blockCommentNoIndent = true;        // if no, cannot indent continuation lines
2595                         continue;
2596                 }
2597                 else if ((isInComment || isInLineComment) && line.compare(i, 2, "*/") == 0)
2598                 {
2599                         size_t firstText = line.find_first_not_of(" \t");
2600                         // if there is a 'case' statement after these comments unindent by 1
2601                         // only if the ending comment is the first entry on the line
2602                         if (isCaseHeaderCommentIndent && firstText == i)
2603                                 --indentCount;
2604                         // if this comment close starts the line, must check for else-if indent
2605                         // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
2606                         // if there is an 'else' after these comments a tempStacks indent is required
2607                         if (firstText == i)
2608                         {
2609                                 if (isElseHeaderIndent && !lineOpensWithComment && !tempStacks->empty())
2610                                         indentCount += adjustIndentCountForBreakElseIfComments();
2611                         }
2612                         isInComment = false;
2613                         i++;
2614                         blockCommentNoIndent = false;           // ok to indent next comment
2615                         continue;
2616                 }
2617                 // treat indented preprocessor lines as a line comment
2618                 else if (line[0] == '#' && isIndentedPreprocessor(line, i))
2619                 {
2620                         isInLineComment = true;
2621                 }
2622
2623                 if (isInLineComment)
2624                 {
2625                         // bypass rest of the comment up to the comment end
2626                         while (i + 1 < line.length())
2627                                 i++;
2628
2629                         continue;
2630                 }
2631                 if (isInComment)
2632                 {
2633                         // if there is a 'case' statement after these comments unindent by 1
2634                         if (!lineOpensWithComment && isCaseHeaderCommentIndent)
2635                                 --indentCount;
2636                         // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
2637                         // if there is an 'else' after these comments a tempStacks indent is required
2638                         if (!lineOpensWithComment && isElseHeaderIndent && !tempStacks->empty())
2639                                 indentCount += adjustIndentCountForBreakElseIfComments();
2640                         // bypass rest of the comment up to the comment end
2641                         while (i + 1 < line.length()
2642                                 && line.compare(i + 1, 2, "*/") != 0)
2643                                 i++;
2644
2645                         continue;
2646                 }
2647
2648                 // if we have reached this far then we are NOT in a comment or string of special character...
2649
2650                 if (probationHeader != nullptr)
2651                 {
2652                         if ((probationHeader == &AS_STATIC && ch == '{')
2653                                 || (probationHeader == &AS_SYNCHRONIZED && ch == '('))
2654                         {
2655                                 // insert the probation header as a new header
2656                                 isInHeader = true;
2657                                 headerStack->emplace_back(probationHeader);
2658
2659                                 // handle the specific probation header
2660                                 isInConditional = (probationHeader == &AS_SYNCHRONIZED);
2661
2662                                 isContinuation = false;
2663                                 // if the probation comes from the previous line, then indent by 1 tab count.
2664                                 if (previousLineProbation
2665                                         && ch == '{'
2666                                         && !(blockIndent && probationHeader == &AS_STATIC))
2667                                 {
2668                                         ++indentCount;
2669                                         previousLineProbationTab = true;
2670                                 }
2671                                 previousLineProbation = false;
2672                         }
2673
2674                         // dismiss the probation header
2675                         probationHeader = nullptr;
2676                 }
2677
2678                 prevNonSpaceCh = currentNonSpaceCh;
2679                 currentNonSpaceCh = ch;
2680                 if (!isLegalNameChar(ch) && ch != ',' && ch != ';')
2681                 {
2682                         prevNonLegalCh = currentNonLegalCh;
2683                         currentNonLegalCh = ch;
2684                 }
2685
2686                 if (isInHeader)
2687                 {
2688                         isInHeader = false;
2689                         currentHeader = headerStack->back();
2690                 }
2691                 else
2692                         currentHeader = nullptr;
2693
2694                 if (isCStyle() && isInTemplate
2695                         && (ch == '<' || ch == '>')
2696                         && !(line.length() > i + 1 && line.compare(i, 2, ">=") == 0))
2697                 {
2698                         if (ch == '<')
2699                         {
2700                                 ++templateDepth;
2701                                 continuationIndentStackSizeStack->push_back(continuationIndentStack->size());
2702                                 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
2703                         }
2704                         else if (ch == '>')
2705                         {
2706                                 popLastContinuationIndent();
2707                                 if (--templateDepth <= 0)
2708                                 {
2709                                         ch = ';';
2710                                         isInTemplate = false;
2711                                         templateDepth = 0;
2712                                 }
2713                         }
2714                 }
2715
2716                 // handle parentheses
2717                 if (ch == '(' || ch == '[' || ch == ')' || ch == ']')
2718                 {
2719                         if (ch == '(' || ch == '[')
2720                         {
2721                                 isInOperator = false;
2722                                 // if have a struct header, this is a declaration not a definition
2723                                 if (ch == '('
2724                                         && !headerStack->empty()
2725                                         && headerStack->back() == &AS_STRUCT)
2726                                 {
2727                                         headerStack->pop_back();
2728                                         isInClassHeader = false;
2729                                         if (line.find(AS_STRUCT, 0) > i)        // if not on this line
2730                                                 indentCount -= classInitializerIndents;
2731                                         if (indentCount < 0)
2732                                                 indentCount = 0;
2733                                 }
2734
2735                                 if (parenDepth == 0)
2736                                 {
2737                                         parenStatementStack->push_back(isContinuation);
2738                                         isContinuation = true;
2739                                 }
2740                                 parenDepth++;
2741                                 if (ch == '[')
2742                                 {
2743                                         ++squareBracketCount;
2744                                         if (squareBracketCount == 1 && isCStyle())
2745                                         {
2746                                                 isInObjCMethodCall = true;
2747                                                 isInObjCMethodCallFirst = true;
2748                                         }
2749                                 }
2750
2751                                 continuationIndentStackSizeStack->push_back(continuationIndentStack->size());
2752
2753                                 if (currentHeader != nullptr)
2754                                         registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, minConditionalIndent, true);
2755                                 else
2756                                         registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
2757                         }
2758                         else if (ch == ')' || ch == ']')
2759                         {
2760                                 if (ch == ']')
2761                                         --squareBracketCount;
2762                                 if (squareBracketCount <= 0)
2763                                 {
2764                                         squareBracketCount = 0;
2765                                         if (isInObjCMethodCall)
2766                                                 isImmediatelyPostObjCMethodCall = true;
2767                                 }
2768                                 foundPreCommandHeader = false;
2769                                 parenDepth--;
2770                                 if (parenDepth == 0)
2771                                 {
2772                                         if (!parenStatementStack->empty())      // in case of unmatched closing parens
2773                                         {
2774                                                 isContinuation = parenStatementStack->back();
2775                                                 parenStatementStack->pop_back();
2776                                         }
2777                                         isInAsm = false;
2778                                         isInConditional = false;
2779                                 }
2780
2781                                 if (!continuationIndentStackSizeStack->empty())
2782                                 {
2783                                         popLastContinuationIndent();
2784
2785                                         if (!parenIndentStack->empty())
2786                                         {
2787                                                 int poppedIndent = parenIndentStack->back();
2788                                                 parenIndentStack->pop_back();
2789
2790                                                 if (i == 0)
2791                                                         spaceIndentCount = poppedIndent;
2792                                         }
2793                                 }
2794                         }
2795                         continue;
2796                 }
2797
2798                 if (ch == '{')
2799                 {
2800                         // first, check if '{' is a block-opener or a static-array opener
2801                         bool isBlockOpener = ((prevNonSpaceCh == '{' && braceBlockStateStack->back())
2802                                               || prevNonSpaceCh == '}'
2803                                               || prevNonSpaceCh == ')'
2804                                               || prevNonSpaceCh == ';'
2805                                               || peekNextChar(line, i) == '{'
2806                                               || foundPreCommandHeader
2807                                               || foundPreCommandMacro
2808                                               || isInClassHeader
2809                                               || (isInClassInitializer && !isLegalNameChar(prevNonSpaceCh))
2810                                               || isNonInStatementArray
2811                                               || isInObjCMethodDefinition
2812                                               || isInObjCInterface
2813                                               || isSharpAccessor
2814                                               || isSharpDelegate
2815                                               || isInExternC
2816                                               || isInAsmBlock
2817                                               || getNextWord(line, i) == AS_NEW
2818                                               || (isInDefine
2819                                                   && (prevNonSpaceCh == '('
2820                                                       || isLegalNameChar(prevNonSpaceCh))));
2821
2822                         if (isInObjCMethodDefinition)
2823                         {
2824                                 objCColonAlignSubsequent = 0;
2825                                 isImmediatelyPostObjCMethodDefinition = true;
2826                                 if (lineBeginsWithOpenBrace)            // for run-in braces
2827                                         clearObjCMethodDefinitionAlignment();
2828                         }
2829
2830                         if (!isBlockOpener && !isContinuation && !isInClassInitializer && !isInEnum)
2831                         {
2832                                 if (headerStack->empty())
2833                                         isBlockOpener = true;
2834                                 else if (headerStack->back() == &AS_OPEN_BRACE
2835                                          && headerStack->size() >= 2)
2836                                 {
2837                                         if ((*headerStack)[headerStack->size() - 2] == &AS_NAMESPACE
2838                                                 || (*headerStack)[headerStack->size() - 2] == &AS_MODULE
2839                                                 || (*headerStack)[headerStack->size() - 2] == &AS_CLASS
2840                                                 || (*headerStack)[headerStack->size() - 2] == &AS_INTERFACE
2841                                                 || (*headerStack)[headerStack->size() - 2] == &AS_STRUCT
2842                                                 || (*headerStack)[headerStack->size() - 2] == &AS_UNION)
2843                                                 isBlockOpener = true;
2844                                 }
2845                                 else if (headerStack->back() == &AS_NAMESPACE
2846                                          || headerStack->back() == &AS_MODULE
2847                                          || headerStack->back() == &AS_CLASS
2848                                          || headerStack->back() == &AS_INTERFACE
2849                                          || headerStack->back() == &AS_STRUCT
2850                                          || headerStack->back() == &AS_UNION)
2851                                         isBlockOpener = true;
2852                         }
2853
2854                         if (!isBlockOpener && currentHeader != nullptr)
2855                         {
2856                                 for (size_t n = 0; n < nonParenHeaders->size(); n++)
2857                                         if (currentHeader == (*nonParenHeaders)[n])
2858                                         {
2859                                                 isBlockOpener = true;
2860                                                 break;
2861                                         }
2862                         }
2863
2864                         braceBlockStateStack->push_back(isBlockOpener);
2865
2866                         if (!isBlockOpener)
2867                         {
2868                                 continuationIndentStackSizeStack->push_back(continuationIndentStack->size());
2869                                 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
2870                                 parenDepth++;
2871                                 if (i == 0)
2872                                         shouldIndentBracedLine = false;
2873                                 isInEnumTypeID = false;
2874
2875                                 continue;
2876                         }
2877
2878                         // this brace is a block opener...
2879
2880                         ++lineOpeningBlocksNum;
2881
2882                         if (isInClassInitializer || isInEnumTypeID)
2883                         {
2884                                 // decrease tab count if brace is broken
2885                                 if (lineBeginsWithOpenBrace)
2886                                 {
2887                                         indentCount -= classInitializerIndents;
2888                                         // decrease one more if an empty class
2889                                         if (!headerStack->empty()
2890                                                 && (*headerStack).back() == &AS_CLASS)
2891                                         {
2892                                                 int nextChar = getNextProgramCharDistance(line, i);
2893                                                 if ((int) line.length() > nextChar && line[nextChar] == '}')
2894                                                         --indentCount;
2895                                         }
2896                                 }
2897                         }
2898
2899                         if (isInObjCInterface)
2900                         {
2901                                 isInObjCInterface = false;
2902                                 if (lineBeginsWithOpenBrace)
2903                                         --indentCount;
2904                         }
2905
2906                         if (braceIndent && !namespaceIndent && !headerStack->empty()
2907                                 && ((*headerStack).back() == &AS_NAMESPACE
2908                                     || (*headerStack).back() == &AS_MODULE))
2909                         {
2910                                 shouldIndentBracedLine = false;
2911                                 --indentCount;
2912                         }
2913
2914                         // an indentable struct is treated like a class in the header stack
2915                         if (!headerStack->empty()
2916                                 && (*headerStack).back() == &AS_STRUCT
2917                                 && isInIndentableStruct)
2918                                 (*headerStack).back() = &AS_CLASS;
2919
2920                         squareBracketDepthStack->emplace_back(parenDepth);
2921                         blockStatementStack->push_back(isContinuation);
2922
2923                         if (!continuationIndentStack->empty())
2924                         {
2925                                 // completely purge the inStatementIndentStack
2926                                 while (!continuationIndentStack->empty())
2927                                         popLastContinuationIndent();
2928                                 if (isInClassInitializer || isInClassHeaderTab)
2929                                 {
2930                                         if (lineBeginsWithOpenBrace || lineBeginsWithComma)
2931                                                 spaceIndentCount = 0;
2932                                 }
2933                                 else
2934                                         spaceIndentCount = 0;
2935                         }
2936
2937                         blockTabCount += (isContinuation ? 1 : 0);
2938                         if (g_preprocessorCppExternCBrace == 3)
2939                                 ++g_preprocessorCppExternCBrace;
2940                         parenDepth = 0;
2941                         isInClassHeader = false;
2942                         isInClassHeaderTab = false;
2943                         isInClassInitializer = false;
2944                         isInEnumTypeID = false;
2945                         isContinuation = false;
2946                         isInQuestion = false;
2947                         isInLet = false;
2948                         foundPreCommandHeader = false;
2949                         foundPreCommandMacro = false;
2950                         isInExternC = false;
2951
2952                         tempStacks->emplace_back(new vector<const string*>);
2953                         headerStack->emplace_back(&AS_OPEN_BRACE);
2954                         lastLineHeader = &AS_OPEN_BRACE;
2955
2956                         continue;
2957                 }       // end '{'
2958
2959                 //check if a header has been reached
2960                 bool isPotentialHeader = isCharPotentialHeader(line, i);
2961
2962                 if (isPotentialHeader && squareBracketCount == 0)
2963                 {
2964                         const string* newHeader = findHeader(line, i, headers);
2965
2966                         // Qt headers may be variables in C++
2967                         if (isCStyle()
2968                                 && (newHeader == &AS_FOREVER || newHeader == &AS_FOREACH))
2969                         {
2970                                 if (line.find_first_of("=;", i) != string::npos)
2971                                         newHeader = nullptr;
2972                         }
2973                         else if (newHeader == &AS_USING
2974                                  && ASBeautifier::peekNextChar(line, i + (*newHeader).length() - 1) != '(')
2975                                 newHeader = nullptr;
2976
2977                         if (newHeader != nullptr)
2978                         {
2979                                 // if we reached here, then this is a header...
2980                                 bool isIndentableHeader = true;
2981
2982                                 isInHeader = true;
2983
2984                                 vector<const string*>* lastTempStack = nullptr;;
2985                                 if (!tempStacks->empty())
2986                                         lastTempStack = tempStacks->back();
2987
2988                                 // if a new block is opened, push a new stack into tempStacks to hold the
2989                                 // future list of headers in the new block.
2990
2991                                 // take care of the special case: 'else if (...)'
2992                                 if (newHeader == &AS_IF && lastLineHeader == &AS_ELSE)
2993                                 {
2994                                         headerStack->pop_back();
2995                                 }
2996
2997                                 // take care of 'else'
2998                                 else if (newHeader == &AS_ELSE)
2999                                 {
3000                                         if (lastTempStack != nullptr)
3001                                         {
3002                                                 int indexOfIf = indexOf(*lastTempStack, &AS_IF);
3003                                                 if (indexOfIf != -1)
3004                                                 {
3005                                                         // recreate the header list in headerStack up to the previous 'if'
3006                                                         // from the temporary snapshot stored in lastTempStack.
3007                                                         int restackSize = lastTempStack->size() - indexOfIf - 1;
3008                                                         for (int r = 0; r < restackSize; r++)
3009                                                         {
3010                                                                 headerStack->emplace_back(lastTempStack->back());
3011                                                                 lastTempStack->pop_back();
3012                                                         }
3013                                                         if (!closingBraceReached)
3014                                                                 indentCount += restackSize;
3015                                                 }
3016                                                 /*
3017                                                  * If the above if is not true, i.e. no 'if' before the 'else',
3018                                                  * then nothing beautiful will come out of this...
3019                                                  * I should think about inserting an Exception here to notify the caller of this...
3020                                                  */
3021                                         }
3022                                 }
3023
3024                                 // check if 'while' closes a previous 'do'
3025                                 else if (newHeader == &AS_WHILE)
3026                                 {
3027                                         if (lastTempStack != nullptr)
3028                                         {
3029                                                 int indexOfDo = indexOf(*lastTempStack, &AS_DO);
3030                                                 if (indexOfDo != -1)
3031                                                 {
3032                                                         // recreate the header list in headerStack up to the previous 'do'
3033                                                         // from the temporary snapshot stored in lastTempStack.
3034                                                         int restackSize = lastTempStack->size() - indexOfDo - 1;
3035                                                         for (int r = 0; r < restackSize; r++)
3036                                                         {
3037                                                                 headerStack->emplace_back(lastTempStack->back());
3038                                                                 lastTempStack->pop_back();
3039                                                         }
3040                                                         if (!closingBraceReached)
3041                                                                 indentCount += restackSize;
3042                                                 }
3043                                         }
3044                                 }
3045                                 // check if 'catch' closes a previous 'try' or 'catch'
3046                                 else if (newHeader == &AS_CATCH || newHeader == &AS_FINALLY)
3047                                 {
3048                                         if (lastTempStack != nullptr)
3049                                         {
3050                                                 int indexOfTry = indexOf(*lastTempStack, &AS_TRY);
3051                                                 if (indexOfTry == -1)
3052                                                         indexOfTry = indexOf(*lastTempStack, &AS_CATCH);
3053                                                 if (indexOfTry != -1)
3054                                                 {
3055                                                         // recreate the header list in headerStack up to the previous 'try'
3056                                                         // from the temporary snapshot stored in lastTempStack.
3057                                                         int restackSize = lastTempStack->size() - indexOfTry - 1;
3058                                                         for (int r = 0; r < restackSize; r++)
3059                                                         {
3060                                                                 headerStack->emplace_back(lastTempStack->back());
3061                                                                 lastTempStack->pop_back();
3062                                                         }
3063
3064                                                         if (!closingBraceReached)
3065                                                                 indentCount += restackSize;
3066                                                 }
3067                                         }
3068                                 }
3069                                 else if (newHeader == &AS_CASE)
3070                                 {
3071                                         isInCase = true;
3072                                         if (!haveCaseIndent)
3073                                         {
3074                                                 haveCaseIndent = true;
3075                                                 if (!lineBeginsWithOpenBrace)
3076                                                         --indentCount;
3077                                         }
3078                                 }
3079                                 else if (newHeader == &AS_DEFAULT)
3080                                 {
3081                                         isInCase = true;
3082                                         --indentCount;
3083                                 }
3084                                 else if (newHeader == &AS_STATIC
3085                                          || newHeader == &AS_SYNCHRONIZED)
3086                                 {
3087                                         if (!headerStack->empty()
3088                                                 && (headerStack->back() == &AS_STATIC
3089                                                     || headerStack->back() == &AS_SYNCHRONIZED))
3090                                         {
3091                                                 isIndentableHeader = false;
3092                                         }
3093                                         else
3094                                         {
3095                                                 isIndentableHeader = false;
3096                                                 probationHeader = newHeader;
3097                                         }
3098                                 }
3099                                 else if (newHeader == &AS_TEMPLATE)
3100                                 {
3101                                         isInTemplate = true;
3102                                         isIndentableHeader = false;
3103                                 }
3104
3105                                 if (isIndentableHeader)
3106                                 {
3107                                         headerStack->emplace_back(newHeader);
3108                                         isContinuation = false;
3109                                         if (indexOf(*nonParenHeaders, newHeader) == -1)
3110                                         {
3111                                                 isInConditional = true;
3112                                         }
3113                                         lastLineHeader = newHeader;
3114                                 }
3115                                 else
3116                                         isInHeader = false;
3117
3118                                 i += newHeader->length() - 1;
3119
3120                                 continue;
3121                         }  // newHeader != nullptr
3122
3123                         if (findHeader(line, i, preCommandHeaders) != nullptr)
3124                                 foundPreCommandHeader = true;
3125
3126                         // Objective-C NSException macros are preCommandHeaders
3127                         if (isCStyle() && findKeyword(line, i, AS_NS_DURING))
3128                                 foundPreCommandMacro = true;
3129                         if (isCStyle() && findKeyword(line, i, AS_NS_HANDLER))
3130                                 foundPreCommandMacro = true;
3131
3132                         if (parenDepth == 0 && findKeyword(line, i, AS_ENUM))
3133                                 isInEnum = true;
3134
3135                         if (isSharpStyle() && findKeyword(line, i, AS_LET))
3136                                 isInLet = true;
3137
3138                 }   // isPotentialHeader
3139
3140                 if (ch == '?')
3141                         isInQuestion = true;
3142
3143                 // special handling of colons
3144                 if (ch == ':')
3145                 {
3146                         if (line.length() > i + 1 && line[i + 1] == ':') // look for ::
3147                         {
3148                                 ++i;
3149                                 continue;
3150                         }
3151                         else if (isInQuestion)
3152                         {
3153                                 // do nothing special
3154                         }
3155                         else if (parenDepth > 0)
3156                         {
3157                                 // found a 'for' loop or an objective-C statement
3158                                 // so do nothing special
3159                         }
3160                         else if (isInEnum)
3161                         {
3162                                 // found an enum with a base-type
3163                                 isInEnumTypeID = true;
3164                                 if (i == 0)
3165                                         indentCount += classInitializerIndents;
3166                         }
3167                         else if (isCStyle()
3168                                  && !isInCase
3169                                  && (prevNonSpaceCh == ')' || foundPreCommandHeader))
3170                         {
3171                                 // found a 'class' c'tor initializer
3172                                 isInClassInitializer = true;
3173                                 registerContinuationIndentColon(line, i, tabIncrementIn);
3174                                 if (i == 0)
3175                                         indentCount += classInitializerIndents;
3176                         }
3177                         else if (isInClassHeader || isInObjCInterface)
3178                         {
3179                                 // is in a 'class A : public B' definition
3180                                 isInClassHeaderTab = true;
3181                                 registerContinuationIndentColon(line, i, tabIncrementIn);
3182                         }
3183                         else if (isInAsm || isInAsmOneLine || isInAsmBlock)
3184                         {
3185                                 // do nothing special
3186                         }
3187                         else if (isDigit(peekNextChar(line, i)))
3188                         {
3189                                 // found a bit field - do nothing special
3190                         }
3191                         else if (isCStyle() && isInClass && prevNonSpaceCh != ')')
3192                         {
3193                                 // found a 'private:' or 'public:' inside a class definition
3194                                 --indentCount;
3195                                 if (modifierIndent)
3196                                         spaceIndentCount += (indentLength / 2);
3197                         }
3198                         else if (isCStyle() && !isInClass
3199                                  && headerStack->size() >= 2
3200                                  && (*headerStack)[headerStack->size() - 2] == &AS_CLASS
3201                                  && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE)
3202                         {
3203                                 // found a 'private:' or 'public:' inside a class definition
3204                                 // and on the same line as the class opening brace
3205                                 // do nothing
3206                         }
3207                         else if (isJavaStyle() && lastLineHeader == &AS_FOR)
3208                         {
3209                                 // found a java for-each statement
3210                                 // so do nothing special
3211                         }
3212                         else
3213                         {
3214                                 currentNonSpaceCh = ';'; // so that braces after the ':' will appear as block-openers
3215                                 char peekedChar = peekNextChar(line, i);
3216                                 if (isInCase)
3217                                 {
3218                                         isInCase = false;
3219                                         ch = ';'; // from here on, treat char as ';'
3220                                 }
3221                                 else if (isCStyle() || (isSharpStyle() && peekedChar == ';'))
3222                                 {
3223                                         // is in a label (e.g. 'label1:')
3224                                         if (labelIndent)
3225                                                 --indentCount; // unindent label by one indent
3226                                         else if (!lineBeginsWithOpenBrace)
3227                                                 indentCount = 0; // completely flush indent to left
3228                                 }
3229                         }
3230                 }
3231
3232                 if ((ch == ';' || (parenDepth > 0 && ch == ',')) && !continuationIndentStackSizeStack->empty())
3233                         while ((int) continuationIndentStackSizeStack->back() + (parenDepth > 0 ? 1 : 0)
3234                                 < (int) continuationIndentStack->size())
3235                                 continuationIndentStack->pop_back();
3236
3237                 else if (ch == ',' && isInEnum && isNonInStatementArray && !continuationIndentStack->empty())
3238                         continuationIndentStack->pop_back();
3239
3240                 // handle commas
3241                 // previous "isInStatement" will be from an assignment operator or class initializer
3242                 if (ch == ',' && parenDepth == 0 && !isContinuation && !isNonInStatementArray)
3243                 {
3244                         // is comma at end of line
3245                         size_t nextChar = line.find_first_not_of(" \t", i + 1);
3246                         if (nextChar != string::npos)
3247                         {
3248                                 if (line.compare(nextChar, 2, "//") == 0
3249                                         || line.compare(nextChar, 2, "/*") == 0)
3250                                         nextChar = string::npos;
3251                         }
3252                         // register indent
3253                         if (nextChar == string::npos)
3254                         {
3255                                 // register indent at previous word
3256                                 if (isJavaStyle() && isInClassHeader)
3257                                 {
3258                                         // do nothing for now
3259                                 }
3260                                 // register indent at second word on the line
3261                                 else if (!isInTemplate && !isInClassHeaderTab && !isInClassInitializer)
3262                                 {
3263                                         int prevWord = getContinuationIndentComma(line, i);
3264                                         int continuationIndentCount = prevWord + spaceIndentCount + tabIncrementIn;
3265                                         continuationIndentStack->emplace_back(continuationIndentCount);
3266                                         isContinuation = true;
3267                                 }
3268                         }
3269                 }
3270                 // handle comma first initializers
3271                 if (ch == ',' && parenDepth == 0 && lineBeginsWithComma
3272                         && (isInClassInitializer || isInClassHeaderTab))
3273                         spaceIndentCount = 0;
3274
3275                 // handle ends of statements
3276                 if ((ch == ';' && parenDepth == 0) || ch == '}')
3277                 {
3278                         if (ch == '}')
3279                         {
3280                                 // first check if this '}' closes a previous block, or a static array...
3281                                 if (braceBlockStateStack->size() > 1)
3282                                 {
3283                                         bool braceBlockState = braceBlockStateStack->back();
3284                                         braceBlockStateStack->pop_back();
3285                                         if (!braceBlockState)
3286                                         {
3287                                                 if (!continuationIndentStackSizeStack->empty())
3288                                                 {
3289                                                         // this brace is a static array
3290                                                         popLastContinuationIndent();
3291                                                         parenDepth--;
3292                                                         if (i == 0)
3293                                                                 shouldIndentBracedLine = false;
3294
3295                                                         if (!parenIndentStack->empty())
3296                                                         {
3297                                                                 int poppedIndent = parenIndentStack->back();
3298                                                                 parenIndentStack->pop_back();
3299                                                                 if (i == 0)
3300                                                                         spaceIndentCount = poppedIndent;
3301                                                         }
3302                                                 }
3303                                                 continue;
3304                                         }
3305                                 }
3306
3307                                 // this brace is block closer...
3308
3309                                 ++lineClosingBlocksNum;
3310
3311                                 if (!continuationIndentStackSizeStack->empty())
3312                                         popLastContinuationIndent();
3313
3314                                 if (!squareBracketDepthStack->empty())
3315                                 {
3316                                         parenDepth = squareBracketDepthStack->back();
3317                                         squareBracketDepthStack->pop_back();
3318                                         isContinuation = blockStatementStack->back();
3319                                         blockStatementStack->pop_back();
3320
3321                                         if (isContinuation)
3322                                                 blockTabCount--;
3323                                 }
3324
3325                                 closingBraceReached = true;
3326                                 if (i == 0)
3327                                         spaceIndentCount = 0;
3328                                 isInAsmBlock = false;
3329                                 isInAsm = isInAsmOneLine = isInQuote = false;   // close these just in case
3330
3331                                 int headerPlace = indexOf(*headerStack, &AS_OPEN_BRACE);
3332                                 if (headerPlace != -1)
3333                                 {
3334                                         const string* popped = headerStack->back();
3335                                         while (popped != &AS_OPEN_BRACE)
3336                                         {
3337                                                 headerStack->pop_back();
3338                                                 popped = headerStack->back();
3339                                         }
3340                                         headerStack->pop_back();
3341
3342                                         if (headerStack->empty())
3343                                                 g_preprocessorCppExternCBrace = 0;
3344
3345                                         // do not indent namespace brace unless namespaces are indented
3346                                         if (!namespaceIndent && !headerStack->empty()
3347                                                 && ((*headerStack).back() == &AS_NAMESPACE
3348                                                     || (*headerStack).back() == &AS_MODULE)
3349                                                 && i == 0)              // must be the first brace on the line
3350                                                 shouldIndentBracedLine = false;
3351
3352                                         if (!tempStacks->empty())
3353                                         {
3354                                                 vector<const string*>* temp = tempStacks->back();
3355                                                 tempStacks->pop_back();
3356                                                 delete temp;
3357                                         }
3358                                 }
3359
3360                                 ch = ' '; // needed due to cases such as '}else{', so that headers ('else' in this case) will be identified...
3361                         }       // ch == '}'
3362
3363                         /*
3364                          * Create a temporary snapshot of the current block's header-list in the
3365                          * uppermost inner stack in tempStacks, and clear the headerStack up to
3366                          * the beginning of the block.
3367                          * Thus, the next future statement will think it comes one indent past
3368                          * the block's '{' unless it specifically checks for a companion-header
3369                          * (such as a previous 'if' for an 'else' header) within the tempStacks,
3370                          * and recreates the temporary snapshot by manipulating the tempStacks.
3371                          */
3372                         if (!tempStacks->back()->empty())
3373                                 while (!tempStacks->back()->empty())
3374                                         tempStacks->back()->pop_back();
3375                         while (!headerStack->empty() && headerStack->back() != &AS_OPEN_BRACE)
3376                         {
3377                                 tempStacks->back()->emplace_back(headerStack->back());
3378                                 headerStack->pop_back();
3379                         }
3380
3381                         if (parenDepth == 0 && ch == ';')
3382                                 isContinuation = false;
3383
3384                         if (isInObjCMethodDefinition)
3385                         {
3386                                 objCColonAlignSubsequent = 0;
3387                                 isImmediatelyPostObjCMethodDefinition = true;
3388                         }
3389
3390                         previousLastLineHeader = nullptr;
3391                         isInClassHeader = false;                // for 'friend' class
3392                         isInEnum = false;
3393                         isInEnumTypeID = false;
3394                         isInQuestion = false;
3395                         isInTemplate = false;
3396                         isInObjCInterface = false;
3397                         foundPreCommandHeader = false;
3398                         foundPreCommandMacro = false;
3399                         squareBracketCount = 0;
3400
3401                         continue;
3402                 }
3403
3404                 if (isPotentialHeader)
3405                 {
3406                         // check for preBlockStatements in C/C++ ONLY if not within parentheses
3407                         // (otherwise 'struct XXX' statements would be wrongly interpreted...)
3408                         if (!isInTemplate && !(isCStyle() && parenDepth > 0))
3409                         {
3410                                 const string* newHeader = findHeader(line, i, preBlockStatements);
3411                                 // handle CORBA IDL module
3412                                 if (newHeader == &AS_MODULE)
3413                                 {
3414                                         char nextChar = peekNextChar(line, i + newHeader->length() - 1);
3415                                         if (prevNonSpaceCh == ')' || !isalpha(nextChar))
3416                                                 newHeader = nullptr;
3417                                 }
3418                                 if (newHeader != nullptr
3419                                         && !(isCStyle() && newHeader == &AS_CLASS && isInEnum)) // is not 'enum class'
3420                                 {
3421                                         if (!isSharpStyle())
3422                                                 headerStack->emplace_back(newHeader);
3423                                         // do not need 'where' in the headerStack
3424                                         // do not need second 'class' statement in a row
3425                                         else if (!(newHeader == &AS_WHERE
3426                                                    || ((newHeader == &AS_CLASS || newHeader == &AS_STRUCT)
3427                                                        && !headerStack->empty()
3428                                                        && (headerStack->back() == &AS_CLASS
3429                                                            || headerStack->back() == &AS_STRUCT))))
3430                                                 headerStack->emplace_back(newHeader);
3431
3432                                         if (!headerStack->empty())
3433                                         {
3434                                                 if ((*headerStack).back() == &AS_CLASS
3435                                                         || (*headerStack).back() == &AS_STRUCT
3436                                                         || (*headerStack).back() == &AS_INTERFACE)
3437                                                 {
3438                                                         isInClassHeader = true;
3439                                                 }
3440                                                 else if ((*headerStack).back() == &AS_NAMESPACE
3441                                                          || (*headerStack).back() == &AS_MODULE)
3442                                                 {
3443                                                         // remove continuationIndent from namespace
3444                                                         if (!continuationIndentStack->empty())
3445                                                                 continuationIndentStack->pop_back();
3446                                                         isContinuation = false;
3447                                                 }
3448                                         }
3449
3450                                         i += newHeader->length() - 1;
3451                                         continue;
3452                                 }
3453                         }
3454                         const string* foundIndentableHeader = findHeader(line, i, indentableHeaders);
3455
3456                         if (foundIndentableHeader != nullptr)
3457                         {
3458                                 // must bypass the header before registering the in statement
3459                                 i += foundIndentableHeader->length() - 1;
3460                                 if (!isInOperator && !isInTemplate && !isNonInStatementArray)
3461                                 {
3462                                         registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, false);
3463                                         isContinuation = true;
3464                                 }
3465                                 continue;
3466                         }
3467
3468                         if (isCStyle() && findKeyword(line, i, AS_OPERATOR))
3469                                 isInOperator = true;
3470
3471                         if (g_preprocessorCppExternCBrace == 1 && findKeyword(line, i, AS_EXTERN))
3472                                 ++g_preprocessorCppExternCBrace;
3473
3474                         if (g_preprocessorCppExternCBrace == 3) // extern "C" is not followed by a '{'
3475                                 g_preprocessorCppExternCBrace = 0;
3476
3477                         // "new" operator is a pointer, not a calculation
3478                         if (findKeyword(line, i, AS_NEW))
3479                         {
3480                                 if (isContinuation && !continuationIndentStack->empty() && prevNonSpaceCh == '=')
3481                                         continuationIndentStack->back() = 0;
3482                         }
3483
3484                         if (isCStyle())
3485                         {
3486                                 if (findKeyword(line, i, AS_ASM)
3487                                         || findKeyword(line, i, AS__ASM__))
3488                                 {
3489                                         isInAsm = true;
3490                                 }
3491                                 else if (findKeyword(line, i, AS_MS_ASM)                // microsoft specific
3492                                          || findKeyword(line, i, AS_MS__ASM))
3493                                 {
3494                                         int index = 4;
3495                                         if (peekNextChar(line, i) == '_')               // check for __asm
3496                                                 index = 5;
3497
3498                                         char peekedChar = peekNextChar(line, i + index);
3499                                         if (peekedChar == '{' || peekedChar == ' ')
3500                                                 isInAsmBlock = true;
3501                                         else
3502                                                 isInAsmOneLine = true;
3503                                 }
3504                         }
3505
3506                         // bypass the entire name for all others
3507                         string name = getCurrentWord(line, i);
3508                         i += name.length() - 1;
3509                         continue;
3510                 }
3511
3512                 // Handle Objective-C statements
3513
3514                 if (ch == '@' && !isWhiteSpace(line[i + 1])
3515                         && isCharPotentialHeader(line, i + 1))
3516                 {
3517                         string curWord = getCurrentWord(line, i + 1);
3518                         if (curWord == AS_INTERFACE     && headerStack->empty())
3519                         {
3520                                 isInObjCInterface = true;
3521                                 string name = '@' + curWord;
3522                                 i += name.length() - 1;
3523                                 continue;
3524                         }
3525                         else if (isInObjCInterface)
3526                         {
3527                                 --indentCount;
3528                                 isInObjCInterface = false;
3529                         }
3530
3531                         if (curWord == AS_PUBLIC
3532                                 || curWord == AS_PRIVATE
3533                                 || curWord == AS_PROTECTED)
3534                         {
3535                                 --indentCount;
3536                                 if (modifierIndent)
3537                                         spaceIndentCount += (indentLength / 2);
3538                                 string name = '@' + curWord;
3539                                 i += name.length() - 1;
3540                                 continue;
3541                         }
3542                         else if (curWord == AS_END)
3543                         {
3544                                 popLastContinuationIndent();
3545                                 spaceIndentCount = 0;
3546                                 isInObjCMethodDefinition = false;
3547                                 string name = '@' + curWord;
3548                                 i += name.length() - 1;
3549                                 continue;
3550                         }
3551                 }
3552                 else if ((ch == '-' || ch == '+')
3553                          && peekNextChar(line, i) == '('
3554                          && headerStack->empty()
3555                          && line.find_first_not_of(" \t") == i)
3556                 {
3557                         if (isInObjCInterface)
3558                                 --indentCount;
3559                         isInObjCInterface = false;
3560                         isInObjCMethodDefinition = true;
3561                         continue;
3562                 }
3563
3564                 // Handle operators
3565
3566                 bool isPotentialOperator = isCharPotentialOperator(ch);
3567
3568                 if (isPotentialOperator)
3569                 {
3570                         // Check if an operator has been reached.
3571                         const string* foundAssignmentOp = findOperator(line, i, assignmentOperators);
3572                         const string* foundNonAssignmentOp = findOperator(line, i, nonAssignmentOperators);
3573
3574                         if (foundNonAssignmentOp != nullptr)
3575                         {
3576                                 if (foundNonAssignmentOp == &AS_LAMBDA)
3577                                         foundPreCommandHeader = true;
3578                                 if (isInTemplate && foundNonAssignmentOp == &AS_GR_GR)
3579                                         foundNonAssignmentOp = nullptr;
3580                         }
3581
3582                         // Since findHeader's boundary checking was not used above, it is possible
3583                         // that both an assignment op and a non-assignment op where found,
3584                         // e.g. '>>' and '>>='. If this is the case, treat the LONGER one as the
3585                         // found operator.
3586                         if (foundAssignmentOp != nullptr && foundNonAssignmentOp != nullptr)
3587                         {
3588                                 if (foundAssignmentOp->length() < foundNonAssignmentOp->length())
3589                                         foundAssignmentOp = nullptr;
3590                                 else
3591                                         foundNonAssignmentOp = nullptr;
3592                         }
3593
3594                         if (foundNonAssignmentOp != nullptr)
3595                         {
3596                                 if (foundNonAssignmentOp->length() > 1)
3597                                         i += foundNonAssignmentOp->length() - 1;
3598
3599                                 // For C++ input/output, operator<< and >> should be
3600                                 // aligned, if we are not in a statement already and
3601                                 // also not in the "operator<<(...)" header line
3602                                 if (!isInOperator
3603                                         && continuationIndentStack->empty()
3604                                         && isCStyle()
3605                                         && (foundNonAssignmentOp == &AS_GR_GR
3606                                             || foundNonAssignmentOp == &AS_LS_LS))
3607                                 {
3608                                         // this will be true if the line begins with the operator
3609                                         if (i < 2 && spaceIndentCount == 0)
3610                                                 spaceIndentCount += 2 * indentLength;
3611                                         // align to the beginning column of the operator
3612                                         registerContinuationIndent(line, i - foundNonAssignmentOp->length(), spaceIndentCount, tabIncrementIn, 0, false);
3613                                 }
3614                         }
3615
3616                         else if (foundAssignmentOp != nullptr)
3617                         {
3618                                 foundPreCommandHeader = false;          // clears this for array assignments
3619                                 foundPreCommandMacro = false;
3620
3621                                 if (foundAssignmentOp->length() > 1)
3622                                         i += foundAssignmentOp->length() - 1;
3623
3624                                 if (!isInOperator && !isInTemplate && (!isNonInStatementArray || isInEnum))
3625                                 {
3626                                         // if multiple assignments, align on the previous word
3627                                         if (foundAssignmentOp == &AS_ASSIGN
3628                                                 && prevNonSpaceCh != ']'                // an array
3629                                                 && statementEndsWithComma(line, i))
3630                                         {
3631                                                 if (!haveAssignmentThisLine)            // only one assignment indent per line
3632                                                 {
3633                                                         // register indent at previous word
3634                                                         haveAssignmentThisLine = true;
3635                                                         int prevWordIndex = getContinuationIndentAssign(line, i);
3636                                                         int continuationIndentCount = prevWordIndex + spaceIndentCount + tabIncrementIn;
3637                                                         continuationIndentStack->emplace_back(continuationIndentCount);
3638                                                         isContinuation = true;
3639                                                 }
3640                                         }
3641                                         // don't indent an assignment if 'let'
3642                                         else if (isInLet)
3643                                         {
3644                                                 isInLet = false;
3645                                         }
3646                                         else if (!lineBeginsWithComma)
3647                                         {
3648                                                 if (i == 0 && spaceIndentCount == 0)
3649                                                         spaceIndentCount += indentLength;
3650                                                 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, false);
3651                                                 isContinuation = true;
3652                                         }
3653                                 }
3654                         }
3655                 }
3656         }       // end of for loop * end of for loop * end of for loop * end of for loop * end of for loop *
3657 }
3658
3659 }   // end namespace astyle