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