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